diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 65cd61a..0a039c3 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -17,7 +17,7 @@ jobs: - 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) \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8e0296c..690997a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,8 @@ Thumbs.db builtins dist deployer_version_settings.txt + .deployer_cache +bob*.jar +manifest.private.der +manifest.public.der \ No newline at end of file diff --git a/.luacheckrc b/.luacheckrc deleted file mode 100644 index f9c6bc5..0000000 --- a/.luacheckrc +++ /dev/null @@ -1,56 +0,0 @@ -std = "max" -files['.luacheckrc'].global = false -unused_args = false - -max_code_line_length = 120 -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", - "describe", - "before", - "after", - "it", -} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..44850ee --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,38 @@ +{ + "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" + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 329ab66..760392e 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ [![](media/druid_logo.png)](https://insality.github.io/druid/) -[![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) +[![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) -[![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/actions/workflow/status/insality/druid/ci-workflow.yml?branch=master)](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-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. @@ -17,18 +17,26 @@ Try the [**HTML5 version**](https://insality.github.io/druid/druid/) of the **Dr 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: -**Druid v0.11.0** +**Druid v0.12.0** -> [https://github.com/Insality/druid/archive/refs/tags/0.11.0.zip](https://github.com/Insality/druid/archive/refs/tags/0.11.0.zip) +> [https://github.com/Insality/druid/archive/refs/tags/0.12.0.zip](https://github.com/Insality/druid/archive/refs/tags/0.12.0.zip) Here is a list of [all releases](https://github.com/Insality/druid/releases). -Size: **67.16 KB** -> The size metrics exlcude the extended components, which are including only on demand. +### Library Size + +> **Note:** The library size is calculated based on the build report per platform. The extended components are exlcuded, which are including only on demand. + +| Platform | Library Size | +| ---------------- | ------------- | +| HTML5 | **38.96 KB** | +| Desktop / Mobile | **65.97 KB** | + ### Input Bindings -**Druid** utilizes the `/builtins/input/all.input_binding` input bindings. For custom input bindings, refer to the Input Binding section in the **_[Advanced Setup](docs_md/advanced-setup.md#input-bindings)_**. + +**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). ## Usage @@ -140,7 +148,7 @@ druid.register("data_list", data_list) | **[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) | | | **[Timer](https://insality.github.io/druid/modules/Timer.html)** | Logic over GUI Text. Handle basic timer functions. | ❌ | | | **[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) | | -| **[Layout](https://insality.github.io/druid/modules/Layout.html)** | Logic over GUI Node. Handle node size depends on layout mode and screen aspect ratio. Contains helpers to build more complex UI layout. | [Layout Example](https://insality.github.io/druid/druid/?example=general_layout) | | +| **[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) | | For a complete overview, see: **_[components.md](docs_md/01-components.md)_**. @@ -173,8 +181,6 @@ Each example page provides a direct link to the corresponding example code, maki Or refer directly to the [**example folder**](https://github.com/Insality/druid/tree/develop/example) for code examples demonstrating how to use **Druid**. -If you want to see examples of GUIs created with Druid, please refer to the [game_examples.md](docs_md/game_examples.md) file. - ## Documentation To better understand **Druid**, read the following documentation: @@ -214,4 +220,4 @@ For a complete history of the development of **Druid**, please check the [change 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) +[![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/insality) \ No newline at end of file diff --git a/config.ld b/config.ld index 1a295b1..a487ec9 100644 --- a/config.ld +++ b/config.ld @@ -4,7 +4,6 @@ description='Documentation for Druid Framework' file={"./druid", exclude = { "./druid/styles/", - "./druid/system/middleclass.lua", "./druid/templates/", "./druid/annotations.lua", "./druid/custom/rich_text/module", diff --git a/deployer_build_stats.csv b/deployer_build_stats.csv index 8643758..9960c84 100644 --- a/deployer_build_stats.csv +++ b/deployer_build_stats.csv @@ -17,3 +17,4 @@ date,sha,version,build_size,build_time,platform,mode,is_cache_using,commits_coun 2023-08-05T16:31:19Z,37fff52aa59feb20f761ef4d340d9f677743d54b,0.11.693,2456,43,js-web,release,true,693 2023-08-05T16:41:25Z,d7dd4a86b81d73d345ad7e136de9c2c488bc4d8b,0.11.694,2452,43,js-web,release,true,694 2023-10-20T08:23:33Z,9132dc477b645d674ec21efbfcf85f48ef0ea8a6,0.11.718,2544,47,js-web,release,true,718 +2024-10-15T16:54:05Z,ea80c874f6c0ea175b317d01ac45c567db9179c7,0.11.0,1840,24,js-web,release,true,796 diff --git a/docs/modules/BackHandler.html b/docs/modules/BackHandler.html index 50d2bc5..df93b56 100644 --- a/docs/modules/BackHandler.html +++ b/docs/modules/BackHandler.html @@ -147,9 +147,8 @@ local back_handler = self.druid:new_back_handler(callback, [params]) diff --git a/docs/modules/BaseComponent.html b/docs/modules/BaseComponent.html index 1c81617..4d4d649 100644 --- a/docs/modules/BaseComponent.html +++ b/docs/modules/BaseComponent.html @@ -106,7 +106,7 @@ return AwesomeComponent Context used as first arg in all Druid events - get_druid(self) + get_druid(self, template, nodes) Get Druid instance for inner component creation. @@ -226,7 +226,7 @@ return AwesomeComponent
- get_druid(self) + get_druid(self, template, nodes)
Get Druid instance for inner component creation. @@ -238,6 +238,14 @@ return AwesomeComponent BaseComponent BaseComponent +
  • template + string or nil + The template name +
  • +
  • nodes + table or nil + The nodes table +
  • Returns:

    diff --git a/docs/modules/Button.html b/docs/modules/Button.html index 2a0def6..a451bac 100644 --- a/docs/modules/Button.html +++ b/docs/modules/Button.html @@ -97,7 +97,7 @@ print("Also the button component is passed in callback params") end -local custom_args = "any variable to pass inside callback" +local custom_args = "Any variable to pass inside callback" local button = self.druid:new_button("button_name", on_button_click, custom_args) @@ -153,7 +153,7 @@ local button = self.druid:new_button("button_name", on_button_click, c click_zone - Additional button click area, defined by another GUI Node + Additional button click area, defined by another GUI node hover @@ -360,7 +360,7 @@ local button = self.druid:new_button("button_name", on_button_click, c Button
  • zone - node or nil + node, string or nil Gui node
  • @@ -433,7 +433,7 @@ button:set_enabled(true) Button
  • key - hash + hash or string The action_id of the input key
  • @@ -508,19 +508,16 @@ button:set_enabled(true)

    Fields:

    @@ -289,9 +287,8 @@ diff --git a/docs/modules/CheckboxGroup.html b/docs/modules/CheckboxGroup.html index 8551324..3a3914b 100644 --- a/docs/modules/CheckboxGroup.html +++ b/docs/modules/CheckboxGroup.html @@ -86,7 +86,7 @@ Return checkbox group state - init(self, nodes, callback[, click_nodes=node]) + init(self, nodes, callback, click_nodes) The CheckboxGroup constructor @@ -142,7 +142,7 @@
    - init(self, nodes, callback[, click_nodes=node]) + init(self, nodes, callback, click_nodes)
    The CheckboxGroup constructor @@ -163,9 +163,8 @@ Checkbox callback
  • click_nodes - node[] + node[] or nil Array of trigger nodes, by default equals to nodes - (default node)
  • diff --git a/docs/modules/DataList.html b/docs/modules/DataList.html index 8003f36..68df37a 100644 --- a/docs/modules/DataList.html +++ b/docs/modules/DataList.html @@ -83,6 +83,10 @@

    Functions

    + + + + @@ -100,22 +104,10 @@ - - - - - - - - - - - - @@ -124,6 +116,14 @@ + + + + + + + + @@ -131,6 +131,10 @@ + + + +
    add(self, data, index, shift_policy)Add element to DataList.
    clear(self) Clear the DataList and refresh visualsReturn current data from DataList component
    get_first_index(self)Return first index from data.
    get_index(self, data) Return index for data value
    get_last_index(self)Return last index from data
    get_length(self)Return amount of data
    init(self, scroll, grid, create_function) The DataList constructor
    Druid System on_remove function
    remove(self, index, shift_policy)Remove element from DataList.
    remove_by_data(self, data, shift_policy)Remove element from DataList by data value.
    scroll_to_index(self, index) Instant scroll to element with passed index
    set_data(self, data) Set new data set for DataList component
    set_use_cache(self, is_use_cache)Set refresh function for DataList component

    Fields

    @@ -140,7 +144,7 @@ - + @@ -164,7 +168,7 @@ - +
    last_indexThe current visual last data indexThe current last index of visual elements
    on_element_add
    top_indexThe current visual top data indexThe current top index of visual elements
    @@ -175,6 +179,39 @@

    Functions

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

    Parameters:

    +
      +
    • self + DataList + DataList +
    • +
    • data + table + +
    • +
    • index + number or nil + +
    • +
    • shift_policy + number or nil + The constant from const.SHIFT.* +
    • +
    + + + + + +
    clear(self) @@ -276,27 +313,6 @@ -
    -
    - - get_first_index(self) -
    -
    - Return first index from data. It not always equals to 1 - - -

    Parameters:

    - - - - - -
    @@ -322,48 +338,6 @@ - -
    - - get_last_index(self) -
    -
    - Return last index from data - - -

    Parameters:

    - - - - - - -
    -
    - - get_length(self) -
    -
    - Return amount of data - - -

    Parameters:

    - - - - - -
    @@ -418,6 +392,64 @@ + +
    + + remove(self, index, shift_policy) +
    +
    + Remove element from DataList. Currenly untested + + +

    Parameters:

    + + + + + + +
    +
    + + remove_by_data(self, data, shift_policy) +
    +
    + Remove element from DataList by data value. Currenly untested + + +

    Parameters:

    + + + + + +
    @@ -474,6 +506,37 @@ + +
    + + set_use_cache(self, is_use_cache) +
    +
    + Set refresh function for DataList component + + +

    Parameters:

    + + +

    Returns:

    +
      + + druid.data_list + Current DataList instance +
    + + + +

    Fields

    @@ -504,7 +567,7 @@ last_index
    - The current visual last data index + The current last index of visual elements +

    Returns:

    +
      + + boolean + True if callback was subscribed +
    @@ -274,7 +354,7 @@ event:trigger("Param1", "Param2
    - unsubscribe(self, callback, context) + unsubscribe(self, callback, callback_context)
    Unsubscribe callback on event @@ -290,7 +370,7 @@ event:trigger("Param1", "Param2 function Callback itself -
  • context +
  • callback_context any or nil Additional context as first param to callback call
  • diff --git a/docs/modules/DruidInstance.html b/docs/modules/DruidInstance.html index 2e0ae35..5007e3c 100644 --- a/docs/modules/DruidInstance.html +++ b/docs/modules/DruidInstance.html @@ -142,10 +142,6 @@ end Call this in gui_script final function. - new(self, component, ...) - Create new component. - - new_back_handler(self, callback, params) Create BackHandler component @@ -162,7 +158,7 @@ end Create Checkbox component - new_checkbox_group(self, nodes, callback[, click_nodes=node]) + new_checkbox_group(self, nodes, callback, click_nodes) Create CheckboxGroup component @@ -182,7 +178,7 @@ end Create Hotkey component - new_hover(self, node, on_hover_callback) + new_hover(self, node, on_hover_callback, on_mouse_hover_callback) Create Hover component @@ -202,7 +198,7 @@ end Create Progress component - new_radio_group(self, nodes, callback[, click_nodes=node]) + new_radio_group(self, nodes, callback, click_nodes) Create RadioGroup component @@ -246,11 +242,11 @@ end Remove created component from Druid instance. - set_blacklist(self[, blacklist_components=nil]) + set_blacklist(self, blacklist_components) Set blacklist components for input processing. - set_whitelist(self[, whitelist_components=nil]) + set_whitelist(self, whitelist_components) Set whitelist components for input processing. @@ -286,41 +282,6 @@ end -
    -
    - - new(self, component, ...) -
    -
    - Create new component. - - -

    Parameters:

    - - -

    Returns:

    -
      - - BaseComponent - Component instance -
    - - - -
    @@ -411,11 +372,11 @@ end Button callback
  • params - table or nil + any or nil Button callback params
  • anim_node - node or nil + node, string or nil Button anim node (node, if not provided)
  • @@ -476,7 +437,7 @@ end
    - new_checkbox_group(self, nodes, callback[, click_nodes=node]) + new_checkbox_group(self, nodes, callback, click_nodes)
    Create CheckboxGroup component @@ -489,7 +450,7 @@ end
  • nodes - node[] + (node or string)[] Array of gui node
  • callback @@ -497,9 +458,8 @@ end Checkbox callback
  • click_nodes - node[] + (node, string)[] or nil Array of trigger nodes, by default equals to nodes - (default node)
  • @@ -660,7 +620,7 @@ end
    - new_hover(self, node, on_hover_callback) + new_hover(self, node, on_hover_callback, on_mouse_hover_callback)
    Create Hover component @@ -680,6 +640,10 @@ end function or nil Hover callback +
  • on_mouse_hover_callback + function or nil + Mouse hover callback +
  • Returns:

    @@ -712,7 +676,7 @@ end Button node to enabled input component
  • text_node - string or node + string, node or druid.text Text node what will be changed on user input
  • keyboard_type @@ -847,7 +811,7 @@ end
  • - new_radio_group(self, nodes, callback[, click_nodes=node]) + new_radio_group(self, nodes, callback, click_nodes)
    Create RadioGroup component @@ -860,7 +824,7 @@ end
  • nodes - node[] + (node or string)[] Array of gui node
  • callback @@ -868,9 +832,8 @@ end Radio callback
  • click_nodes - node[] + (node, string)[] or nil Array of trigger nodes, by default equals to nodes - (default node)
  • @@ -1211,7 +1174,7 @@ end Message from on_message
  • sender - hash + url Sender from on_message
  • @@ -1242,6 +1205,12 @@ end +

    Returns:

    +
      + + boolean + True if component was removed +
    @@ -1249,7 +1218,7 @@ end
    - set_blacklist(self[, blacklist_components=nil]) + set_blacklist(self, blacklist_components)
    Set blacklist components for input processing. @@ -1264,9 +1233,8 @@ end DruidInstance
  • blacklist_components - table or BaseComponent + table, BaseComponent or nil The array of component to blacklist - (default nil)
  • @@ -1283,7 +1251,7 @@ end
    - set_whitelist(self[, whitelist_components=nil]) + set_whitelist(self, whitelist_components)
    Set whitelist components for input processing. @@ -1298,9 +1266,8 @@ end
  • whitelist_components - table or BaseComponent + table, BaseComponent or nil The array of component to whitelist - (default nil)
  • diff --git a/docs/modules/DynamicGrid.html b/docs/modules/DynamicGrid.html index 2f6677f..52d8458 100644 --- a/docs/modules/DynamicGrid.html +++ b/docs/modules/DynamicGrid.html @@ -420,7 +420,7 @@
      vector3 - Node position + node position
    diff --git a/docs/modules/Helper.html b/docs/modules/Helper.html index 2ede020..f465d57 100644 --- a/docs/modules/Helper.html +++ b/docs/modules/Helper.html @@ -151,10 +151,18 @@ helper.centrate_nodes(0, node_1, node_2) Check if device is native mobile (Android or iOS) + helper.is_multitouch_supported() + Check if device is mobile and can support multitouch + + helper.is_web() Check if device is HTML5 + helper.is_web_mobile() + Check if device is HTML5 mobile + + helper.lerp(a, b, t) Lerp between two values @@ -658,6 +666,26 @@ helper.centrate_nodes(0, node_1, node_2) +
    +
    + + helper.is_multitouch_supported() +
    +
    + Check if device is mobile and can support multitouch + + + +

    Returns:

    +
      + + boolean + Is multitouch supported +
    + + + +
    @@ -678,6 +706,26 @@ helper.centrate_nodes(0, node_1, node_2) + +
    + + helper.is_web_mobile() +
    +
    + Check if device is HTML5 mobile + + + +

    Returns:

    +
      + + boolean + Is web mobile +
    + + + +
    diff --git a/docs/modules/Hotkey.html b/docs/modules/Hotkey.html index 3cd5a00..68e4015 100644 --- a/docs/modules/Hotkey.html +++ b/docs/modules/Hotkey.html @@ -90,6 +90,10 @@ init(self, keys, callback, callback_argument) The Hotkey constructor + + set_repeat(self, is_enabled_repeated) + If true, the callback will be triggered on action.repeated +

    Tables

    @@ -113,8 +117,12 @@ - - + + + + + +
    Visual node
    on_change_stateOn change state callback(self, state)on_hotkey_pressedOn hotkey released callback(self, argument)
    on_hotkey_releasedOn hotkey released callback(self, argument)
    @@ -192,6 +200,37 @@ + +
    + + set_repeat(self, is_enabled_repeated) +
    +
    + If true, the callback will be triggered on action.repeated + + +

    Parameters:

    + + +

    Returns:

    +
      + + Hotkey + +
    + + + +

    Tables

    @@ -254,9 +293,8 @@ @@ -286,15 +324,35 @@
    - - on_change_state + + on_hotkey_pressed
    - On change state callback(self, state) + On hotkey released callback(self, argument) + + + + + +
    +
    + + on_hotkey_released +
    +
    + On hotkey released callback(self, argument) + + +
    +
    + + get_text_selected_replaced(self, text) +
    +
    + Replace selected text with new text + + +

    Parameters:

    + + +

    Returns:

    +
      + + string + New input text +
    + + + +
    @@ -250,6 +333,39 @@ + +
    + + move_selection(self, delta, is_add_to_selection, is_move_to_end) +
    +
    + Change cursor position by delta + + +

    Parameters:

    + + + + + +
    @@ -267,6 +383,12 @@ +

    Returns:

    +
      + + druid.input + Current input instance +
    @@ -292,6 +414,45 @@ + +
    + + select_cursor(self, cursor_index, start_index, end_index) +
    +
    + Set cursor position in input field + + +

    Parameters:

    + + +

    Returns:

    +
      + + druid.input + Current input instance +
    + + + +
    @@ -422,23 +583,15 @@
    - On input field unselect callback(self, input_text) + On input field unselect callback(self, input_text, input_instance)
    +
    + + text_width +
    +
    + Text width + + + + + + + + +
    +
    + + value +
    +
    + Current input value + + + + + + + +
    diff --git a/docs/modules/LangText.html b/docs/modules/LangText.html index 2099832..0d02aba 100644 --- a/docs/modules/LangText.html +++ b/docs/modules/LangText.html @@ -93,7 +93,7 @@ Format string with new text params on localized text - init(self, node[, locale_id=node_text[, adjust_type=downscale]]) + init(self, node, locale_id, adjust_type) The LangText constructor @@ -185,7 +185,7 @@
    - init(self, node[, locale_id=node_text[, adjust_type=downscale]]) + init(self, node, locale_id, adjust_type)
    The LangText constructor @@ -202,14 +202,12 @@ The node_id or gui.get_node(node_id)
  • locale_id - string + string or nil Default locale id or text from node as default - (default node_text)
  • adjust_type - string + string or nil Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference - (default downscale)
  • diff --git a/docs/modules/Layout.html b/docs/modules/Layout.html index edad2b6..c8f4140 100644 --- a/docs/modules/Layout.html +++ b/docs/modules/Layout.html @@ -32,7 +32,6 @@

    Contents

    @@ -79,45 +78,6 @@

    Example Link

    -

    Functions

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    fit_into_node(self, node)Set node for layout node to fit inside it.
    fit_into_size(self, target_size)Set size for layout node to fit inside it
    fit_into_window(self)Set current size for layout node to fit inside it
    init(self, node, mode, on_size_changed_callback)The Layout constructor
    set_max_gui_upscale(self, max_gui_upscale)Set max gui upscale for FIT adjust mode (or side).
    set_max_size(self, max_size)Set maximum size of layout node
    set_min_size(self, min_size)Set minimal size of layout node
    set_origin_position(self, new_origin_position)Set new origin position of layout node.
    set_origin_size(self, new_origin_size)Set new origin size of layout node.

    Fields

    @@ -128,297 +88,12 @@ - - - -
    node Layout node
    on_size_changedOn window resize callback(self, new_size)


    -

    Functions

    - -
    -
    - - fit_into_node(self, node) -
    -
    - Set node for layout node to fit inside it. Pass nil to reset - - -

    Parameters:

    -
      -
    • self - Layout - Layout -
    • -
    • node - node or nil - -
    • -
    - -

    Returns:

    -
      - - Layout - Layout -
    - - - - -
    -
    - - fit_into_size(self, target_size) -
    -
    - Set size for layout node to fit inside it - - -

    Parameters:

    -
      -
    • self - Layout - Layout -
    • -
    • target_size - vector3 - -
    • -
    - -

    Returns:

    -
      - - Layout - Layout -
    - - - - -
    -
    - - fit_into_window(self) -
    -
    - Set current size for layout node to fit inside it - - -

    Parameters:

    -
      -
    • self - Layout - Layout -
    • -
    - -

    Returns:

    -
      - - Layout - Layout -
    - - - - -
    -
    - - init(self, node, mode, on_size_changed_callback) -
    -
    - The Layout constructor - - -

    Parameters:

    -
      -
    • self - Layout - Layout -
    • -
    • node - node - Gui node -
    • -
    • mode - string - The layout mode (from const.LAYOUT_MODE) -
    • -
    • on_size_changed_callback - function or nil - The callback on window resize -
    • -
    - - - - - -
    -
    - - set_max_gui_upscale(self, max_gui_upscale) -
    -
    - Set max gui upscale for FIT adjust mode (or side). It happens on bigger render gui screen - - -

    Parameters:

    -
      -
    • self - Layout - Layout -
    • -
    • max_gui_upscale - number - -
    • -
    - -

    Returns:

    -
      - - Layout - Layout -
    - - - - -
    -
    - - set_max_size(self, max_size) -
    -
    - Set maximum size of layout node - - -

    Parameters:

    -
      -
    • self - Layout - Layout -
    • -
    • max_size - vector3 - -
    • -
    - -

    Returns:

    -
      - - Layout - Layout -
    - - - - -
    -
    - - set_min_size(self, min_size) -
    -
    - Set minimal size of layout node - - -

    Parameters:

    -
      -
    • self - Layout - Layout -
    • -
    • min_size - vector3 - -
    • -
    - -

    Returns:

    -
      - - Layout - Layout -
    - - - - -
    -
    - - set_origin_position(self, new_origin_position) -
    -
    - Set new origin position of layout node. You should apply this on node movement - - -

    Parameters:

    -
      -
    • self - Layout - Layout -
    • -
    • new_origin_position - vector3 - -
    • -
    - -

    Returns:

    -
      - - Layout - Layout -
    - - - - -
    -
    - - set_origin_size(self, new_origin_size) -
    -
    - Set new origin size of layout node. You should apply this on node manual size change - - -

    Parameters:

    -
      -
    • self - Layout - Layout -
    • -
    • new_origin_size - vector3 - -
    • -
    - -

    Returns:

    -
      - - Layout - Layout -
    - - - - -
    -

    Fields

    @@ -461,26 +136,6 @@ -
    -
    - - on_size_changed -
    -
    - On window resize callback(self, new_size) - - - - - - - -
    diff --git a/docs/modules/PinKnob.html b/docs/modules/PinKnob.html index 6e58444..d97d64e 100644 --- a/docs/modules/PinKnob.html +++ b/docs/modules/PinKnob.html @@ -91,7 +91,7 @@ Set current and min/max angles for component - set_friction(self[, value=1]) + set_friction(self, value) Set current and min/max angles for component @@ -192,7 +192,7 @@
    - set_friction(self[, value=1]) + set_friction(self, value)
    Set current and min/max angles for component @@ -205,9 +205,8 @@ PinKnob
  • value - number - The spin speed multiplier - (default 1) + number or nil + The spin speed multiplier. Default: 1
  • diff --git a/docs/modules/Progress.html b/docs/modules/Progress.html index b72ba4f..cec8988 100644 --- a/docs/modules/Progress.html +++ b/docs/modules/Progress.html @@ -103,7 +103,7 @@ Return current progress bar value - init(self, node, key[, init_value=1]) + init(self, node, key, init_value) The Progress constructor @@ -234,7 +234,7 @@
    - init(self, node, key[, init_value=1]) + init(self, node, key, init_value)
    The Progress constructor @@ -255,9 +255,8 @@ Progress bar direction: const.SIDE.X or const.SIDE.Y
  • init_value - number - Initial value of progress bar - (default 1) + number or nil + Initial value of progress bar. Default: 1
  • @@ -401,14 +400,12 @@

    Fields:

    diff --git a/docs/modules/RadioGroup.html b/docs/modules/RadioGroup.html index 95b3e24..7445394 100644 --- a/docs/modules/RadioGroup.html +++ b/docs/modules/RadioGroup.html @@ -86,7 +86,7 @@ Return radio group state - init(self, nodes, callback[, click_nodes=node]) + init(self, nodes, callback, click_nodes) The RadioGroup constructor @@ -142,7 +142,7 @@
    - init(self, nodes, callback[, click_nodes=node]) + init(self, nodes, callback, click_nodes)
    The RadioGroup constructor @@ -163,9 +163,8 @@ Radio callback
  • click_nodes - node[] - Array of trigger nodes, by default equals to nodes - (default node) + node[] or nil + Array of trigger nodes, by default equals to nodes. Default - nodes
  • diff --git a/docs/modules/RichInput.html b/docs/modules/RichInput.html index c8d62dc..0c70936 100644 --- a/docs/modules/RichInput.html +++ b/docs/modules/RichInput.html @@ -84,20 +84,32 @@ - + + + + + + + + + + + + +
    get_text(self)GSet input field textSet input field text
    init(self, template, nodes) The RichInput constructor
    select(self)Select input field
    set_allowed_characters(self, characters) Set allowed charaters for input field.
    set_font(self, font)Set input field font
    set_placeholder(self, placeholder_text) Set placeholder text
    set_text(self, text)Set input field text

    Fields

    @@ -135,7 +147,7 @@ get_text(self)
    - GSet input field text + Set input field text

    Parameters:

    @@ -146,12 +158,6 @@ -

    Returns:

    -
      - - string - Current input text -
    @@ -185,6 +191,27 @@ +
    +
    + + select(self) +
    +
    + Select input field + + +

    Parameters:

    + + + + + +
    @@ -218,6 +245,37 @@ + +
    + + set_font(self, font) +
    +
    + Set input field font + + +

    Parameters:

    + + +

    Returns:

    +
      + + druid.input + Current input instance +
    + + + +
    @@ -234,16 +292,41 @@ RichInput
  • placeholder_text - string or nil + string The placeholder text
  • + + + + + +
    + + set_text(self, text) +
    +
    + Set input field text + + +

    Parameters:

    + +

    Returns:

      - RichInput - Current instance + druid.input + Current input instance
    diff --git a/docs/modules/RichText.html b/docs/modules/RichText.html index 372c37e..ec185a8 100644 --- a/docs/modules/RichText.html +++ b/docs/modules/RichText.html @@ -81,19 +81,7 @@ # Overview #

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

    All parameters for the Rich Text component are adjusted in the GUI scene. -

    This component uses GUI component template. (/druid/custom/rich_text/rich_text.gui). -

    You able to customize it or make your own with the next node scructure: -

    root -

    - text_prefab -

    - icon_prefab -

    # Rich Text Setup # -

    • Root node size: Set the maximum width and height of the text. -

    • Root anchor: Define the alignment of the Rich Text inside the root node size area. -

    • Text prefab: Configure all default text parameters for the text node. -

    • Text prefab anchor: Set the anchor for each text node (adjust this only if animating text). -

    • Icon prefab: Configure all default node parameters for the icon node. -

    • Icon prefab anchor: Set the anchor for each icon node (adjust this only if animating the icon). +

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

    # Notes #

    • Nested tags are supported

    Example Link

    @@ -119,7 +107,6 @@ self.rich_text:set_text("Hello, Druid Rich Text!") outline: vector4, font: string, image: druid.rich_text.image, - default_animation: string, br: boolean, nobr: boolean, } @@ -150,6 +137,10 @@ type druid.rich_text.metrics = {

    Functions

    + + + + @@ -159,11 +150,15 @@ type druid.rich_text.metrics = { + + + + - + @@ -171,7 +166,7 @@ type druid.rich_text.metrics = { - +
    characters(self, word)Split a word into it's characters
    clear() Clear all created words.Get current line metrics
    get_text(self)Get current text
    get_words() Get all current words.
    init(self, template, nodes)init(self, text_node, value) The RichText constructor
    Set text for Rich Text
    tagged(tag)tagged(self, tag) Get all words, which has a passed tag.
    @@ -188,6 +183,18 @@ type druid.rich_text.metrics = { druid The component druid instance + + icon_prefab + The icon prefab node + + + root + The root node of the Rich Text + + + text_prefab + The text prefab node +
    @@ -197,6 +204,37 @@ type druid.rich_text.metrics = {

    Functions

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

    Parameters:

    +
      +
    • self + RichText + RichText +
    • +
    • word + druid.rich_text.word + +
    • +
    + +

    Returns:

    +
      + + druid.rich_text.word[] + characters +
    + + + + +
    clear() @@ -230,6 +268,33 @@ type druid.rich_text.metrics = { +
    +
    + + get_text(self) +
    +
    + Get current text + + +

    Parameters:

    + + +

    Returns:

    +
      + + string + text +
    + + + +
    @@ -253,7 +318,7 @@ type druid.rich_text.metrics = {
    - init(self, template, nodes) + init(self, text_node, value)
    The RichText constructor @@ -265,13 +330,13 @@ type druid.rich_text.metrics = { RichText RichText -
  • template - string - The Rich Text template name +
  • text_node + node or string + The text node to make Rich Text
  • -
  • nodes - table - The node table, if prefab was copied by gui.clone_tree() +
  • value + string or nil + The initial text value. Default will be gui.get_text(text_node)
  • @@ -295,7 +360,7 @@ type druid.rich_text.metrics = { RichText
  • text - string + string or nil The text to set
  • @@ -361,7 +426,7 @@ Words <nobr>inside tag</nobr> won't break
    - tagged(tag) + tagged(self, tag)
    Get all words, which has a passed tag. @@ -369,6 +434,10 @@ Words <nobr>inside tag</nobr> won't breakParameters: @@ -683,7 +699,7 @@ The new size for content node
  • offset - vector3 + vector3 or nil Offset value to set, where content is starts
  • @@ -729,6 +745,58 @@ +
    +
    + + set_view_size(self, size) +
    +
    + Set new scroll view size in case the node size was changed. + + +

    Parameters:

    + + +

    Returns:

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

    Parameters:

    + + + + + +

    Tables

    @@ -747,64 +815,52 @@

    Fields:

    @@ -817,6 +873,26 @@

    Fields

    +
    + + _is_inert +
    +
    + Flag, if scroll now moving by inertion + + + + + + + + +
    available_pos @@ -1027,9 +1103,8 @@ @@ -1077,6 +1152,26 @@ + +
    + + view_size +
    +
    + Scroll view size + + + + + + + +
    diff --git a/docs/modules/Slider.html b/docs/modules/Slider.html index 3fdf8fe..94fc9f0 100644 --- a/docs/modules/Slider.html +++ b/docs/modules/Slider.html @@ -86,10 +86,18 @@ The Slider constructor + is_enabled(self) + Check if Slider component is enabled + + set(self, value, is_silent) Set value for slider + set_enabled(self, is_enabled) + Set Slider input enabled or disabled + + set_input_node(self, input_node) Set input zone for slider. @@ -177,6 +185,33 @@ + +
    + + is_enabled(self) +
    +
    + Check if Slider component is enabled + + +

    Parameters:

    + + +

    Returns:

    +
      + + boolean + +
    + + + +
    @@ -206,6 +241,31 @@ + +
    + + set_enabled(self, is_enabled) +
    +
    + Set Slider input enabled or disabled + + +

    Parameters:

    + + + + + +
    @@ -225,7 +285,7 @@ Slider
  • input_node - node + node, string or nil
  • @@ -291,7 +351,7 @@ diff --git a/docs/modules/StaticGrid.html b/docs/modules/StaticGrid.html index e5591d3..076f3bb 100644 --- a/docs/modules/StaticGrid.html +++ b/docs/modules/StaticGrid.html @@ -138,7 +138,7 @@ Return grid content size - init(self, parent, element[, in_row=1]) + init(self, parent, element, in_row) The StaticGrid constructor @@ -154,9 +154,21 @@ Set new in_row elements for grid + set_item_size(self[, width[, height]]) + Set new node size for grid + + + set_items(self, nodes[, is_instant=false]) + Set new items to the grid. + + set_position_function(self, callback) Change set position function for grid nodes. + + sort_nodes(self, comparator) + Sort grid nodes by custom comparator function +

    Tables

    @@ -496,7 +508,7 @@
    - init(self, parent, element[, in_row=1]) + init(self, parent, element, in_row)
    The StaticGrid constructor @@ -517,9 +529,8 @@ Element prefab. Need to get it size
  • in_row - number - How many nodes in row can be placed - (default 1) + number or nil + How many nodes in row can be placed. By default 1
  • @@ -622,6 +633,73 @@ +
    +
    + + set_item_size(self[, width[, height]]) +
    +
    + Set new node size for grid + + +

    Parameters:

    + + +

    Returns:

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

    Parameters:

    + + + + + +
    @@ -654,6 +732,37 @@ + +
    + + sort_nodes(self, comparator) +
    +
    + Sort grid nodes by custom comparator function + + +

    Parameters:

    + + +

    Returns:

    +
      + + druid.static_grid + Current grid instance +
    + + + +

    Tables

    @@ -672,14 +781,12 @@

    Fields:

    diff --git a/docs/modules/Swipe.html b/docs/modules/Swipe.html index 3b68b0d..da20bb1 100644 --- a/docs/modules/Swipe.html +++ b/docs/modules/Swipe.html @@ -169,7 +169,7 @@ Swipe
  • zone - node + node, string or nil Gui node
  • @@ -196,19 +196,16 @@

    Fields:

    diff --git a/docs/modules/Text.html b/docs/modules/Text.html index 179c6cb..4f7d196 100644 --- a/docs/modules/Text.html +++ b/docs/modules/Text.html @@ -105,11 +105,15 @@ + + + + - + @@ -247,6 +251,37 @@ + +
    + + get_text_index_by_width(self, width) +
    +
    + Get chars count by width + + +

    Parameters:

    + + +

    Returns:

    +
      + + number + Chars count +
    + + + +
    @@ -263,8 +298,8 @@ Text
  • text - string or nil - + string + |nil
  • @@ -284,7 +319,7 @@
    - init(self, node, value[, adjust_type=downscale]) + init(self, node, value, adjust_type)
    The Text constructor @@ -302,12 +337,11 @@
  • value string or nil - Initial text. Default value is node text from GUI scene. + Initial text. Default value is node text from GUI scene. Default: nil
  • adjust_type - string - Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference - (default downscale) + string or nil + Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference. Default: DOWNSCALE
  • @@ -544,7 +578,7 @@ Text
  • adjust_type - number or nil + string or nil See const.TEXT_ADJUST. If pass nil - use current adjust type
  • minimal_scale @@ -612,14 +646,20 @@

    Fields:

    • TRIM_POSTFIX - string - The postfix for TRIM adjust type - (default ...) + string or nil + The postfix for TRIM adjust type. Default: ...
    • DEFAULT_ADJUST - string - The default adjust type for any text component - (default DOWNSCALE) + string or nil + The default adjust type for any text component. Default: DOWNSCALE +
    • +
    • ADJUST_STEPS + string or nil + Amount of iterations for text adjust by height. Default: 20 +
    • +
    • ADJUST_SCALE_DELTA + string or nil + Scale step on each height adjust step. Default: 0.02
    diff --git a/docs/modules/Timer.html b/docs/modules/Timer.html index 7c3eb82..9dca7a5 100644 --- a/docs/modules/Timer.html +++ b/docs/modules/Timer.html @@ -158,7 +158,7 @@ Gui text node
  • seconds_from - number + number or nil Start timer value in seconds
  • seconds_to diff --git a/docs/modules/druid.extended.layout.html b/docs/modules/druid.extended.layout.html new file mode 100644 index 0000000..4f01fd5 --- /dev/null +++ b/docs/modules/druid.extended.layout.html @@ -0,0 +1,95 @@ + + + + + Defold Druid UI Framework + + + + +
    + +
    + +
    +
    +
    + + +
    + + + + + + +
    + +

    Module druid.extended.layout

    +

    Druid layout module +

    # Overview # +

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

    +

    Works like a Figma layout. +

    # Notes

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

    Module druid.system.utf8

    +

    +

    + + + +
    +
    + + + + +
    +
    +
    +generated by LDoc TESTING +Last updated 2015-01-01 12:00:00 +
    +
    + + diff --git a/docs_md/02-creating_custom_components.md b/docs_md/02-creating_custom_components.md index b7aaf99..cf9c32c 100644 --- a/docs_md/02-creating_custom_components.md +++ b/docs_md/02-creating_custom_components.md @@ -14,21 +14,14 @@ A basic custom component template looks like this (you can copy it from `/druid/ ```lua local component = require("druid.component") ----@class component_name : druid.base_component +---@class component_name: druid.base_component local Component = component.create("component_name") -local SCHEME = { - ROOT = "root", - BUTTON = "button", -} - 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.druid = self:get_druid(template, nodes) + self.root = self:get_node("root") - self.button = self.druid:new_button(SCHEME.BUTTON, function() end) + self.button = self.druid:new_button("button", function() end) end function Component:on_remove() end @@ -43,18 +36,12 @@ A full custom component template looks like this (you can copy it from `/druid/t ```lua local component = require("druid.component") ----@class component_name : druid.base_component +---@class component_name: druid.base_component local Component = component.create("component_name") -local SCHEME = { - ROOT = "root", - BUTTON = "button", -} 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.druid = self:get_druid(template, nodes) + self.root = self:get_node("root") end function Component:update(dt) end @@ -92,7 +79,7 @@ local my_component = require("my.amazing.component") function init(self) self.druid = druid.new(self) - self.druid:new(my_component, "template_name", nodes) + self.druid:new(my_component, "template_name") end ``` @@ -107,6 +94,7 @@ local druid = require("druid.druid") local my_component = require("my.amazing.component") function init(self) + -- Register makes a "druid:new_{component_name}" function available druid.register("my_component", my_component) end ``` @@ -145,36 +133,7 @@ Available keywords: - `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 [Dr - -uid Timer](01-components.md#timer) component. - -## Best Practices for Custom Components - -When working with each component, it's recommended to describe the component scheme in the following way: - -```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) - - local root = self:get_node(SCHEME.ROOT) - local druid = self:get_druid() - - -- Create components inside this component using the inner druid instance -end -``` +- `timer`: Adds a [Druid Timer](01-components.md#timer) component. ## The Power of Using Templates diff --git a/docs_md/advanced-setup.md b/docs_md/advanced-setup.md index ac13ec9..5e047a7 100644 --- a/docs_md/advanced-setup.md +++ b/docs_md/advanced-setup.md @@ -3,7 +3,7 @@ ## Input Bindings -By default, **Druid** utilizes the `/builtins/input/all.input_binding` for 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: @@ -14,6 +14,11 @@ By default, **Druid** utilizes the `/builtins/input/all.input_binding` for input - 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) @@ -37,6 +42,11 @@ 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 ``` diff --git a/docs_md/changelog.md b/docs_md/changelog.md index cffcf26..f04f284 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -500,3 +500,28 @@ Thanks to the my supporters: 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 0.12.0 + +**Changelog 0.12.0** +- New Logo! +- [Example] New Example Page with 40+ examples +- [Data List] Rework Data List. Now only works with Static Grid only. Now the Data List more stable with extended API. + - Add Cached Data List option. This used less memory (it's really much optimized) but requires uses the `on_add_element` and `on_remove_element` events to setup your nodes. All components should be the same class. +- [Rich Text] The Rich Text now applied to the text node instead of Rich Text Template (contained 3 nodes before - root, text and image prefabs) +- [Rich Input] Updated Rich Input. Now it goes with selection and cursor navigation. Added new input keys for setup in Druid (arrows keys, ctrl, shift) +- [System] Updated and fixed annotations +- [System] Removed `middleclass.lua` +- [System] Add `self:get_druid(template, nodes)` to escape the `self:set_template(template)` and `self:set_nodes(nodes)` calls in custom components +- [Input] Now user can tap from one text input area to another with one click. Before first tap is closed the focus on selected input. +- [Layout] Removed Layout component. Add new Layout component what do a some different things. It's like Dynamic Grid but with more control and settings. +- [Dynamic Grid] Deprecated Dynamic Grid. Layout will be instead of it. +- [Drag] Add touch param to Drag callbacks, it's much easier to add custom logic with knowledge of input action data. +- [Scroll] Add `scroll.view_size`, `scroll:set_view_size(size)` and `scroll:update_view_size()` functions to manage with current scroll input area and scroll visible part +- [Static Grid] Add `grid:set_item_size(size)`, `grid:sort_nodes(comparator)` functions +- [Text] Seems adjust by height for multiline text is workings good now +- [Rich Input] Extended Rich Input API +- [Progress Bar] More accurate scaling for progress bars fow images with slice9 params +- [Slider] Fix several slider issues in slider setup diff --git a/docs_md/game_examples.md b/docs_md/game_examples.md deleted file mode 100644 index 9735b3d..0000000 --- a/docs_md/game_examples.md +++ /dev/null @@ -1,8 +0,0 @@ -# Game Examples - -## Family Island - -## Sea Battle: Universe - -## Monkey Mart - diff --git a/druid/annotations.lua b/druid/annotations.lua index efd981f..4c9e4c7 100644 --- a/druid/annotations.lua +++ b/druid/annotations.lua @@ -63,8 +63,10 @@ function druid__base_component.get_context(self) end --- Get Druid instance for inner component creation. ---@param self druid.base_component @{BaseComponent} +---@param template string|nil The template name +---@param nodes table|nil The nodes table ---@return druid_instance Druid instance with component context -function druid__base_component.get_druid(self) end +function druid__base_component.get_druid(self, template, nodes) end --- Return component input priority ---@param self druid.base_component @{BaseComponent} @@ -168,7 +170,7 @@ function druid__blocker.set_enabled(self, state) end ---@class druid.button : druid.base_component ----@field anim_node node Button animation node. +---@field anim_node node|nil Button animation node. ---@field click_zone node|nil Additional button click area, defined by another GUI node ---@field hover druid.hover The @{Hover}: Button Hover component ---@field node node Button trigger node @@ -213,7 +215,7 @@ function druid__button.set_check_function(self, check_function, failure_callback --- 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 ---@param self druid.button @{Button} ----@param zone node|nil Gui node +---@param zone node|string|nil Gui node ---@return druid.button Current button instance function druid__button.set_click_zone(self, zone) end @@ -239,9 +241,9 @@ function druid__button.set_web_user_interaction(self, is_web_mode) end ---@class druid.button.style ----@field AUTOHOLD_TRIGGER number Maximum hold time to trigger button release while holding ----@field DOUBLETAP_TIME number Time between double taps ----@field LONGTAP_TIME number Minimum time to trigger on_hold_callback +---@field AUTOHOLD_TRIGGER number|nil Maximum hold time to trigger button release while holding. Default: 0.8 +---@field DOUBLETAP_TIME number|nil Time between double taps. Default: 0.4 +---@field LONGTAP_TIME number|nil Minimum time to trigger on_hold_callback. Default: 0.4 ---@field on_click function function(self, node) ---@field on_click_disabled function function(self, node) ---@field on_hover function function(self, node, hover_state) @@ -252,7 +254,7 @@ local druid__button__style = {} ---@class druid.checkbox : druid.base_component ---@field button druid.button Button component from click_node ----@field click_node node Button trigger node +---@field click_node node|nil Button trigger node ---@field node node Visual node ---@field on_change_state druid.event On change state callback(self, state) ---@field style druid.checkbox.style Component style params. @@ -267,8 +269,8 @@ function druid__checkbox.get_state(self) end ---@param self druid.checkbox @{Checkbox} ---@param node node Gui node ---@param callback function Checkbox callback ----@param click_node node Trigger node, by default equals to node ----@param initial_state boolean The initial state of checkbox, default - false +---@param click_node node|nil Trigger node, by default equals to node. Default: node +---@param initial_state boolean|nil The initial state of checkbox, default - false function druid__checkbox.init(self, node, callback, click_node, initial_state) end --- Set checkbox state @@ -298,7 +300,7 @@ function druid__checkbox_group.get_state(self) end ---@param self druid.checkbox_group @{CheckboxGroup} ---@param nodes node[] Array of gui node ---@param callback function Checkbox callback ----@param click_nodes node[] Array of trigger nodes, by default equals to nodes +---@param click_nodes node[]|nil Array of trigger nodes, by default equals to nodes function druid__checkbox_group.init(self, nodes, callback, click_nodes) end --- Set checkbox group state @@ -310,15 +312,23 @@ function druid__checkbox_group.set_state(self, indexes, is_instant) end ---@class druid.data_list : druid.base_component ---@field grid druid.static_grid|druid.dynamic_grid The Druid Grid component ----@field last_index number The current visual last data index +---@field last_index number The current last index of visual elements ---@field on_element_add druid.event On DataList visual element created Event callback(self, index, node, instance) ---@field on_element_remove druid.event On DataList visual element created Event callback(self, index) ---@field on_scroll_progress_change druid.event Event triggered when scroll progress is changed; event(self, progress_value) ---@field scroll druid.scroll The Druid scroll component ---@field scroll_progress number The current progress of scroll posititon ----@field top_index number The current visual top data index +---@field top_index number The current top index of visual elements local druid__data_list = {} +--- Add element to DataList. +--- Currenly untested +---@param self druid.data_list @{DataList} +---@param data table +---@param index number|nil +---@param shift_policy number|nil The constant from const.SHIFT.* +function druid__data_list.add(self, data, index, shift_policy) end + --- Clear the DataList and refresh visuals ---@param self druid.data_list @{DataList} function druid__data_list.clear(self) end @@ -338,24 +348,11 @@ function druid__data_list.get_created_nodes(self) end ---@return table The current data array function druid__data_list.get_data(self) end ---- Return first index from data. ---- It not always equals to 1 ----@param self druid.data_list @{DataList} -function druid__data_list.get_first_index(self) end - --- Return index for data value ---@param self druid.data_list @{DataList} ---@param data table function druid__data_list.get_index(self, data) end ---- Return last index from data ----@param self druid.data_list @{DataList} -function druid__data_list.get_last_index(self) end - ---- Return amount of data ----@param self druid.data_list @{DataList} -function druid__data_list.get_length(self) end - --- The @{DataList} constructor ---@param self druid.data_list @{DataList} ---@param scroll druid.scroll The @{Scroll} instance for Data List component @@ -367,6 +364,20 @@ function druid__data_list.init(self, scroll, grid, create_function) end ---@param self druid.data_list @{DataList} function druid__data_list.on_remove(self) end +--- Remove element from DataList. +--- Currenly untested +---@param self druid.data_list @{DataList} +---@param index number|nil +---@param shift_policy number|nil The constant from const.SHIFT.* +function druid__data_list.remove(self, index, shift_policy) end + +--- Remove element from DataList by data value. +--- Currenly untested +---@param self druid.data_list @{DataList} +---@param data table +---@param shift_policy number|nil The constant from const.SHIFT.* +function druid__data_list.remove_by_data(self, data, shift_policy) end + --- Instant scroll to element with passed index ---@param self druid.data_list @{DataList} ---@param index number @@ -378,6 +389,12 @@ function druid__data_list.scroll_to_index(self, index) end ---@return druid.data_list Current DataList instance function druid__data_list.set_data(self, data) end +--- Set refresh function for DataList component +---@param self druid.data_list @{DataList} +---@param is_use_cache boolean Use cache version of DataList. Requires make setup of components in on_element_add callback and clean in on_element_remove +---@return druid.data_list Current DataList instance +function druid__data_list.set_use_cache(self, is_use_cache) end + ---@class druid.drag : druid.base_component ---@field can_x boolean Is drag component process vertical dragging. @@ -385,17 +402,17 @@ function druid__data_list.set_data(self, data) end ---@field is_drag boolean Is component now dragging ---@field is_touch boolean Is component now touching ---@field node node Drag node ----@field on_drag druid.event on drag progress callback(self, dx, dy, total_x, total_y) ----@field on_drag_end druid.event Event on drag end callback(self, total_x, total_y) +---@field on_drag druid.event on drag progress callback(self, dx, dy, total_x, total_y, touch) +---@field on_drag_end druid.event Event on drag end callback(self, total_x, total_y, touch) ---@field on_drag_start druid.event Event on drag start callback(self, touch) ---@field on_touch_end druid.event Event on touch end callback(self) ---@field on_touch_start druid.event Event on touch start callback(self) +---@field screen_x number Current touch x screen position +---@field screen_y number Current touch y screen position ---@field style druid.drag.style Component style params. ---@field touch_start_pos vector3 Touch start position ---@field x number Current touch x position ---@field y number Current touch y position ----@field screen_x number Current touch x screen position ----@field screen_y number Current touch y screen position local druid__drag = {} --- The @{Drag} constructor @@ -412,7 +429,7 @@ function druid__drag.is_enabled(self) end --- Strict drag click area. --- Useful for restrict events outside stencil node ---@param self druid.drag @{Drag} ----@param node node Gui node +---@param node node|string|nil Gui node function druid__drag.set_click_zone(self, node) end --- Set Drag input enabled or disabled @@ -422,8 +439,8 @@ function druid__drag.set_enabled(self, is_enabled) end ---@class druid.drag.style ----@field DRAG_DEADZONE number Distance in pixels to start dragging ----@field NO_USE_SCREEN_KOEF boolean If screen aspect ratio affects on drag values +---@field DRAG_DEADZONE number|nil Distance in pixels to start dragging. Default: 10 +---@field NO_USE_SCREEN_KOEF boolean|nil If screen aspect ratio affects on drag values. Default: false local druid__drag__style = {} @@ -487,7 +504,7 @@ function druid__dynamic_grid.get_offset(self) end ---@param index number The grid element index ---@param node node The node to be placed ---@param origin_index number|nil Index of nearby node ----@return vector3 Node position +---@return vector3 node position function druid__dynamic_grid.get_pos(self, index, node, origin_index) end --- Return grid content size @@ -526,20 +543,33 @@ local druid__event = {} function druid__event.clear(self) end --- DruidEvent constructor +---@param callback function|nil Subscribe the callback on new event, if callback exist +---@param callback_context any|nil Additional context as first param to callback call +function druid__event.create(callback, callback_context) end + +--- Return true, if event not have handler ---@param self druid.event @{DruidEvent} ----@param initial_callback function|nil Subscribe the callback on new event, if callback exist -function druid__event.initialize(self, initial_callback) end +---@return boolean True if event not have handlers +function druid__event.is_empty(self) end --- Return true, if event have at lease one handler ---@param self druid.event @{DruidEvent} ---@return boolean True if event have handlers function druid__event.is_exist(self) end +--- Check is event subscribed. +---@param self druid.event @{DruidEvent} +---@param callback function Callback itself +---@param callback_context any|nil Additional context as first param to callback call +---@return boolean, number|nil @Is event subscribed, return index of callback in event as second param +function druid__event.is_subscribed(self, callback, callback_context) end + --- Subscribe callback on event ---@param self druid.event @{DruidEvent} ---@param callback function Callback itself ----@param context any|nil Additional context as first param to callback call, usually it's self -function druid__event.subscribe(self, callback, context) end +---@param callback_context any|nil Additional context as first param to callback call, usually it's self +---@return boolean True if callback was subscribed +function druid__event.subscribe(self, callback, callback_context) end --- Trigger the event and call all subscribed callbacks ---@param self druid.event @{DruidEvent} @@ -549,15 +579,16 @@ function druid__event.trigger(self, ...) end --- Unsubscribe callback on event ---@param self druid.event @{DruidEvent} ---@param callback function Callback itself ----@param context any|nil Additional context as first param to callback call -function druid__event.unsubscribe(self, callback, context) end +---@param callback_context any|nil Additional context as first param to callback call +function druid__event.unsubscribe(self, callback, callback_context) end ---@class druid.hotkey : druid.base_component ---@field button druid.button Button component from click_node ----@field click_node node Button trigger node +---@field click_node node|nil Button trigger node ---@field node node Visual node ----@field on_change_state druid.event On change state callback(self, state) +---@field on_hotkey_pressed druid.event On hotkey released callback(self, argument) +---@field on_hotkey_released druid.event On hotkey released callback(self, argument) ---@field style druid.hotkey.style Component style params. local druid__hotkey = {} @@ -588,15 +619,18 @@ local druid__hotkey__style = {} ---@class druid.hover : druid.base_component +---@field node node Hover node ---@field on_hover druid.event On hover callback(self, state, hover_instance) ---@field on_mouse_hover druid.event On mouse hover callback(self, state, hover_instance) +---@field style druid.hover.style Component style params. local druid__hover = {} --- The @{Hover} constructor ---@param self druid.hover @{Hover} ---@param node node Gui node ---@param on_hover_callback function Hover callback -function druid__hover.init(self, node, on_hover_callback) end +---@param on_mouse_hover function On mouse hover callback +function druid__hover.init(self, node, on_hover_callback, on_mouse_hover) end --- Return current hover enabled state ---@param self druid.hover @{Hover} @@ -618,7 +652,7 @@ function druid__hover.is_mouse_hovered(self) end --- Strict hover click area. --- Useful for no click events outside stencil node ---@param self druid.hover @{Hover} ----@param zone node Gui node +---@param zone node|string|nil Gui node function druid__hover.set_click_zone(self, zone) end --- Set enable state of hover component. @@ -638,21 +672,37 @@ function druid__hover.set_hover(self, state) end function druid__hover.set_mouse_hover(self, state) end +---@class druid.hover.style +---@field ON_HOVER_CURSOR string Mouse hover style on node hover +---@field ON_MOUSE_HOVER_CURSOR string Mouse hover style on node mouse hover +local druid__hover__style = {} + + ---@class druid.input : druid.base_component ---@field allowerd_characters string|nil Pattern matching for user input ---@field button druid.button Button component +---@field current_value string Current input value with marked text +---@field cursor_index number The cursor index. +---@field end_index number Theselection end index. ---@field is_empty boolean Is current input is empty now ---@field is_selected boolean Is current input selected now ---@field keyboard_type number Gui keyboard type for input field +---@field marked_text_width number Marked text width +---@field marked_value string Marked text for input field. ---@field max_length number|nil Max length for input text ---@field on_input_empty druid.event On input field text change to empty string callback(self, input_text) ---@field on_input_full druid.event On input field text change to max length string callback(self, input_text) ----@field on_input_select druid.event On input field select callback(self, button_node) +---@field on_input_select druid.event On input field select callback(self, input_instance) ---@field on_input_text druid.event On input field text change callback(self, input_text) ----@field on_input_unselect druid.event On input field unselect callback(self, input_text) ----@field on_input_wrong druid.event On trying user input with not allowed character callback(self, params, button_instance) +---@field on_input_unselect druid.event On input field unselect callback(self, input_text, input_instance) +---@field on_input_wrong druid.event On trying user input with not allowed character callback(self, params, input_text) +---@field on_select_cursor_change druid.event On cursor position change callback(self, cursor_index, start_index, end_index) +---@field previous_value string Previous input value +---@field start_index number The selection start index. ---@field style druid.input.style Component style params. ---@field text druid.text Text component +---@field text_width number Text width +---@field value string Current input value local druid__input = {} --- Return current input field text @@ -660,6 +710,12 @@ local druid__input = {} ---@return string The current input field text function druid__input.get_text(self) end +--- Replace selected text with new text +---@param self druid.input @{Input} +---@param text string The text to replace selected text +---@return string New input text +function druid__input.get_text_selected_replaced(self, text) end + --- The @{Input} constructor ---@param self druid.input @{Input} ---@param click_node node Node to enabled input component @@ -667,8 +723,16 @@ function druid__input.get_text(self) end ---@param keyboard_type number|nil Gui keyboard type for input field function druid__input.init(self, click_node, text_node, keyboard_type) end +--- Change cursor position by delta +---@param self druid.input @{Input} +---@param delta number side for cursor position, -1 for left, 1 for right +---@param is_add_to_selection boolean (Shift key) +---@param is_move_to_end boolean (Ctrl key) +function druid__input.move_selection(self, delta, is_add_to_selection, is_move_to_end) end + --- Reset current input selection and return previous value ---@param self druid.input @{Input} +---@return druid.input Current input instance function druid__input.reset_changes(self) end --- Select input field. @@ -676,6 +740,14 @@ function druid__input.reset_changes(self) end ---@param self druid.input @{Input} function druid__input.select(self) end +--- Set cursor position in input field +---@param self druid.input @{Input} +---@param cursor_index number|nil Cursor index for cursor position, if nil - will be set to the end of the text +---@param start_index number|nil Start index for cursor position, if nil - will be set to the end of the text +---@param end_index number|nil End index for cursor position, if nil - will be set to the start_index +---@return druid.input Current input instance +function druid__input.select_cursor(self, cursor_index, start_index, end_index) end + --- Set allowed charaters for input field. --- See: https://defold.com/ref/stable/string/ ex: [%a%d] for alpha and numeric ---@param self druid.input @{Input} @@ -702,11 +774,9 @@ function druid__input.unselect(self) end ---@class druid.input.style ----@field IS_LONGTAP_ERASE boolean Is long tap will erase current input data ----@field IS_UNSELECT_ON_RESELECT boolean If true, call unselect on select selected input ----@field MASK_DEFAULT_CHAR string Default character mask for password input ----@field NO_CONSUME_INPUT_WHILE_SELECTED boolean If true, will not consume input while input is selected. It's allow to interact with other components while input is selected (text input still captured) ----@field button_style table Custom button style for input node +---@field IS_LONGTAP_ERASE boolean Is long tap will erase current input data. Default: false +---@field IS_UNSELECT_ON_RESELECT boolean If true, call unselect on select selected input. Default: false +---@field MASK_DEFAULT_CHAR string Default character mask for password input. Default: *] ---@field on_input_wrong function (self, button_node) Callback on wrong user input ---@field on_select function (self, button_node) Callback on input field selecting ---@field on_unselect function (self, button_node) Callback on input field unselecting @@ -734,8 +804,8 @@ function druid__lang_text.format(self, a, b, c, d, e, f, g) end --- The @{LangText} constructor ---@param self druid.lang_text @{LangText} ---@param node string|node The node_id or gui.get_node(node_id) ----@param locale_id string Default locale id or text from node as default ----@param adjust_type string Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference +---@param locale_id string|nil Default locale id or text from node as default +---@param adjust_type string|nil Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference function druid__lang_text.init(self, node, locale_id, adjust_type) end --- Setup raw text to lang_text component @@ -761,67 +831,8 @@ function druid__lang_text.translate(self, locale_id, a, b, c, d, e, f, g) end ---@class druid.layout : druid.base_component ---@field mode string Current layout mode ---@field node node Layout node ----@field on_size_changed druid.event On window resize callback(self, new_size) local druid__layout = {} ---- Set node for layout node to fit inside it. ---- Pass nil to reset ----@param self druid.layout @{Layout} ----@param node node|nil ----@return druid.layout @{Layout} -function druid__layout.fit_into_node(self, node) end - ---- Set size for layout node to fit inside it ----@param self druid.layout @{Layout} ----@param target_size vector3 ----@return druid.layout @{Layout} -function druid__layout.fit_into_size(self, target_size) end - ---- Set current size for layout node to fit inside it ----@param self druid.layout @{Layout} ----@return druid.layout @{Layout} -function druid__layout.fit_into_window(self) end - ---- The @{Layout} constructor ----@param self druid.layout @{Layout} ----@param node node Gui node ----@param mode string The layout mode (from const.LAYOUT_MODE) ----@param on_size_changed_callback function|nil The callback on window resize -function druid__layout.init(self, node, mode, on_size_changed_callback) end - ---- Set max gui upscale for FIT adjust mode (or side). ---- It happens on bigger render gui screen ----@param self druid.layout @{Layout} ----@param max_gui_upscale number ----@return druid.layout @{Layout} -function druid__layout.set_max_gui_upscale(self, max_gui_upscale) end - ---- Set maximum size of layout node ----@param self druid.layout @{Layout} ----@param max_size vector3 ----@return druid.layout @{Layout} -function druid__layout.set_max_size(self, max_size) end - ---- Set minimal size of layout node ----@param self druid.layout @{Layout} ----@param min_size vector3 ----@return druid.layout @{Layout} -function druid__layout.set_min_size(self, min_size) end - ---- Set new origin position of layout node. ---- You should apply this on node movement ----@param self druid.layout @{Layout} ----@param new_origin_position vector3 ----@return druid.layout @{Layout} -function druid__layout.set_origin_position(self, new_origin_position) end - ---- Set new origin size of layout node. ---- You should apply this on node manual size change ----@param self druid.layout @{Layout} ----@param new_origin_size vector3 ----@return druid.layout @{Layout} -function druid__layout.set_origin_size(self, new_origin_size) end - ---@class druid.pin_knob : druid.base_component ---@field druid druid_instance The component druid instance @@ -846,7 +857,7 @@ function druid__pin_knob.set_angle(self, cur_value, min, max) end --- Set current and min/max angles for component ---@param self druid.pin_knob @{PinKnob} ----@param value number The spin speed multiplier +---@param value number|nil The spin speed multiplier. Default: 1 ---@return druid.pin_knob @{PinKnob} function druid__pin_knob.set_friction(self, value) end @@ -878,7 +889,7 @@ function druid__progress.get(self) end ---@param self druid.progress @{Progress} ---@param node string|node Node name or GUI Node itself. ---@param key string Progress bar direction: const.SIDE.X or const.SIDE.Y ----@param init_value number Initial value of progress bar +---@param init_value number|nil Initial value of progress bar. Default: 1 function druid__progress.init(self, node, key, init_value) end --- Set progress bar max node size @@ -906,8 +917,8 @@ function druid__progress.to(self, to, callback) end ---@class druid.progress.style ----@field MIN_DELTA number Minimum step to fill progress bar ----@field SPEED number Progress bas fill rate. More -> faster +---@field MIN_DELTA number|nil Minimum step to fill progress bar. Default: 0.005 +---@field SPEED number|nil Progress bas fill rate. More -> faster. Default: 5 local druid__progress__style = {} @@ -925,7 +936,7 @@ function druid__radio_group.get_state(self) end ---@param self druid.radio_group @{RadioGroup} ---@param nodes node[] Array of gui node ---@param callback function Radio callback ----@param click_nodes node[] Array of trigger nodes, by default equals to nodes +---@param click_nodes node[]|nil Array of trigger nodes, by default equals to nodes. Default - nodes function druid__radio_group.init(self, nodes, callback, click_nodes) end --- Set radio group state @@ -935,7 +946,7 @@ function druid__radio_group.init(self, nodes, callback, click_nodes) end function druid__radio_group.set_state(self, index, is_instant) end ----@class druid.rich_input : druid.input +---@class druid.rich_input ---@field cursor node On input field text change to empty string callback(self, input_text) ---@field druid druid_instance The component druid instance ---@field input druid.input On input field text change callback(self, input_text) @@ -943,9 +954,8 @@ function druid__radio_group.set_state(self, index, is_instant) end ---@field root node Root node local druid__rich_input = {} ---- GSet input field text +--- Set input field text ---@param self druid.rich_input @{RichInput} ----@return string Current input text function druid__rich_input.get_text(self) end --- The @{RichInput} constructor @@ -954,6 +964,10 @@ function druid__rich_input.get_text(self) end ---@param nodes table Nodes table from gui.clone_tree function druid__rich_input.init(self, template, nodes) end +--- Select input field +---@param self druid.rich_input @{RichInput} +function druid__rich_input.select(self) end + --- Set allowed charaters for input field. --- See: https://defold.com/ref/stable/string/ ex: [%a%d] for alpha and numeric ---@param self druid.rich_input @{RichInput} @@ -961,18 +975,38 @@ function druid__rich_input.init(self, template, nodes) end ---@return druid.rich_input Current instance function druid__rich_input.set_allowed_characters(self, characters) end +--- Set input field font +---@param self druid.rich_input @{RichInput} +---@param font hash The font hash +---@return druid.input Current input instance +function druid__rich_input.set_font(self, font) end + --- Set placeholder text ---@param self druid.rich_input @{RichInput} ----@param placeholder_text string|nil The placeholder text ----@return druid.rich_input Current instance +---@param placeholder_text string The placeholder text function druid__rich_input.set_placeholder(self, placeholder_text) end +--- Set input field text +---@param self druid.rich_input @{RichInput} +---@param text string The input text +---@return druid.input Current input instance +function druid__rich_input.set_text(self, text) end + ---@class druid.rich_text : druid.base_component ---@field druid druid_instance The component druid instance +---@field icon_prefab node The icon prefab node +---@field root node The root node of the Rich Text ---@field style druid.rich_text.style Component style params. +---@field text_prefab node The text prefab node local druid__rich_text = {} +--- Split a word into it's characters +---@param self druid.rich_text @{RichText} +---@param word druid.rich_text.word +---@return druid.rich_text.word[] characters +function druid__rich_text.characters(self, word) end + --- Clear all created words. function druid__rich_text.clear() end @@ -980,38 +1014,44 @@ function druid__rich_text.clear() end ---@return druid.rich_text.lines_metrics function druid__rich_text.get_line_metric() end +--- Get current text +---@param self druid.rich_text @{RichText} +---@return string text +function druid__rich_text.get_text(self) end + --- Get all current words. ---@return table druid.rich_text.word[] function druid__rich_text.get_words() end --- The @{RichText} constructor ---@param self druid.rich_text @{RichText} ----@param template string The Rich Text template name ----@param nodes table The node table, if prefab was copied by gui.clone_tree() -function druid__rich_text.init(self, template, nodes) end +---@param text_node node|string The text node to make Rich Text +---@param value string|nil The initial text value. Default will be gui.get_text(text_node) +function druid__rich_text.init(self, text_node, value) end --- Set text for Rich Text ---@param self druid.rich_text @{RichText} ----@param text string The text to set +---@param text string|nil The text to set ---@return druid.rich_text.word[] words ---@return druid.rich_text.lines_metrics line_metrics function druid__rich_text.set_text(self, text) end --- Get all words, which has a passed tag. +---@param self druid.rich_text @{RichText} ---@param tag string ---@return druid.rich_text.word[] words -function druid__rich_text.tagged(tag) end +function druid__rich_text.tagged(self, tag) end ---@class druid.rich_text.style ----@field ADJUST_SCALE_DELTA number Scale step on each height adjust step ----@field ADJUST_STEPS number Amount steps of attemps text adjust by height ----@field COLORS table Rich Text color aliases +---@field ADJUST_SCALE_DELTA number|nil Scale step on each height adjust step. Default: 0.02 +---@field ADJUST_STEPS number|nil Amount steps of attemps text adjust by height. Default: 20 +---@field COLORS table|nil Rich Text color aliases. Default: {} local druid__rich_text__style = {} ---@class druid.scroll : druid.base_component ----@field _is_inert bool Flag, if scroll now moving by inertion +---@field _is_inert boolean Flag, if scroll now moving by inertion ---@field available_pos vector4 Available position for content node: (min_x, max_y, max_x, min_y) ---@field available_size vector3 Size of available positions: (width, height, 0) ---@field content_node node Scroll content node @@ -1026,6 +1066,7 @@ local druid__rich_text__style = {} ---@field style druid.scroll.style Component style params. ---@field target_position vector3 Current scroll target position ---@field view_node node Scroll view node +---@field view_size vector3 Scroll view size local druid__scroll = {} --- Bind the grid component (Static or Dynamic) to recalculate scroll size on grid changes @@ -1084,7 +1125,7 @@ function druid__scroll.scroll_to_percent(self, percent, is_instant) end --- Strict drag scroll area. --- Useful for restrict events outside stencil node ---@param self druid.drag ----@param node node Gui node +---@param node node|string Gui node function druid__scroll.set_click_zone(self, node) end --- Set extra size for scroll stretching. @@ -1118,7 +1159,7 @@ function druid__scroll.set_points(self, points) end --- It will change content gui node size ---@param self druid.scroll @{Scroll} ---@param size vector3 The new size for content node ----@param offset vector3 Offset value to set, where content is starts +---@param offset vector3|nil Offset value to set, where content is starts ---@return druid.scroll Current scroll instance function druid__scroll.set_size(self, size, offset) end @@ -1128,25 +1169,35 @@ function druid__scroll.set_size(self, size, offset) end ---@return druid.scroll Current scroll instance function druid__scroll.set_vertical_scroll(self, state) end +--- Set new scroll view size in case the node size was changed. +---@param self druid.scroll @{Scroll} +---@param size vector3 The new size for view node +---@return druid.scroll Current scroll instance +function druid__scroll.set_view_size(self, size) end + +--- Refresh scroll view size +---@param self druid.scroll @{Scroll} +function druid__scroll.update_view_size(self) end + ---@class druid.scroll.style ----@field ANIM_SPEED number Scroll gui.animation speed for scroll_to function ----@field BACK_SPEED number Scroll back returning lerp speed ----@field EXTRA_STRETCH_SIZE number extra size in pixels outside of scroll (stretch effect) ----@field FRICT number Multiplier for free inertion ----@field FRICT_HOLD number Multiplier for inertion, while touching ----@field INERT_SPEED number Multiplier for inertion speed ----@field INERT_THRESHOLD number Scroll speed to stop inertion ----@field POINTS_DEADZONE number Speed to check points of interests in no_inertion mode ----@field SMALL_CONTENT_SCROLL boolean If true, content node with size less than view node size can be scrolled ----@field WHEEL_SCROLL_BY_INERTION boolean If true, wheel will add inertion to scroll. Direct set position otherwise. ----@field WHEEL_SCROLL_INVERTED boolean If true, invert direction for touchpad and mouse wheel scroll ----@field WHEEL_SCROLL_SPEED boolean The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling +---@field ANIM_SPEED number|nil Scroll gui.animation speed for scroll_to function. Default: 2 +---@field BACK_SPEED number|nil Scroll back returning lerp speed. Default: 35 +---@field EXTRA_STRETCH_SIZE number|nil extra size in pixels outside of scroll (stretch effect). Default: 0 +---@field FRICT number|nil Multiplier for free inertion. Default: 0 +---@field FRICT_HOLD number|nil Multiplier for inertion, while touching. Default: 0 +---@field INERT_SPEED number|nil Multiplier for inertion speed. Default: 30 +---@field INERT_THRESHOLD number|nil Scroll speed to stop inertion. Default: 3 +---@field POINTS_DEADZONE number|nil Speed to check points of interests in no_inertion mode. Default: 20 +---@field SMALL_CONTENT_SCROLL boolean|nil If true, content node with size less than view node size can be scrolled. Default: false +---@field WHEEL_SCROLL_BY_INERTION boolean|nil If true, wheel will add inertion to scroll. Direct set position otherwise.. Default: false +---@field WHEEL_SCROLL_INVERTED boolean|nil If true, invert direction for touchpad and mouse wheel scroll. Default: false +---@field WHEEL_SCROLL_SPEED boolean|nil The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling. Default: 0 local druid__scroll__style = {} ---@class druid.slider : druid.base_component ----@field dist number Length between start and end position +---@field dist vector3 Length between start and end position ---@field end_pos vector3 End pin node position ---@field is_drag boolean Current drag state ---@field node node Slider pin node @@ -1164,16 +1215,26 @@ local druid__slider = {} ---@param callback function|nil On slider change callback function druid__slider.init(self, node, end_pos, callback) end +--- Check if Slider component is enabled +---@param self druid.slider @{Slider} +---@return boolean +function druid__slider.is_enabled(self) end + --- Set value for slider ---@param self druid.slider @{Slider} ---@param value number Value from 0 to 1 ---@param is_silent boolean|nil Don't trigger event if true function druid__slider.set(self, value, is_silent) end +--- Set Slider input enabled or disabled +---@param self druid.slider @{Slider} +---@param is_enabled boolean +function druid__slider.set_enabled(self, is_enabled) end + --- Set input zone for slider. --- User can touch any place of node, pin instantly will move at this position and node drag will start. This function require the Defold version 1.3.0+ ---@param self druid.slider @{Slider} ----@param input_node node +---@param input_node node|string|nil ---@return druid.slider @{Slider} function druid__slider.set_input_node(self, input_node) end @@ -1258,7 +1319,7 @@ function druid__static_grid.get_size(self) end ---@param self druid.static_grid @{StaticGrid} ---@param parent string|node The GUI Node container, where grid's items will be placed ---@param element node Element prefab. Need to get it size ----@param in_row number How many nodes in row can be placed +---@param in_row number|nil How many nodes in row can be placed. By default 1 function druid__static_grid.init(self, parent, element, in_row) end --- Remove the item from the grid. @@ -1282,6 +1343,20 @@ function druid__static_grid.set_anchor(self, anchor) end ---@return druid.static_grid Current grid instance function druid__static_grid.set_in_row(self, in_row) end +--- Set new node size for grid +---@param self druid.static_grid @{StaticGrid} +---@param width number The new node width +---@param height number The new node height +---@return druid.static_grid Current grid instance +function druid__static_grid.set_item_size(self, width, height) end + +--- Set new items to the grid. +--- All previous items will be removed +---@param self druid.static_grid @{StaticGrid} +---@param nodes node[] The new grid nodes +---@param is_instant boolean If true, update node positions instantly +function druid__static_grid.set_items(self, nodes, is_instant) end + --- Change set position function for grid nodes. --- It will call on update poses on grid elements. Default: gui.set_position ---@param self druid.static_grid @{StaticGrid} @@ -1289,10 +1364,16 @@ function druid__static_grid.set_in_row(self, in_row) end ---@return druid.static_grid Current grid instance function druid__static_grid.set_position_function(self, callback) end +--- Sort grid nodes by custom comparator function +---@param self druid.static_grid @{StaticGrid} +---@param comparator function The comparator function. (a, b) -> boolean +---@return druid.static_grid Current grid instance +function druid__static_grid.sort_nodes(self, comparator) end + ---@class druid.static_grid.style ----@field IS_ALIGN_LAST_ROW boolean If true, always align last row of the grid as grid pivot sets ----@field IS_DYNAMIC_NODE_POSES boolean If true, always center grid content as grid pivot sets +---@field IS_ALIGN_LAST_ROW boolean|nil If true, always align last row of the grid as grid pivot sets. Default: false +---@field IS_DYNAMIC_NODE_POSES boolean|nil If true, always center grid content as grid pivot sets. Default: false local druid__static_grid__style = {} @@ -1312,14 +1393,14 @@ function druid__swipe.init(self, node, on_swipe_callback) end --- Strict swipe click area. --- Useful for restrict events outside stencil node ---@param self druid.swipe @{Swipe} ----@param zone node Gui node +---@param zone node|string|nil Gui node function druid__swipe.set_click_zone(self, zone) end ---@class druid.swipe.style ----@field SWIPE_THRESHOLD number Minimum distance for swipe trigger ----@field SWIPE_TIME number Maximum time for swipe trigger ----@field SWIPE_TRIGGER_ON_MOVE boolean If true, trigger on swipe moving, not only release action +---@field SWIPE_THRESHOLD number|nil Minimum distance for swipe trigger. Default: 50 +---@field SWIPE_TIME number|nil Maximum time for swipe trigger. Default: 0.4 +---@field SWIPE_TRIGGER_ON_MOVE boolean|nil If true, trigger on swipe moving, not only release action. Default: false local druid__swipe__style = {} @@ -1346,9 +1427,15 @@ local druid__text = {} ---@return number The current text adjust type function druid__text.get_text_adjust(self, adjust_type) end +--- Get chars count by width +---@param self druid.text @{Text} +---@param width number +---@return number Chars count +function druid__text.get_text_index_by_width(self, width) end + --- Calculate text width with font with respect to trailing space ---@param self druid.text @{Text} ----@param text string|nil +---@param text string |nil ---@return number Width ---@return number Height function druid__text.get_text_size(self, text) end @@ -1356,8 +1443,8 @@ function druid__text.get_text_size(self, text) end --- The @{Text} constructor ---@param self druid.text @{Text} ---@param node string|node Node name or GUI Text Node itself ----@param value string|nil Initial text. Default value is node text from GUI scene. ----@param adjust_type string Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference +---@param value string|nil Initial text. Default value is node text from GUI scene. Default: nil +---@param adjust_type string|nil Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference. Default: DOWNSCALE function druid__text.init(self, node, value, adjust_type) end --- Return true, if text with line break @@ -1417,8 +1504,10 @@ function druid__text.set_to(self, set_to) end ---@class druid.text.style ----@field DEFAULT_ADJUST string The default adjust type for any text component ----@field TRIM_POSTFIX string The postfix for TRIM adjust type +---@field ADJUST_SCALE_DELTA string|nil Scale step on each height adjust step. Default: 0.02 +---@field ADJUST_STEPS string|nil Amount of iterations for text adjust by height. Default: 20 +---@field DEFAULT_ADJUST string|nil The default adjust type for any text component. Default: DOWNSCALE +---@field TRIM_POSTFIX string|nil The postfix for TRIM adjust type. Default: ... local druid__text__style = {} @@ -1435,7 +1524,7 @@ local druid__timer = {} --- The @{Timer} constructor ---@param self druid.timer @{Timer} ---@param node node Gui text node ----@param seconds_from number Start timer value in seconds +---@param seconds_from number|nil Start timer value in seconds ---@param seconds_to number|nil End timer value in seconds ---@param callback function|nil Function on timer end function druid__timer.init(self, node, seconds_from, seconds_to, callback) end @@ -1464,13 +1553,6 @@ local druid_instance = {} ---@param self druid_instance function druid_instance.final(self) end ---- Create new component. ----@param self druid_instance ----@param component druid.base_component Component module ----@param ... any Other component params to pass it to component:init function ----@return druid.base_component Component instance -function druid_instance.new(self, component, ...) end - --- Create @{BackHandler} component ---@param self druid_instance ---@param callback function|nil @The callback(self, custom_args) to call on back event @@ -1488,8 +1570,8 @@ function druid_instance.new_blocker(self, node) end ---@param self druid_instance ---@param node string|node The node_id or gui.get_node(node_id) ---@param callback function|nil Button callback ----@param params table|nil Button callback params ----@param anim_node node|nil Button anim node (node, if not provided) +---@param params any|nil Button callback params +---@param anim_node node|string|nil Button anim node (node, if not provided) ---@return druid.button @{Button} component function druid_instance.new_button(self, node, callback, params, anim_node) end @@ -1504,9 +1586,9 @@ function druid_instance.new_checkbox(self, node, callback, click_node, initial_s --- Create @{CheckboxGroup} component ---@param self druid_instance ----@param nodes node[] Array of gui node +---@param nodes (node|string)[] Array of gui node ---@param callback function Checkbox callback ----@param click_nodes node[] Array of trigger nodes, by default equals to nodes +---@param click_nodes (node|string)[]|nil Array of trigger nodes, by default equals to nodes ---@return druid.checkbox_group @{CheckboxGroup} component function druid_instance.new_checkbox_group(self, nodes, callback, click_nodes) end @@ -1543,13 +1625,14 @@ function druid_instance.new_hotkey(self, keys_array, callback, callback_argument ---@param self druid_instance ---@param node string|node The node_id or gui.get_node(node_id) ---@param on_hover_callback function|nil Hover callback +---@param on_mouse_hover_callback function|nil Mouse hover callback ---@return druid.hover @{Hover} component -function druid_instance.new_hover(self, node, on_hover_callback) end +function druid_instance.new_hover(self, node, on_hover_callback, on_mouse_hover_callback) end --- Create @{Input} component ---@param self druid_instance ---@param click_node string|node Button node to enabled input component ----@param text_node string|node Text node what will be changed on user input +---@param text_node string|node|druid.text Text node what will be changed on user input ---@param keyboard_type number|nil Gui keyboard type for input field ---@return druid.input @{Input} component function druid_instance.new_input(self, click_node, text_node, keyboard_type) end @@ -1579,9 +1662,9 @@ function druid_instance.new_progress(self, node, key, init_value) end --- Create @{RadioGroup} component ---@param self druid_instance ----@param nodes node[] Array of gui node +---@param nodes (node|string)[] Array of gui node ---@param callback function Radio callback ----@param click_nodes node[] Array of trigger nodes, by default equals to nodes +---@param click_nodes (node|string)[]|nil Array of trigger nodes, by default equals to nodes ---@return druid.radio_group @{RadioGroup} component function druid_instance.new_radio_group(self, nodes, callback, click_nodes) end @@ -1660,19 +1743,20 @@ function druid_instance.on_message(self, message_id, message, sender) end --- Component `on_remove` function will be invoked, if exist. ---@param self druid_instance ---@param component druid.base_component Component instance +---@return boolean True if component was removed function druid_instance.remove(self, component) end --- Set blacklist components for input processing. --- If blacklist is not empty and component contains in this list, component will be not processed on input step ---@param self druid_instance @{DruidInstance} ----@param blacklist_components table|druid.base_component The array of component to blacklist +---@param blacklist_components table|druid.base_component|nil The array of component to blacklist ---@return self @{DruidInstance} function druid_instance.set_blacklist(self, blacklist_components) end --- Set whitelist components for input processing. --- If whitelist is not empty and component not contains in this list, component will be not processed on input step ---@param self druid_instance ----@param whitelist_components table|druid.base_component The array of component to whitelist +---@param whitelist_components table|druid.base_component|nil The array of component to whitelist ---@return self @{DruidInstance} function druid_instance.set_whitelist(self, whitelist_components) end @@ -1780,10 +1864,18 @@ function helper.insert_with_shift(array, any, index, shift_policy) end ---@return boolean Is mobile function helper.is_mobile() end +--- Check if device is mobile and can support multitouch +---@return boolean Is multitouch supported +function helper.is_multitouch_supported() end + --- Check if device is HTML5 ---@return boolean Is web function helper.is_web() end +--- Check if device is HTML5 mobile +---@return boolean Is web mobile +function helper.is_web_mobile() end + --- Lerp between two values ---@param a number First value ---@param b number Second value @@ -1825,11 +1917,15 @@ function helper.table_to_string(t) end -- Manual Annotations -- +---@class druid.component: druid.base_component + ---@class druid.rich_text.metrics ---@field width number ---@field height number ---@field offset_x number|nil ---@field offset_y number|nil +---@field max_ascent number +---@field max_descent number ---@field node_size vector3|nil @For images only ---@class druid.rich_text.lines_metrics @@ -1846,7 +1942,7 @@ function helper.table_to_string(t) end ---@field scale vector3 ---@field size vector3 ---@field metrics druid.rich_text.metrics ----@field pivot number @ The gui.PIVOT_* constant +---@field pivot userdata @ The gui.PIVOT_* constant ---@field text string ---@field shadow vector4 ---@field outline vector4 @@ -1856,6 +1952,9 @@ function helper.table_to_string(t) end ---@field anchor number ---@field br boolean ---@field nobr boolean +---@field source_text string +---@field image_color vector4 +---@field text_color vector4 ---@class druid.rich_text.image ---@field texture string @@ -1867,6 +1966,7 @@ function helper.table_to_string(t) end ---@field parent node ---@field size number ---@field fonts table +---@field scale vector3 ---@field color vector4 ---@field shadow vector4 ---@field outline vector4 @@ -1874,11 +1974,46 @@ function helper.table_to_string(t) end ---@field image_pixel_grid_snap boolean ---@field combine_words boolean ---@field default_animation string ----@field node_prefab node ---@field text_prefab node +---@field adjust_scale number +---@field default_texture string +---@field is_multiline boolean +---@field text_leading number +---@field font hash +---@field width number +---@field height number ---@class GUITextMetrics ---@field width number ---@field height number ---@field max_ascent number ---@field max_descent number + +---@class utf8 +---@field len fun(s: string):number +---@field sub fun(s: string, start_index: number, length: number) +---@field reverse fun() +---@field char fun() +---@field unicode fun() +---@field gensub fun() +---@field byte fun() +---@field find fun() +---@field match fun(s: string, m: string) +---@field gmatch fun(s: string, m: string) +---@field gsub fun() +---@field dump fun() +---@field format fun() +---@field lower fun() +---@field upper fun() +---@field rep fun() + + +---Add generics to some functions. + +---Create new component. +---@generic T: druid.base_component +---@param self druid_instance +---@param component T Component module +---@param ... any Other component params to pass it to component:init function +---@return T Component instance +function druid_instance.new(self, component, ...) end \ No newline at end of file diff --git a/druid/base/button.lua b/druid/base/button.lua index 5bd10c4..9b09c48 100755 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -123,7 +123,7 @@ -- 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[opt=node] node anim_node +-- @tfield node|nil anim_node Default node ---Custom args for any Button event. Setup in Button constructor -- @tfield any params @@ -240,7 +240,12 @@ local function on_button_release(self) 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 @@ -258,9 +263,9 @@ end -- 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 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) @@ -339,10 +344,7 @@ function Button.on_input(self, action_id, action) return false end - if not self:is_enabled() 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 @@ -365,6 +367,7 @@ function Button.on_input(self, action_id, action) if is_key_trigger then self.hover:set_hover(not action.released) + is_consume = false end if action.pressed then @@ -380,19 +383,19 @@ function Button.on_input(self, action_id, action) on_button_click(self) end) end - return true + return is_consume end -- While hold button, repeat rate pick from input.repeat_interval if action.repeated 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 self.can_action and self.on_long_click:is_exist() then @@ -400,21 +403,23 @@ function Button.on_input(self, action_id, action) 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 @@ -478,7 +483,7 @@ end -- -- This functions calls automatically if you don't disable it in game.project: druid.no_stencil_check -- @tparam Button self @{Button} --- @tparam node|nil zone Gui node +-- @tparam node|string|nil zone Gui node -- @treturn Button Current button instance -- @usage -- button:set_click_zone("stencil_node") diff --git a/druid/base/drag.lua b/druid/base/drag.lua index c2a5072..fd79105 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -22,10 +22,10 @@ --- Event on drag start callback(self, touch) -- @tfield DruidEvent on_drag_start @{DruidEvent} ---- on drag progress callback(self, dx, dy, total_x, total_y) +--- on drag progress callback(self, dx, dy, total_x, total_y, touch) -- @tfield DruidEvent on_drag Event @{DruidEvent} ---- Event on drag end callback(self, total_x, total_y) +--- Event on drag end callback(self, total_x, total_y, touch) -- @tfield DruidEvent on_drag_end @{DruidEvent} --- Is component now touching @@ -175,8 +175,8 @@ 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[opt=false] boolean NO_USE_SCREEN_KOEF If screen aspect ratio affects on drag values +-- @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 @@ -324,7 +324,7 @@ 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 diff --git a/druid/base/hover.lua b/druid/base/hover.lua index f2a2517..f178cf2 100644 --- a/druid/base/hover.lua +++ b/druid/base/hover.lua @@ -5,6 +5,9 @@ -- @within BaseComponent -- @alias druid.hover +--- Hover node +-- @tfield node node + --- On hover callback(self, state, hover_instance) -- @tfield DruidEvent on_hover @{DruidEvent} @@ -25,7 +28,8 @@ local Hover = component.create("hover") -- @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 @@ -91,9 +108,15 @@ end -- @tparam Hover self @{Hover} -- @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, self) + 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 @@ -110,9 +133,15 @@ end -- @tparam Hover self @{Hover} -- @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, self) + 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 @@ -128,7 +157,7 @@ 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 @@ -161,4 +190,31 @@ function Hover.is_enabled(self) 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 diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 7328429..962411a 100755 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -50,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 @@ -123,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] boolean SMALL_CONTENT_SCROLL If true, content node with size less than view node size can be scrolled --- @tfield[opt=0] boolean WHEEL_SCROLL_SPEED The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling --- @tfield[opt=false] boolean WHEEL_SCROLL_INVERTED If true, invert direction for touchpad and mouse wheel scroll --- @tfield[opt=false] boolean 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 @@ -216,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 @@ -255,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 @@ -305,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 @@ -325,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 @@ -338,6 +354,31 @@ 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 @@ -464,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 @@ -493,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 @@ -583,14 +624,14 @@ 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 + 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) @@ -677,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 @@ -692,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 @@ -746,14 +795,14 @@ function Scroll._update_size(self) 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 @@ -788,7 +837,7 @@ 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) end return true diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index ee2903e..e66813c 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -102,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] boolean IS_DYNAMIC_NODE_POSES If true, always center grid content as grid pivot sets --- @tfield[opt=false] boolean 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 @@ -115,7 +115,7 @@ end -- @tparam StaticGrid self @{StaticGrid} -- @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 = {} @@ -171,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) @@ -236,6 +240,23 @@ 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 @@ -337,6 +358,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 @@ -377,6 +399,35 @@ 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:_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 boolean|nil is_instant If true, node position update instantly, otherwise with set_position_function callback diff --git a/druid/base/text.lua b/druid/base/text.lua index a34ffe7..39188f4 100755 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -81,12 +81,18 @@ local const = require("druid.const") local helper = require("druid.helper") local utf8_lua = require("druid.system.utf8") local component = require("druid.component") -local utf8 = utf8 or utf8_lua +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), @@ -98,19 +104,24 @@ end --- Reset initial scale for text local function reset_default_scale(self) - self.scale = self.start_scale + self.scale.x = self.start_scale.x + self.scale.y = self.start_scale.y + self.scale.z = self.start_scale.z gui.set_scale(self.node, self.start_scale) gui.set_size(self.node, self.start_size) end +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) if metrics.width == 0 then @@ -119,15 +130,56 @@ local function update_text_area_size(self) 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 scale_modifier_by_height = math.sqrt(max_height / metrics.height) - scale_modifier = math.min(self.start_scale.y, scale_modifier_by_height) + -- 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 - if metrics.width * scale_modifier > max_width then - scale_modifier = math.min(max_width / metrics.width, self.start_scale.x) + -- #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 @@ -135,12 +187,16 @@ local function update_text_area_size(self) 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, metrics) + self.on_update_text_scale:trigger(self:get_context(), self.scale, metrics) end @@ -155,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 @@ -171,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 = resource.get_text_metrics(font, "1").width - local with_space = resource.get_text_metrics(font, " 1").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) @@ -216,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 --- The @{Text} constructor -- @tparam Text self @{Text} -- @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. --- @tparam[opt=downscale] string adjust_type Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference +-- @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) @@ -251,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 @@ -276,32 +327,60 @@ end --- Calculate text width with font with respect to trailing space -- @tparam Text self @{Text} --- @tparam string|nil 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_name = gui.get_font(self.node) local font = gui.get_font_resource(font_name) - local scale = gui.get_scale(self.node) + local scale = self.last_scale or gui.get_scale(self.node) local linebreak = gui.get_line_break(self.node) - local metrics = resource.get_text_metrics(font, text, { + 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 - for i = #text, 1, -1 do - local c = string.sub(text, i, i) - if c ~= ' ' then + + 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 diff --git a/druid/component.lua b/druid/component.lua index ca6f89e..1bd76c9 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -19,13 +19,12 @@ -- @alias druid.base_component local const = require("druid.const") -local class = require("druid.system.middleclass") local helper = require("druid.helper") -local BaseComponent = class("druid.component") +local BaseComponent = {} local INTERESTS = {} -- Cache interests per component class in runtime -local IS_AUTO_TEMPLATE = not (sys.get_config("druid.no_auto_template") == "1") +local IS_AUTO_TEMPLATE = not (sys.get_config_int("druid.no_auto_template", 0) == 1) -- Component Interests BaseComponent.ON_INPUT = const.ON_INPUT @@ -205,10 +204,22 @@ end --- Get Druid instance for inner component creation. -- @tparam BaseComponent self @{BaseComponent} +-- @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) +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 @@ -336,31 +347,13 @@ 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.create` --- @tparam BaseComponent self @{BaseComponent} --- @tparam string name BaseComponent name --- @tparam number|nil 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.create_uid() - } -end - - --- Print log information if debug mode is enabled -- @tparam BaseComponent self @{BaseComponent} -- @tparam string message @@ -443,21 +436,22 @@ 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 @@ -486,12 +480,24 @@ end -- @tparam number|nil input_priority The input priority. The bigger number processed first -- @local function BaseComponent.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 + 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 diff --git a/druid/const.lua b/druid/const.lua index c9adc29..70667de 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -17,8 +17,13 @@ M.ACTION_MULTITOUCH = hash(sys.get_config_string("druid.input_multitouch", "touc 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.IS_STENCIL_CHECK = not (sys.get_config_string("druid.no_stencil_check") == "1") +M.IS_STENCIL_CHECK = not (sys.get_config_int("druid.no_stencil_check", 0) == 1) M.ON_INPUT = "on_input" diff --git a/druid/custom/pin_knob/pin_knob.gui b/druid/custom/pin_knob/pin_knob.gui deleted file mode 100644 index 6397460..0000000 --- a/druid/custom/pin_knob/pin_knob.gui +++ /dev/null @@ -1,182 +0,0 @@ -script: "" -fonts { - name: "game" - font: "/example/assets/fonts/game.font" -} -textures { - name: "kenney" - texture: "/example/assets/images/kenney.atlas" -} -background_color { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 1.0 - y: 1.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_AUTO -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 2.0 - y: 2.0 - z: 1.0 - w: 1.0 - } - size { - x: 36.0 - y: 36.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/slider_move" - id: "pin" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_AUTO -} -nodes { - position { - x: 0.0 - y: 13.5 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.2 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 17.0 - y: 17.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.101960786 - z: 0.101960786 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/tick" - id: "notch" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "pin" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_AUTO -} -material: "/builtins/materials/gui.material" -adjust_reference: ADJUST_REFERENCE_PARENT -max_nodes: 512 diff --git a/druid/custom/pin_knob/pin_knob.lua b/druid/custom/pin_knob/pin_knob.lua deleted file mode 100644 index 418f6be..0000000 --- a/druid/custom/pin_knob/pin_knob.lua +++ /dev/null @@ -1,123 +0,0 @@ --- Copyright (c) 2022 Maksim Tuprikov . 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 boolean 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 - - ---- The @{PinKnob} constructor --- @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 diff --git a/druid/custom/rich_input/rich_input.lua b/druid/custom/rich_input/rich_input.lua index 68d3560..bffe3fa 100644 --- a/druid/custom/rich_input/rich_input.lua +++ b/druid/custom/rich_input/rich_input.lua @@ -3,7 +3,6 @@ --- 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 @@ -18,13 +17,36 @@ --- On input field text change to empty string callback(self, input_text) -- @tfield node cursor +--- On input field text change to empty string callback(self, input_text) +-- @tfield node cursor_text + +--- On input field text change to empty string callback(self, input_text) +-- @tfield vector3 cursor_position + +--- On input field text change to empty string callback(self, input_text) +-- @tfield druid.text input_text + +--- On input field text change to empty string callback(self, input_text) +-- @tfield druid.drag drag + +--- On input field text change to empty string callback(self, input_text) +-- @tfield druid.text placeholder + +--- On input field text change to empty string callback(self, input_text) +-- @tfield vector3 text_position + --- On input field text change to max length string callback(self, input_text) -- @tfield druid.text placeholder @{Text} --- 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 = { @@ -33,34 +55,140 @@ 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 + + +--- 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 @@ -69,38 +197,111 @@ end -- @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.druid = self:get_druid(template, nodes) self.root = self:get_node(SCHEME.ROOT) - self.input = self.druid:new_input(self:get_node(SCHEME.BUTTON), self:get_node(SCHEME.INPUT)) + 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 --- Set placeholder text -- @tparam RichInput self @{RichInput} --- @tparam string|nil placeholder_text The placeholder text --- @treturn RichInput Current instance +-- @tparam string placeholder_text The placeholder text function RichInput.set_placeholder(self, placeholder_text) self.placeholder:set_to(placeholder_text) return self end ----GSet input field text +--- 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} --- @treturn string Current input text function RichInput.get_text(self) return self.input:get_text() end diff --git a/druid/custom/rich_text/module/rt.lua b/druid/custom/rich_text/module/rt.lua index 8a350ec..8baa48c 100755 --- a/druid/custom/rich_text/module/rt.lua +++ b/druid/custom/rich_text/module/rt.lua @@ -11,6 +11,9 @@ 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 @@ -71,18 +74,18 @@ function M.length(text) end ----@param word rich_text.word ----@param previous_word rich_text.word|nil ----@param settings rich_text.settings ----@return rich_text.metrics +---@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.text_scale.x * settings.adjust_scale - local word_scale_y = word.relative_scale * settings.text_scale.y * settings.adjust_scale + 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, "|") @@ -116,16 +119,17 @@ end ---@param settings druid.rich_text.settings ---@return druid.rich_text.metrics local function get_image_metrics(word, settings) - local node_prefab = settings.node_prefab - gui.play_flipbook(node_prefab, word.image.anim) - local node_size = gui.get_size(node_prefab) + 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.node_scale.x * settings.adjust_scale, - height = node_size.y * word.relative_scale * settings.node_scale.y * settings.adjust_scale, + 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 @@ -136,6 +140,16 @@ end ---@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 @@ -145,14 +159,14 @@ end --- @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 words ---- @return metrics +--- @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 font = gui.get_font(settings.text_prefab) local word_params = { node = nil, -- Autofill on node creation relative_scale = 1, @@ -169,12 +183,10 @@ function M.create(text, settings, style) text_color = gui.get_color(settings.text_prefab), shadow = settings.shadow, outline = settings.outline, - font = font, + font = gui.get_font(settings.text_prefab), -- Image params - ---@type rich_text.word.image + ---@type druid.rich_text.image image = nil, - image_color = gui.get_color(settings.node_prefab), - default_animation = nil, -- Tags br = nil, nobr = nil, @@ -203,8 +215,8 @@ function M._fill_properties(word, metrics, settings) if word.image then -- Image properties - word.scale = gui.get_scale(settings.node_prefab) * word.relative_scale * settings.adjust_scale - word.pivot = gui.get_pivot(settings.node_prefab) + 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 @@ -213,8 +225,8 @@ function M._fill_properties(word, metrics, settings) end else -- Text properties - word.scale = gui.get_scale(settings.text_prefab) * word.relative_scale * settings.adjust_scale - word.pivot = gui.get_pivot(settings.text_prefab) + 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 @@ -234,8 +246,8 @@ function M._split_on_lines(words, settings) repeat local word = words[i] - if word.image then - word.default_animation = settings.default_animation + if word == nil then + break end -- Reset texts to start measure again @@ -305,9 +317,9 @@ function M._split_on_lines(words, settings) end ----@param lines rich_text.word[][] ----@param settings rich_text.settings ----@return rich_text.lines_metrics +---@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 @@ -352,9 +364,9 @@ function M._position_lines(lines, settings) end ----@param lines rich_text.word[][] ----@param settings rich_text.settings ----@return rich_text.lines_metrics +---@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 @@ -386,7 +398,7 @@ function M._get_lines_metrics(lines, settings) } end - ---@type rich_text.lines_metrics + ---@type druid.rich_text.lines_metrics local lines_metrics = { text_width = text_width, text_height = text_height, @@ -397,8 +409,8 @@ function M._get_lines_metrics(lines, settings) end ----@param lines rich_text.word[][] ----@param settings rich_text.settings +---@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] @@ -406,10 +418,11 @@ function M._update_nodes(lines, settings) local word = line[word_index] local node if word.image then - node = word.node or gui.clone(settings.node_prefab) + node = word.node or gui.new_box_node(VECTOR_ZERO, word.size) gui.set_size_mode(node, gui.SIZE_MODE_MANUAL) - gui.play_flipbook(node, hash(word.image.anim or word.default_animation)) - gui.set_color(node, word.color or word.image_color) + 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) @@ -421,6 +434,7 @@ function M._update_nodes(lines, settings) 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) @@ -429,10 +443,10 @@ function M._update_nodes(lines, settings) end ----@param words rich_text.word[] ----@param settings rich_text.settings +---@param words druid.rich_text.word[] +---@param settings druid.rich_text.settings ---@param scale number ----@return rich_text.lines_metrics +---@return druid.rich_text.lines_metrics function M.set_text_scale(words, settings, scale) settings.adjust_scale = scale @@ -463,7 +477,7 @@ function M.adjust_to_area(words, settings, lines_metrics, style) 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, 1) + 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) @@ -496,15 +510,15 @@ function M.adjust_to_area(words, settings, lines_metrics, style) end ----@return boolean @If we fit into area size +---@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 rich_text.word[][] ----@param settings rich_text.settings +---@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) diff --git a/druid/custom/rich_text/module/rt_parse.lua b/druid/custom/rich_text/module/rt_parse.lua index 66c6a1d..53d42a6 100755 --- a/druid/custom/rich_text/module/rt_parse.lua +++ b/druid/custom/rich_text/module/rt_parse.lua @@ -117,6 +117,10 @@ function M.parse(text, default_settings, style) assert(default_settings) text = text:gsub("&zwsp;", "\226\128\139") + + -- Replace all \n with
    to make it easier to split the text + text = text:gsub("\n", "
    ") + local all_words = {} local open_tags = {} @@ -145,7 +149,7 @@ function M.parse(text, default_settings, style) end -- parse the tag, split into name and optional parameters - local endtag, name, params, empty = tag:match("<(/?)(%a+)=?(%S-)(/?)>") + local endtag, name, params, empty = tag:match("<(/?)([%a_]+)=?(%S-)(/?)>") local is_endtag = endtag == "/" local is_empty = empty == "/" diff --git a/druid/custom/rich_text/module/rt_tags.lua b/druid/custom/rich_text/module/rt_tags.lua index 0805822..058131e 100644 --- a/druid/custom/rich_text/module/rt_tags.lua +++ b/druid/custom/rich_text/module/rt_tags.lua @@ -93,11 +93,6 @@ M.register("img", function(params, settings) width, params = split(params, ",") height = split(params, ",") local texture, anim = split(texture_and_anim, ":") - if not anim then - anim = texture - texture = nil - end - width = width and tonumber(width) height = height and tonumber(height) @@ -105,7 +100,7 @@ M.register("img", function(params, settings) texture = texture, anim = anim, width = width, - height = height + height = height or width, } end) diff --git a/druid/custom/rich_text/rich_text.gui b/druid/custom/rich_text/rich_text.gui deleted file mode 100644 index e37f9ea..0000000 --- a/druid/custom/rich_text/rich_text.gui +++ /dev/null @@ -1,199 +0,0 @@ -script: "" -fonts { - name: "game" - font: "/example/assets/fonts/game.font" -} -textures { - name: "items" - texture: "/example/assets/images/kenney.atlas" -} -background_color { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -200.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich text" - font: "game" - id: "text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: false - parent: "root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 21.0 - y: 20.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -material: "/builtins/materials/gui.material" -adjust_reference: ADJUST_REFERENCE_PARENT -max_nodes: 512 diff --git a/druid/custom/rich_text/rich_text.lua b/druid/custom/rich_text/rich_text.lua index 6f0b0cd..81ac7ac 100644 --- a/druid/custom/rich_text/rich_text.lua +++ b/druid/custom/rich_text/rich_text.lua @@ -6,31 +6,7 @@ -- This custom component is inspired by defold-richtext by britzl. -- It uses a similar syntax for tags but currently supports fewer tags. -- --- All parameters for the Rich Text component are adjusted in the GUI scene. --- --- This component uses GUI component template. (/druid/custom/rich_text/rich_text.gui). --- --- You able to customize it or make your own with the next node scructure: --- --- root --- --- - text_prefab --- --- - icon_prefab --- --- # Rich Text Setup # --- --- • Root node size: Set the maximum width and height of the text. --- --- • Root anchor: Define the alignment of the Rich Text inside the root node size area. --- --- • Text prefab: Configure all default text parameters for the text node. --- --- • Text prefab anchor: Set the anchor for each text node (adjust this only if animating text). --- --- • Icon prefab: Configure all default node parameters for the icon node. --- --- • Icon prefab anchor: Set the anchor for each icon node (adjust this only if animating the icon). +-- Create Rich Text on your GUI Text Node. All properties of the text node will be used as default for the text. -- -- # Notes # -- @@ -58,7 +34,6 @@ -- outline: vector4, -- font: string, -- image: druid.rich_text.image, --- default_animation: string, -- br: boolean, -- nobr: boolean, -- } @@ -90,6 +65,12 @@ --- 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") @@ -97,37 +78,28 @@ local rich_text = require("druid.custom.rich_text.module.rt") local RichText = component.create("rich_text") -local SCHEME = { - ROOT = "root", - TEXT_PREFAB = "text_prefab", - ICON_PREFAB = "icon_prefab" -} - --- The @{RichText} constructor -- @tparam RichText self @{RichText} --- @tparam string template The Rich Text template name --- @tparam table nodes The node table, if prefab was copied by gui.clone_tree() -function RichText.init(self, template, nodes) - self:set_template(template) - self:set_nodes(nodes) - - self.root = self:get_node(SCHEME.ROOT) - self.druid = self:get_druid() - - self.text_prefab = self:get_node(SCHEME.TEXT_PREFAB) - self.icon_prefab = self:get_node(SCHEME.ICON_PREFAB) - - gui.set_enabled(self.text_prefab, false) - gui.set_enabled(self.icon_prefab, false) +-- @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) - gui.set_enabled(self.text_prefab, false) - gui.set_enabled(self.icon_prefab, false) if self._last_value then self:set_text(self._last_value) end @@ -138,9 +110,9 @@ end -- You can override this component styles params in Druid styles table -- or create your own style -- @table style --- @tfield[opt={}] table COLORS Rich Text color aliases --- @tfield[opt=20] number ADJUST_STEPS Amount steps of attemps text adjust by height --- @tfield[opt=0.02] number ADJUST_SCALE_DELTA Scale step on each height adjust step +-- @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 {} @@ -151,7 +123,7 @@ end --- Set text for Rich Text -- @tparam RichText self @{RichText} --- @tparam string text The text to set +-- @tparam string|nil text The text to set -- @treturn druid.rich_text.word[] words -- @treturn druid.rich_text.lines_metrics line_metrics -- @usage @@ -198,6 +170,7 @@ end -- -- function RichText.set_text(self, text) + text = text or "" self:clear() self._last_value = text @@ -211,6 +184,14 @@ function RichText.set_text(self, text) 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() self:clear() end @@ -227,9 +208,10 @@ 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(tag) +function RichText.tagged(self, tag) if not self._words then return end @@ -238,6 +220,15 @@ function RichText:tagged(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() @@ -254,29 +245,33 @@ end function RichText:_create_settings() local root_size = gui.get_size(self.root) + local scale = gui.get_scale(self.root) + + 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, - node_prefab = self.icon_prefab, + pivot = gui.get_pivot(self.root), -- Text Settings - shadow = gui.get_shadow(self.text_prefab), - outline = gui.get_outline(self.text_prefab), - text_scale = gui.get_scale(self.text_prefab), - text_leading = gui.get_leading(self.text_prefab), - is_multiline = gui.get_line_break(self.text_prefab), + 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 - node_scale = gui.get_scale(self.icon_prefab), - image_scale = gui.get_scale(self.icon_prefab), - default_animation = gui.get_flipbook(self.icon_prefab), } end diff --git a/druid/druid.lua b/druid/druid.lua index ad5e766..1d247f2 100644 --- a/druid/druid.lua +++ b/druid/druid.lua @@ -107,7 +107,9 @@ function M.new(context, style) 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 diff --git a/druid/editor_scripts/component.lua_template b/druid/editor_scripts/component.lua_template index d50db11..f33bae3 100644 --- a/druid/editor_scripts/component.lua_template +++ b/druid/editor_scripts/component.lua_template @@ -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 -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 diff --git a/druid/editor_scripts/create_druid_component.py b/druid/editor_scripts/create_druid_component.py index 054bfa3..24d1203 100644 --- a/druid/editor_scripts/create_druid_component.py +++ b/druid/editor_scripts/create_druid_component.py @@ -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) diff --git a/druid/editor_scripts/druid.editor_script b/druid/editor_scripts/druid.editor_script index 6534c1d..7903c00 100644 --- a/druid/editor_scripts/druid.editor_script +++ b/druid/editor_scripts/druid.editor_script @@ -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"}, diff --git a/druid/editor_scripts/run_python_script_on_gui.sh b/druid/editor_scripts/run_python_script_on_gui.sh index f76c34d..5b0e2b9 100644 --- a/druid/editor_scripts/run_python_script_on_gui.sh +++ b/druid/editor_scripts/run_python_script_on_gui.sh @@ -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 diff --git a/druid/event.lua b/druid/event.lua index 208620c..ef79c86 100644 --- a/druid/event.lua +++ b/druid/event.lua @@ -8,31 +8,62 @@ -- @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 --- DruidEvent constructor --- @tparam DruidEvent self @{DruidEvent} --- @tparam function|nil initial_callback Subscribe the callback on new event, if callback exist +-- @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(initial_callback) -function DruidEvent.initialize(self, initial_callback) - self._callbacks = nil -- initialize later +-- 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 any|nil context Additional context as first param to callback call, usually it's self +-- @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!") @@ -40,41 +71,39 @@ end -- ... -- local button = self.druid:new_button("button", callback) -- button.on_long_click:subscribe(on_long_callback, self) -function DruidEvent.subscribe(self, callback, context) +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 any|nil context Additional context as first param to callback call +-- @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 DruidEvent.unsubscribe(self, callback, context) - if not self._callbacks then - return +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 @@ -83,11 +112,18 @@ end -- @treturn boolean True if event have handlers -- @usage -- local is_long_click_handler_exists = button.on_long_click:is_exist() -function DruidEvent.is_exist(self) - if not self._callbacks then - return false - end - return #self._callbacks > 0 +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 @@ -95,8 +131,10 @@ end -- @tparam DruidEvent self @{DruidEvent} -- @usage -- button.on_long_click:clear() -function DruidEvent.clear(self) - self._callbacks = nil +function M.clear(self) + for index = #self, 1, -1 do + self[index] = nil + end end @@ -108,19 +146,60 @@ end -- ... -- local event = Event() -- event:trigger("Param1", "Param2") -function DruidEvent.trigger(self, ...) - if not self._callbacks then - return false +function M.trigger(self, ...) + if #self == 0 then + return end - for _, 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, +}) diff --git a/druid/extended/checkbox.lua b/druid/extended/checkbox.lua index 2c629e8..dd13921 100755 --- a/druid/extended/checkbox.lua +++ b/druid/extended/checkbox.lua @@ -14,7 +14,7 @@ -- @tfield node node --- Button trigger node --- @tfield[opt=node] node click_node +-- @tfield node|nil click_node --- Button component from click_node -- @tfield Button button @{Button} @@ -50,8 +50,8 @@ end -- @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 +-- @tparam node|nil click_node Trigger node, by default equals to node. Default: node +-- @tparam boolean|nil 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) diff --git a/druid/extended/checkbox_group.lua b/druid/extended/checkbox_group.lua index 2dd66ba..d59adc3 100644 --- a/druid/extended/checkbox_group.lua +++ b/druid/extended/checkbox_group.lua @@ -25,7 +25,7 @@ local CheckboxGroup = component.create("checkbox_group") -- @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 +-- @tparam node[]|nil 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 = {} diff --git a/druid/extended/data_list.lua b/druid/extended/data_list.lua index f3e5be1..81bf959 100644 --- a/druid/extended/data_list.lua +++ b/druid/extended/data_list.lua @@ -13,17 +13,17 @@ -- @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} @@ -46,16 +46,14 @@ local DataList = component.create("data_list") --- 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 @@ -63,26 +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.on_element_add = Event() self.on_element_remove = Event() - - self:set_data() 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 @@ -92,7 +98,6 @@ 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 @@ -110,42 +115,35 @@ 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 helper.insert_with_shift(self._data, data, index, shift_policy) - self:_update_data_info() - self:_check_elements() + 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) - --self:_refresh() - helper.remove_with_shift(self._data, index, shift_policy) - self:_update_data_info() + self:_refresh() 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 helper.remove_with_shift(self._data, index, shift_policy) - self:_update_data_info() self:_refresh() end end @@ -155,32 +153,10 @@ end -- @tparam DataList self @{DataList} function DataList.clear(self) self._data = {} - self:_update_data_info() self:_refresh() 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 @@ -227,17 +203,12 @@ end -- @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 @@ -246,137 +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.on_element_add:trigger(self:get_context(), index, node, instance) + -- 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 - local instance = self._data_visual[index].component - if instance then - self.druid:remove(instance) + 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.on_element_remove:trigger(self:get_context(), index) + self._data_visual[index] = nil end + --- 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 - - 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 = 0 - self._data_last_index = 0 end end diff --git a/druid/extended/dynamic_grid.lua b/druid/extended/dynamic_grid.lua index 8a91af8..c4f0c76 100644 --- a/druid/extended/dynamic_grid.lua +++ b/druid/extended/dynamic_grid.lua @@ -101,7 +101,7 @@ end -- @tparam number index The grid element index -- @tparam node node The node to be placed -- @tparam number|nil origin_index Index of nearby node --- @treturn vector3 Node position +-- @treturn vector3 node position function DynamicGrid.get_pos(self, index, node, origin_index) local origin_node = self.nodes[origin_index] diff --git a/druid/extended/hotkey.lua b/druid/extended/hotkey.lua index 1e867a8..41507bd 100644 --- a/druid/extended/hotkey.lua +++ b/druid/extended/hotkey.lua @@ -7,14 +7,17 @@ -- @within BaseComponent -- @alias druid.hotkey ---- On change state callback(self, state) --- @tfield DruidEvent on_change_state @{DruidEvent} +--- 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[opt=node] node click_node +-- @tfield node|nil click_node --- Button component from click_node -- @tfield Button button @{Button} @@ -24,7 +27,6 @@ local helper = require("druid.helper") local component = require("druid.component") local Event = require("druid.event") -local const = require("druid.const") local Hotkey = component.create("hotkey") diff --git a/druid/extended/input.lua b/druid/extended/input.lua index 89c5fa0..db608e1 100755 --- a/druid/extended/input.lua +++ b/druid/extended/input.lua @@ -9,10 +9,10 @@ -- @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) @@ -24,12 +24,42 @@ --- 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} @@ -52,12 +82,21 @@ local Event = require("druid.event") local const = require("druid.const") +local helper = require("druid.helper") local component = require("druid.component") 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 @@ -87,31 +126,22 @@ end -- You can override this component styles params in druid styles table -- or create your own style -- @table style --- @tfield[opt=false] boolean 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] boolean IS_UNSELECT_ON_RESELECT If true, call unselect on select selected input --- @tfield[opt=false] boolean NO_CONSUME_INPUT_WHILE_SELECTED If true, will not consume input while input is selected. It's allow to interact with other components while input is selected (text input still captured) +-- @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 = {} self.style.IS_LONGTAP_ERASE = style.IS_LONGTAP_ERASE or false self.style.MASK_DEFAULT_CHAR = style.MASK_DEFAULT_CHAR or "*" self.style.IS_UNSELECT_ON_RESELECT = style.IS_UNSELECT_ON_RESELECT or false - self.style.NO_CONSUME_INPUT_WHILE_SELECTED = style.NO_CONSUME_INPUT_WHILE_SELECTED or false self.style.on_select = style.on_select or function(_, button_node) end self.style.on_unselect = style.on_unselect or function(_, button_node) end self.style.on_input_wrong = style.on_input_wrong or function(_, button_node) end - - self.style.button_style = style.button_style or { - LONGTAP_TIME = 0.4, - AUTOHOLD_TRIGGER = 0.8, - DOUBLETAP_TIME = 0.4 - } end @@ -121,7 +151,7 @@ end -- @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 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) == "table" then self.text = text_node @@ -139,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 @@ -146,10 +179,14 @@ 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 @@ -160,29 +197,36 @@ function Input.init(self, click_node, text_node, keyboard_type) 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) @@ -196,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 @@ -217,14 +279,23 @@ 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_consume_input = not self.style.NO_CONSUME_INPUT_WHILE_SELECTED and self.is_selected - return is_consume_input + 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 @@ -234,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 @@ -242,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 @@ -297,8 +396,10 @@ function Input.select(self) 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 @@ -313,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 @@ -330,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 @@ -359,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 diff --git a/druid/extended/lang_text.lua b/druid/extended/lang_text.lua index 6e2a699..6d38f83 100755 --- a/druid/extended/lang_text.lua +++ b/druid/extended/lang_text.lua @@ -38,8 +38,8 @@ local LangText = component.create("lang_text") --- The @{LangText} constructor -- @tparam LangText self @{LangText} -- @tparam string|node node The node_id or gui.get_node(node_id) --- @tparam[opt=node_text] string locale_id Default locale id or text from node as default --- @tparam[opt=downscale] string adjust_type Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference +-- @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, adjust_type) diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index ff24fef..2380d58 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -1,4 +1,4 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license +-- Copyright (c) 2024 Maksim Tuprikov . This code is licensed under MIT license --- Layout management on node -- @@ -13,205 +13,411 @@ --- Current layout mode -- @tfield string mode ----On window resize callback(self, new_size) --- @tfield DruidEvent on_size_changed @{DruidEvent} - --- - -local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Event = require("druid.event") +-- @class druid.layout.row_data +-- @tfield width number +-- @tfield height number +-- @tfield count number -local Layout = component.create("layout") +-- @class druid.layout.rows_data +-- @tfield total_width number +-- @tfield total_height number +-- @tfield nodes_width table +-- @tfield nodes_height table +-- @tfield rows druid.layout.row_data[]> +-- @class druid.layout: druid.base_component +local M = component.create("layout") ---- The @{Layout} constructor +-- The @{Layout} constructor -- @tparam Layout self @{Layout} -- @tparam node node Gui node --- @tparam string mode The layout mode (from const.LAYOUT_MODE) +-- @tparam string layout_type The layout mode (from const.LAYOUT_MODE) -- @tparam function|nil on_size_changed_callback The callback on window resize -function Layout.init(self, node, mode, on_size_changed_callback) +function M.init(self, node, layout_type) self.node = self:get_node(node) - self._min_size = nil - self._max_size = nil - self._current_size = vmath.vector3(0) - self._inited = false - self._max_gui_upscale = nil - self._fit_node = nil - - self._anchors = {} - - self.mode = mode or const.LAYOUT_MODE.FIT - - self.on_size_changed = Event(on_size_changed_callback) + 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 Layout.on_late_init(self) - self._inited = true - self.origin_size = self.origin_size or gui.get_size(self.node) - self.fit_size = self.fit_size or vmath.vector3(self.origin_size) - self.pivot = helper.get_pivot_offset(gui.get_pivot(self.node)) - self.origin_position = gui.get_position(self.node) - self.position = vmath.vector3(self.origin_position) - gui.set_size_mode(self.node, gui.SIZE_MODE_MANUAL) - gui.set_adjust_mode(self.node, gui.ADJUST_FIT) - self:on_window_resized() -end - - -function Layout.on_window_resized(self) - if not self._inited then +function M:update() + if not self.is_dirty then return end - local x_koef, y_koef = helper.get_screen_aspect_koef() - - local revert_scale = 1 - if self._max_gui_upscale then - revert_scale = self._max_gui_upscale / helper.get_gui_scale() - revert_scale = math.min(revert_scale, 1) - end - gui.set_scale(self.node, vmath.vector3(revert_scale)) - - if self._fit_node then - self.fit_size = gui.get_size(self._fit_node) - self.fit_size.x = self.fit_size.x / x_koef - self.fit_size.y = self.fit_size.y / y_koef - end - - x_koef = self.fit_size.x / self.origin_size.x * x_koef - y_koef = self.fit_size.y / self.origin_size.y * y_koef - - local new_size = vmath.vector3(self.origin_size) - - if self.mode == const.LAYOUT_MODE.STRETCH then - new_size.x = new_size.x * x_koef / revert_scale - new_size.y = new_size.y * y_koef / revert_scale - end - - if self.mode == const.LAYOUT_MODE.STRETCH_X then - new_size.x = new_size.x * x_koef / revert_scale - end - - if self.mode == const.LAYOUT_MODE.STRETCH_Y then - new_size.y = new_size.y * y_koef / revert_scale - end - - -- Fit to the stretched container (node size or other defined) - if self.mode == const.LAYOUT_MODE.ZOOM_MIN then - new_size = new_size * math.min(x_koef, y_koef) - end - if self.mode == const.LAYOUT_MODE.ZOOM_MAX then - new_size = new_size * math.max(x_koef, y_koef) - end - - if self._min_size then - new_size.x = math.max(new_size.x, self._min_size.x) - new_size.y = math.max(new_size.y, self._min_size.y) - end - if self._max_size then - new_size.x = math.min(new_size.x, self._max_size.x) - new_size.y = math.min(new_size.y, self._max_size.y) - end - self._current_size = new_size - gui.set_size(self.node, new_size) - - self.position.x = self.origin_position.x + self.origin_position.x * (x_koef - 1) - self.position.y = self.origin_position.y + self.origin_position.y * (y_koef - 1) - gui.set_position(self.node, self.position) - - self.on_size_changed:trigger(self:get_context(), new_size) + self:refresh_layout() end ---- Set minimal size of layout node -- @tparam Layout self @{Layout} --- @tparam vector3 min_size --- @treturn Layout @{Layout} -function Layout.set_min_size(self, min_size) - self._min_size = min_size +-- @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 ---- Set maximum size of layout node -- @tparam Layout self @{Layout} --- @tparam vector3 max_size --- @treturn Layout @{Layout} -function Layout.set_max_size(self, max_size) - self._max_size = max_size +-- @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 ---- Set new origin position of layout node. You should apply this on node movement -- @tparam Layout self @{Layout} --- @tparam vector3 new_origin_position --- @treturn Layout @{Layout} -function Layout.set_origin_position(self, new_origin_position) - self.origin_position = new_origin_position or self.origin_position - self:on_window_resized() +-- @treturn druid.layout @{Layout} +function M.set_dirty(self) + self.is_dirty = true + return self end ---- Set new origin size of layout node. You should apply this on node manual size change -- @tparam Layout self @{Layout} --- @tparam vector3 new_origin_size --- @treturn Layout @{Layout} -function Layout.set_origin_size(self, new_origin_size) - self.origin_size = new_origin_size or self.origin_size - self:on_window_resized() +-- @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 ---- Set max gui upscale for FIT adjust mode (or side). It happens on bigger render gui screen -- @tparam Layout self @{Layout} --- @tparam number max_gui_upscale --- @treturn Layout @{Layout} -function Layout.set_max_gui_upscale(self, max_gui_upscale) - self._max_gui_upscale = max_gui_upscale - self:on_window_resized() -end +-- @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 - ---- Set size for layout node to fit inside it --- @tparam Layout self @{Layout} --- @tparam vector3 target_size --- @treturn Layout @{Layout} -function Layout.fit_into_size(self, target_size) - self.fit_size = target_size - self:on_window_resized() return self end ---- Set node for layout node to fit inside it. Pass nil to reset -- @tparam Layout self @{Layout} --- @tparam node|nil node --- @treturn Layout @{Layout} -function Layout.fit_into_node(self, node) - self._fit_node = node - self:on_window_resized() +-- @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 ---- Set current size for layout node to fit inside it -- @tparam Layout self @{Layout} --- @treturn Layout @{Layout} -function Layout.fit_into_window(self) - return self:fit_into_size(vmath.vector3( - gui.get_width(), - gui.get_height(), - 0)) +-- @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 -return Layout +-- @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 diff --git a/druid/extended/progress.lua b/druid/extended/progress.lua index b5fb749..163b017 100644 --- a/druid/extended/progress.lua +++ b/druid/extended/progress.lua @@ -76,15 +76,29 @@ end local function set_bar_to(self, set_to, is_silent) local prev_value = self.last_value + local other_side = self.key == const.SIDE.X and const.SIDE.Y or const.SIDE.X self.last_value = set_to - local total_width = set_to * self.max_size + local total_width = set_to * self.max_size[self.key] - local scale = math.min(total_width / self.slice_size, 1) - local size = math.max(total_width, self.slice_size) + local scale = 1 + if self.slice_size[self.key] > 0 then + scale = math.min(total_width / self.slice_size[self.key], 1) + end + local size = math.max(total_width, self.slice_size[self.key]) + + do -- Scale other side + -- Decrease other side of progress bar to match the oppotize slice_size + local minimal_size = self.size[other_side] - self.slice_size[other_side] + local maximum_size = self.size[other_side] + local scale_diff = (maximum_size - minimal_size) / maximum_size + local other_scale = 1 - (scale_diff * (1 - scale)) + self.scale[other_side] = other_scale + end self.scale[self.key] = scale gui.set_scale(self.node, self.scale) + self.size[self.key] = size gui.set_size(self.node, self.size) @@ -101,8 +115,8 @@ end -- You can override this component styles params in druid styles table -- or create your own style -- @table style --- @tfield[opt=5] number SPEED Progress bas fill rate. More -> faster --- @tfield[opt=0.005] number MIN_DELTA Minimum step to fill progress bar +-- @tfield number|nil SPEED Progress bas fill rate. More -> faster. Default: 5 +-- @tfield number|nil MIN_DELTA Minimum step to fill progress bar. Default: 0.005 function Progress.on_style_change(self, style) self.style = {} self.style.SPEED = style.SPEED or 5 @@ -114,7 +128,7 @@ end -- @tparam Progress self @{Progress} -- @tparam string|node node Node name or GUI Node itself. -- @tparam string key Progress bar direction: const.SIDE.X or const.SIDE.Y --- @tparam[opt=1] number init_value Initial value of progress bar +-- @tparam number|nil init_value Initial value of progress bar. Default: 1 function Progress.init(self, node, key, init_value) assert(key == const.SIDE.X or const.SIDE.Y, "Progress bar key should be 'x' or 'y'") @@ -125,15 +139,15 @@ function Progress.init(self, node, key, init_value) self.node = self:get_node(node) self.scale = gui.get_scale(self.node) self.size = gui.get_size(self.node) - self.max_size = self.size[self.key] + self.max_size = gui.get_size(self.node) self.slice = gui.get_slice9(self.node) self.last_value = self._init_value - if self.key == const.SIDE.X then - self.slice_size = self.slice.x + self.slice.z - else - self.slice_size = self.slice.y + self.slice.w - end + self.slice_size = vmath.vector3( + self.slice.x + self.slice.z, + self.slice.y + self.slice.w, + 0 + ) self.on_change = Event() @@ -146,6 +160,12 @@ function Progress.on_layout_change(self) end +function Progress.on_remove(self) + -- Return default size + gui.set_size(self.node, self.max_size) +end + + function Progress.update(self, dt) if self.target then local prev_value = self.last_value @@ -231,7 +251,7 @@ end -- @tparam vector3 max_size The new node maximum (full) size -- @treturn Progress @{Progress} function Progress.set_max_size(self, max_size) - self.max_size = max_size[self.key] + self.max_size[self.key] = max_size[self.key] self:set_to(self.last_value) return self end diff --git a/druid/extended/radio_group.lua b/druid/extended/radio_group.lua index 8321c3f..51dbe6b 100644 --- a/druid/extended/radio_group.lua +++ b/druid/extended/radio_group.lua @@ -34,7 +34,7 @@ end -- @tparam RadioGroup self @{RadioGroup} -- @tparam node[] nodes Array of gui node -- @tparam function callback Radio callback --- @tparam[opt=node] node[] click_nodes Array of trigger nodes, by default equals to nodes +-- @tparam node[]|nil click_nodes Array of trigger nodes, by default equals to nodes. Default - nodes function RadioGroup.init(self, nodes, callback, click_nodes) self.druid = self:get_druid() self.checkboxes = {} diff --git a/druid/extended/slider.lua b/druid/extended/slider.lua index 05e9453..7af97d3 100644 --- a/druid/extended/slider.lua +++ b/druid/extended/slider.lua @@ -26,7 +26,7 @@ -- @tfield vector3 end_pos --- Length between start and end position --- @tfield number dist +-- @tfield vector3 dist --- Current drag state -- @tfield boolean is_drag @@ -68,6 +68,7 @@ function Slider.init(self, node, end_pos, callback) self.pos = gui.get_position(self.node) self.target_pos = vmath.vector3(self.pos) self.end_pos = end_pos + self._is_enabled = true self.dist = self.end_pos - self.start_pos self.is_drag = false @@ -85,6 +86,12 @@ function Slider.on_layout_change(self) end +function Slider.on_remove(self) + -- Return pin to start position + gui.set_position(self.node, self.start_pos) +end + + function Slider.on_window_resized(self) local x_koef, y_koef = helper.get_screen_aspect_koef() self._x_koef = x_koef @@ -98,6 +105,10 @@ function Slider.on_input(self, action_id, action) return false end + if not self._is_enabled or not gui.is_enabled(self.node, true) 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) @@ -132,14 +143,16 @@ function Slider.on_input(self, action_id, action) if prev_x ~= self.target_pos.x or prev_y ~= self.target_pos.y then local prev_value = self.value - if self.dist.x > 0 then + if math.abs(self.dist.x) > 0 then self.value = (self.target_pos.x - self.start_pos.x) / self.dist.x end - if self.dist.y > 0 then + if math.abs(self.dist.y) > 0 then self.value = (self.target_pos.y - self.start_pos.y) / self.dist.y end + self.value = math.abs(self.value) + if self.steps then local closest_dist = 1000 local closest = nil @@ -202,7 +215,7 @@ end -- move at this position and node drag will start. -- This function require the Defold version 1.3.0+ -- @tparam Slider self @{Slider} --- @tparam node input_node +-- @tparam node|string|nil input_node -- @treturn Slider @{Slider} function Slider.set_input_node(self, input_node) self._input_node = self:get_node(input_node) @@ -210,4 +223,20 @@ function Slider.set_input_node(self, input_node) end +--- Set Slider input enabled or disabled +-- @tparam Slider self @{Slider} +-- @tparam boolean is_enabled +function Slider.set_enabled(self, is_enabled) + self._is_enabled = is_enabled +end + + +--- Check if Slider component is enabled +-- @tparam Slider self @{Slider} +-- @treturn boolean +function Slider.is_enabled(self) + return self._is_enabled +end + + return Slider diff --git a/druid/extended/swipe.lua b/druid/extended/swipe.lua index 264805b..110d9f4 100644 --- a/druid/extended/swipe.lua +++ b/druid/extended/swipe.lua @@ -74,9 +74,9 @@ end -- You can override this component styles params in druid styles table -- or create your own style -- @table style --- @tfield[opt=0.4] number SWIPE_TIME Maximum time for swipe trigger --- @tfield[opt=50] number SWIPE_THRESHOLD Minimum distance for swipe trigger --- @tfield[opt=false] boolean SWIPE_TRIGGER_ON_MOVE If true, trigger on swipe moving, not only release action +-- @tfield number|nil SWIPE_TIME Maximum time for swipe trigger. Default: 0.4 +-- @tfield number|nil SWIPE_THRESHOLD Minimum distance for swipe trigger. Default: 50 +-- @tfield boolean|nil SWIPE_TRIGGER_ON_MOVE If true, trigger on swipe moving, not only release action. Default: false function Swipe.on_style_change(self, style) self.style = {} self.style.SWIPE_TIME = style.SWIPE_TIME or 0.4 @@ -150,7 +150,7 @@ end --- Strict swipe click area. Useful for -- restrict events outside stencil node -- @tparam Swipe self @{Swipe} --- @tparam node zone Gui node +-- @tparam node|string|nil zone Gui node function Swipe.set_click_zone(self, zone) self.click_zone = self:get_node(zone) end diff --git a/druid/extended/timer.lua b/druid/extended/timer.lua index beb2af5..235f4be 100644 --- a/druid/extended/timer.lua +++ b/druid/extended/timer.lua @@ -47,24 +47,26 @@ end --- The @{Timer} constructor -- @tparam Timer self @{Timer} -- @tparam node node Gui text node --- @tparam number seconds_from Start timer value in seconds +-- @tparam number|nil seconds_from Start timer value in seconds -- @tparam number|nil seconds_to End timer value in seconds -- @tparam function|nil callback Function on timer end function Timer.init(self, node, seconds_from, seconds_to, callback) self.node = self:get_node(node) - seconds_from = math.max(seconds_from, 0) seconds_to = math.max(seconds_to or 0, 0) self.on_tick = Event() self.on_set_enabled = Event() self.on_timer_end = Event(callback) - self:set_to(seconds_from) - self:set_interval(seconds_from, seconds_to) + if seconds_from then + seconds_from = math.max(seconds_from, 0) + self:set_to(seconds_from) + self:set_interval(seconds_from, seconds_to) - if seconds_to - seconds_from == 0 then - self:set_state(false) - self.on_timer_end:trigger(self:get_context(), self) + if seconds_to - seconds_from == 0 then + self:set_state(false) + self.on_timer_end:trigger(self:get_context(), self) + end end return self diff --git a/druid/helper.lua b/druid/helper.lua index 1838174..827e9cf 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -10,12 +10,15 @@ local const = require("druid.const") local M = {} +local POSITION_X = hash("position.x") +local SCALE_X = hash("scale.x") +local SIZE_X = hash("size.x") local function get_text_width(text_node) if text_node then local text_metrics = M.get_text_metrics_from_node(text_node) - local text_scale = gui.get_scale(text_node).x + local text_scale = gui.get(text_node, SCALE_X) return text_metrics.width * text_scale end @@ -25,8 +28,7 @@ end local function get_icon_width(icon_node) if icon_node then - local icon_scale_x = gui.get_scale(icon_node).x - return gui.get_size(icon_node).x * icon_scale_x -- icon width + return gui.get(icon_node, SIZE_X) * gui.get(icon_node, SCALE_X) -- icon width end return 0 @@ -97,13 +99,12 @@ function M.centrate_nodes(margin, ...) for i = 1, count do local node = select(i, ...) local node_width = node_widths[i] - local pos = gui.get_position(node) pos_x = pos_x + node_width/2 -- made offset for single item local pivot_offset = M.get_pivot_offset(gui.get_pivot(node)) - pos.x = pos_x - width/2 + pivot_offset.x * node_width -- centrate node - gui.set_position(node, pos) + local new_pos_x = pos_x - width/2 + pivot_offset.x * node_width -- centrate node + gui.set(node, POSITION_X, new_pos_x) pos_x = pos_x + node_widths[i]/2 + margin -- add second part of offset end @@ -369,6 +370,25 @@ function M.is_web() end +--- Check if device is HTML5 mobile +-- @function helper.is_web_mobile +-- @treturn boolean Is web mobile +function M.is_web_mobile() + if html5 then + return html5.run("(typeof window.orientation !== 'undefined') || (navigator.userAgent.indexOf('IEMobile') !== -1);") == "true" + end + return false +end + + +--- Check if device is mobile and can support multitouch +-- @function helper.is_multitouch_supported +-- @treturn boolean Is multitouch supported +function M.is_multitouch_supported() + return M.is_mobile() or M.is_web_mobile() +end + + --- Simple table to one-line string converter -- @function helper.table_to_string -- @tparam table t diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index 29921a6..ca9121c 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -6,21 +6,11 @@ local settings = require("druid.system.settings") local M = {} -local function button_hover_scale(node, target, time) - gui.animate(node, "scale", target, gui.EASING_OUTSINE, time) -end - -local function button_tap_anim(node, tap_scale, start_scale) - gui.animate(node, gui.PROP_SCALE, tap_scale, gui.EASING_INSINE, 0.1, 0, function() - gui.animate(node, gui.PROP_SCALE, start_scale, gui.EASING_INSINE, 0.1) - end) -end - M["button"] = { - HOVER_SCALE = vmath.vector3(0.02, 0.02, 1), - HOVER_MOUSE_SCALE = vmath.vector3(0.01, 0.01, 1), - HOVER_TIME = 0.04, - SCALE_CHANGE = vmath.vector3(0.035, 0.035, 1), + HOVER_SCALE = vmath.vector3(0.08, 0.08, 1), + HOVER_MOUSE_SCALE = vmath.vector3(0.04, 0.04, 1), + HOVER_TIME = 0.05, + SCALE_CHANGE = vmath.vector3(0.12, 0.12, 1), BTN_SOUND = "click", BTN_SOUND_DISABLED = "click", DISABLED_COLOR = vmath.vector4(0, 0, 0, 1), @@ -33,35 +23,44 @@ M["button"] = { local scale_to = self.start_scale + M.button.HOVER_SCALE local target_scale = state and scale_to or self.start_scale - button_hover_scale(node, target_scale, M.button.HOVER_TIME) + gui.animate(node, "scale", target_scale, gui.EASING_OUTSINE, M.button.HOVER_TIME) end, on_mouse_hover = function(self, node, state) local scale_to = self.start_scale + M.button.HOVER_MOUSE_SCALE local target_scale = state and scale_to or self.start_scale - button_hover_scale(node, target_scale, M.button.HOVER_TIME) + gui.animate(node, "scale", target_scale, gui.EASING_OUTSINE, M.button.HOVER_TIME) end, on_click = function(self, node) local scale_to = self.start_scale + M.button.SCALE_CHANGE - button_tap_anim(node, scale_to, self.start_scale) + gui.set_scale(node, scale_to) + + local is_hover = self.hover:is_mouse_hovered() + local target_scale = is_hover and self.start_scale + M.button.HOVER_MOUSE_SCALE or self.start_scale + gui.animate(node, gui.PROP_SCALE, target_scale, gui.EASING_OUTBACK, 0.24) + settings.play_sound(M.button.BTN_SOUND) end, on_click_disabled = function(self, node) - settings.play_sound(M.button.BTN_SOUND_DISABLED) + local start_pos = self.start_pos + gui.animate(node, "position.x", start_pos.x - 3, gui.EASING_OUTSINE, 0.05, 0, function() + gui.animate(node, "position.x", start_pos.x + 3, gui.EASING_OUTSINE, 0.1, 0, function() + gui.animate(node, "position.x", start_pos.x, gui.EASING_OUTSINE, 0.05) + end) + end) end, on_set_enabled = function(self, node, state) - if state then - gui.set_color(node, M.button.ENABLED_COLOR) - else - gui.set_color(node, M.button.DISABLED_COLOR) - end end } +M["hover"] = { + ON_HOVER_CURSOR = nil, + ON_MOUSE_HOVER_CURSOR = nil, +} M["drag"] = { DRAG_DEADZONE = 10, -- Size in pixels of drag deadzone @@ -84,8 +83,8 @@ M["scroll"] = { INERT_SPEED = 30, -- koef. of inert speed EXTRA_STRETCH_SIZE = 100, -- extra size in pixels outside of scroll (stretch effect) POINTS_DEADZONE = 20, -- Speed to check points of interests in no_inertion mode - WHEEL_SCROLL_SPEED = 0, -- Amount of pixels to scroll by one wheel event (0 to disable) - WHEEL_SCROLL_INVERTED = false, -- Boolean to invert wheel scroll side + WHEEL_SCROLL_SPEED = 20, -- Amount of pixels to scroll by one wheel event (0 to disable) + WHEEL_SCROLL_INVERTED = true, -- Boolean to invert wheel scroll side WHEEL_SCROLL_BY_INERTION = false, -- If true, wheel will add inertion to scroll. Direct set position otherwise. SMALL_CONTENT_SCROLL = false, -- If true, content node with size less than view node size can be scrolled } @@ -119,11 +118,10 @@ M["swipe"] = { M["input"] = { - IS_LONGTAP_ERASE = true, - BUTTON_SELECT_INCREASE = 1.06, + IS_LONGTAP_ERASE = false, + BUTTON_SELECT_INCREASE = 1.08, MASK_DEFAULT_CHAR = "*", IS_UNSELECT_ON_RESELECT = false, - NO_CONSUME_INPUT_WHILE_SELECTED = false, on_select = function(self, button_node) local target_scale = self.button.start_scale @@ -143,12 +141,6 @@ M["input"] = { end) end) end, - - button = { - LONGTAP_TIME = 0.4, - AUTOHOLD_TRIGGER = 0.8, - DOUBLETAP_TIME = 0.4, - } } diff --git a/druid/styles/sprites/style.lua b/druid/styles/sprites/style.lua deleted file mode 100644 index 260ff2d..0000000 --- a/druid/styles/sprites/style.lua +++ /dev/null @@ -1,26 +0,0 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - -local M = {} - - -M["button"] = { - LONGTAP_TIME = 0.4, - DOUBLETAP_TIME = 0.4, - - HOVER_MOUSE_IMAGE = "button_yellow", - DEFAULT_IMAGE = "button_blue", - HOVER_IMAGE = "button_red", - - on_hover = function(self, node, state) - local anim = state and M.button.HOVER_IMAGE or M.button.DEFAULT_IMAGE - gui.play_flipbook(node, anim) - end, - - on_mouse_hover = function(self, node, state) - local anim = state and M.button.HOVER_MOUSE_IMAGE or M.button.DEFAULT_IMAGE - gui.play_flipbook(node, anim) - end -} - - -return M diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 02f875d..ece7d01 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -68,7 +68,6 @@ -- @see Timer local helper = require("druid.helper") -local class = require("druid.system.middleclass") local settings = require("druid.system.settings") local base_component = require("druid.component") @@ -94,7 +93,7 @@ local back_handler = require("druid.base.back_handler") -- local dynamic_grid = require("druid.extended.dynamic_grid") -- local checkbox_group = require("druid.extended.checkbox_group") -local DruidInstance = class("druid.druid_instance") +local DruidInstance = {} local MSG_ADD_FOCUS = hash("acquire_input_focus") local MSG_REMOVE_FOCUS = hash("release_input_focus") @@ -193,10 +192,6 @@ end local function process_input(self, action_id, action, components) local is_input_consumed = false - if #components == 0 then - return false - end - for i = #components, 1, -1 do local component = components[i] local meta = component._meta @@ -252,7 +247,7 @@ function DruidInstance.initialize(self, context, style) end ---- Create new component. +-- Create new component. -- @tparam DruidInstance self -- @tparam BaseComponent component Component module -- @tparam any ... Other component params to pass it to component:init function @@ -293,23 +288,27 @@ end -- Component `on_remove` function will be invoked, if exist. -- @tparam DruidInstance self -- @tparam BaseComponent component Component instance +-- @treturn boolean True if component was removed function DruidInstance.remove(self, component) if self._is_late_remove_enabled then table.insert(self._late_remove, component) - return + return false end -- Recursive remove all children of component local children = component._meta.children for i = #children, 1, -1 do self:remove(children[i]) - local parent = children[i]:get_parent_component() - if parent then - parent:__remove_children(children[i]) - end children[i] = nil end + local parent = component:get_parent_component() + if parent then + parent:__remove_child(component) + end + + local is_removed = false + local all_components = self.components_all for i = #all_components, 1, -1 do if all_components[i] == component then @@ -317,6 +316,7 @@ function DruidInstance.remove(self, component) component:on_remove() end table.remove(all_components, i) + is_removed = true end end @@ -330,6 +330,8 @@ function DruidInstance.remove(self, component) end end end + + return is_removed end @@ -473,10 +475,10 @@ end -- If whitelist is not empty and component not contains in this list, -- component will be not processed on input step -- @tparam DruidInstance self --- @tparam[opt=nil] table|BaseComponent whitelist_components The array of component to whitelist +-- @tparam table|BaseComponent|nil whitelist_components The array of component to whitelist -- @treturn self @{DruidInstance} function DruidInstance.set_whitelist(self, whitelist_components) - if whitelist_components and whitelist_components.isInstanceOf then + if whitelist_components and whitelist_components._component then whitelist_components = { whitelist_components } end @@ -495,10 +497,10 @@ end -- If blacklist is not empty and component contains in this list, -- component will be not processed on input step -- @tparam DruidInstance self @{DruidInstance} --- @tparam[opt=nil] table|BaseComponent blacklist_components The array of component to blacklist +-- @tparam table|BaseComponent|nil blacklist_components The array of component to blacklist -- @treturn self @{DruidInstance} function DruidInstance.set_blacklist(self, blacklist_components) - if blacklist_components and blacklist_components.isInstanceOf then + if blacklist_components and blacklist_components._component then blacklist_components = { blacklist_components } end @@ -556,8 +558,8 @@ end -- @tparam DruidInstance self -- @tparam string|node node The node_id or gui.get_node(node_id) -- @tparam function|nil callback Button callback --- @tparam table|nil params Button callback params --- @tparam node|nil anim_node Button anim node (node, if not provided) +-- @tparam any|nil params Button callback params +-- @tparam node|string|nil anim_node Button anim node (node, if not provided) -- @treturn Button @{Button} component function DruidInstance.new_button(self, node, callback, params, anim_node) return DruidInstance.new(self, button, node, callback, params, anim_node) @@ -587,9 +589,10 @@ end -- @tparam DruidInstance self -- @tparam string|node node The node_id or gui.get_node(node_id) -- @tparam function|nil on_hover_callback Hover callback +-- @tparam function|nil on_mouse_hover_callback Mouse hover callback -- @treturn Hover @{Hover} component -function DruidInstance.new_hover(self, node, on_hover_callback) - return DruidInstance.new(self, hover, node, on_hover_callback) +function DruidInstance.new_hover(self, node, on_hover_callback, on_mouse_hover_callback) + return DruidInstance.new(self, hover, node, on_hover_callback, on_mouse_hover_callback) end @@ -705,7 +708,7 @@ end --- Create @{Input} component -- @tparam DruidInstance self -- @tparam string|node click_node Button node to enabled input component --- @tparam string|node text_node Text node what will be changed on user input +-- @tparam string|node|druid.text text_node Text node what will be changed on user input -- @tparam number|nil keyboard_type Gui keyboard type for input field -- @treturn Input @{Input} component function DruidInstance.new_input(self, click_node, text_node, keyboard_type) @@ -715,9 +718,9 @@ end --- Create @{CheckboxGroup} component -- @tparam DruidInstance self --- @tparam node[] nodes Array of gui node +-- @tparam (node|string)[] 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 +-- @tparam (node|string)[]|nil click_nodes Array of trigger nodes, by default equals to nodes -- @treturn CheckboxGroup @{CheckboxGroup} component function DruidInstance.new_checkbox_group(self, nodes, callback, click_nodes) return helper.require_component_message("checkbox_group") @@ -727,7 +730,7 @@ end --- Create @{DataList} component -- @tparam DruidInstance self -- @tparam Scroll druid_scroll The Scroll instance for Data List component --- @tparam StaticGrid|DynamicGrid druid_grid The @{StaticGrid} or @{DynamicGrid} instance for Data List component +-- @tparam StaticGrid druid_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]) -- @treturn DataList @{DataList} component function DruidInstance.new_data_list(self, druid_scroll, druid_grid, create_function) @@ -737,9 +740,9 @@ end --- Create @{RadioGroup} component -- @tparam DruidInstance self --- @tparam node[] nodes Array of gui node +-- @tparam (node|string)[] nodes Array of gui node -- @tparam function callback Radio callback --- @tparam[opt=node] node[] click_nodes Array of trigger nodes, by default equals to nodes +-- @tparam (node|string)[]|nil click_nodes Array of trigger nodes, by default equals to nodes -- @treturn RadioGroup @{RadioGroup} component function DruidInstance.new_radio_group(self, nodes, callback, click_nodes) return helper.require_component_message("radio_group") diff --git a/druid/system/middleclass.lua b/druid/system/middleclass.lua deleted file mode 100644 index e0ef598..0000000 --- a/druid/system/middleclass.lua +++ /dev/null @@ -1,156 +0,0 @@ --- Source: https://github.com/kikito/middleclass -local middleclass = {} - -local function _createIndexWrapper(aClass, f) - if f == nil then - return aClass.__instanceDict - else - return function(self, name) - local value = aClass.__instanceDict[name] - - if value ~= nil then - return value - elseif type(f) == "function" then - return (f(self, name)) - else - return f[name] - end - end - end -end - -local function _propagateInstanceMethod(aClass, name, f) - f = name == "__index" and _createIndexWrapper(aClass, f) or f - aClass.__instanceDict[name] = f - - for subclass in pairs(aClass.subclasses) do - if rawget(subclass.__declaredMethods, name) == nil then - _propagateInstanceMethod(subclass, name, f) - end - end -end - -local function _declareInstanceMethod(aClass, name, f) - aClass.__declaredMethods[name] = f - - if f == nil and aClass.super then - f = aClass.super.__instanceDict[name] - end - - _propagateInstanceMethod(aClass, name, f) -end - -local function _tostring(self) return "class " .. self.name end -local function _call(self, ...) return self:instantiate(...) end - -local function _createClass(name, super) - local dict = {} - dict.__index = dict - - local aClass = { name = name, super = super, static = {}, - __instanceDict = dict, __declaredMethods = {}, - subclasses = setmetatable({}, {__mode='k'}) } - - if super then - setmetatable(aClass.static, { - __index = function(_,k) - local result = rawget(dict,k) - if result == nil then - return super.static[k] - end - return result - end - }) - else - setmetatable(aClass.static, { __index = function(_,k) return rawget(dict,k) end }) - end - - setmetatable(aClass, { __index = aClass.static, __tostring = _tostring, - __call = _call, __newindex = _declareInstanceMethod }) - - return aClass -end - -local function _includeMixin(aClass, mixin) - assert(type(mixin) == 'table', "mixin must be a table") - - for name,method in pairs(mixin) do - if name ~= "included" and name ~= "static" then aClass[name] = method end - end - - for name,method in pairs(mixin.static or {}) do - aClass.static[name] = method - end - - if type(mixin.included)=="function" then mixin:included(aClass) end - return aClass -end - -local DefaultMixin = { - __tostring = function(self) return "instance of " .. tostring(self.class) end, - - initialize = function(self, ...) end, - - isInstanceOf = function(self, aClass) - return type(aClass) == 'table' - and type(self) == 'table' - and (self.class == aClass - or type(self.class) == 'table' - and type(self.class.isSubclassOf) == 'function' - and self.class:isSubclassOf(aClass)) - end, - - static = { - allocate = function(self) - assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'") - return setmetatable({ class = self }, self.__instanceDict) - end, - - instantiate = function(self, ...) - assert(type(self) == 'table', "Make sure that you are using 'Class:instantiate' instead of 'Class.instantiate'") - local instance = self:allocate() - instance:initialize(...) - return instance - end, - - subclass = function(self, name) - assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'") - assert(type(name) == "string", "You must provide a name(string) for your class") - - local subclass = _createClass(name, self) - - for methodName, f in pairs(self.__instanceDict) do - _propagateInstanceMethod(subclass, methodName, f) - end - subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end - - self.subclasses[subclass] = true - self:subclassed(subclass) - - return subclass - end, - - subclassed = function(self, other) end, - - isSubclassOf = function(self, other) - return type(other) == 'table' and - type(self.super) == 'table' and - ( self.super == other or self.super:isSubclassOf(other) ) - end, - - include = function(self, ...) - assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'") - for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end - return self - end - } -} - -function middleclass.class(name, super) - assert(type(name) == 'string', "A name (string) is needed for the new class") - return super and super:subclass(name) or _includeMixin(_createClass(name), DefaultMixin) -end - -setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end }) - -return middleclass diff --git a/druid/system/utf8.lua b/druid/system/utf8.lua index 7f13914..6c99fcf 100644 --- a/druid/system/utf8.lua +++ b/druid/system/utf8.lua @@ -688,7 +688,8 @@ local function matcherGenerator(regex, plain) local sum = 0 local bc, ec = utf8sub(str, 1, 1), utf8sub(str, 2, 2) local skip = len(bc) + len(ec) - bc, ec = utf8unicode(bc), utf8unicode(ec) + bc = utf8unicode(bc) --[[@as string]] + ec = utf8unicode(ec) --[[@as string]] return function(cC) if cC == ec and sum > 0 then sum = sum - 1 diff --git a/druid/templates/component.template.lua b/druid/templates/component.template.lua index cbc43ad..d67bf32 100644 --- a/druid/templates/component.template.lua +++ b/druid/templates/component.template.lua @@ -3,20 +3,13 @@ local component = require("druid.component") ---@class component_name : druid.base_component local Component = component.create("component_name") -local SCHEME = { - ROOT = "root", - BUTTON = "button", -} - -- 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.druid = self:get_druid(template, nodes) + self.root = self:get_node("root") - self.button = self.druid:new_button(SCHEME.BUTTON, function() end) + self.button = self.druid:new_button("button", function() end) end diff --git a/druid/templates/component_full.template.lua b/druid/templates/component_full.template.lua index 70232d1..1978cf2 100644 --- a/druid/templates/component_full.template.lua +++ b/druid/templates/component_full.template.lua @@ -3,26 +3,16 @@ 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", -} - - -- 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) + -- Use inner druid instance to create components inside this component + self.druid = self:get_druid(template, nodes) -- self:get_node will auto process component template and nodes - self.root = self:get_node(SCHEME.ROOT) + self.root = self:get_node("root") - -- Use inner druid instance to create components inside this component - self.druid = self:get_druid() end diff --git a/example/example.collection b/example/example.collection index 0d91d8e..4651339 100644 --- a/example/example.collection +++ b/example/example.collection @@ -5,74 +5,16 @@ embedded_instances { data: "components {\n" " id: \"main\"\n" " component: \"/example/example.gui\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" - " property_decls {\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "system" data: "components {\n" " id: \"init\"\n" " component: \"/example/init.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" - " property_decls {\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "sound" @@ -80,59 +22,15 @@ embedded_instances { " id: \"click\"\n" " type: \"sound\"\n" " data: \"sound: \\\"/example/assets/sounds/click.ogg\\\"\\n" - "looping: 0\\n" - "group: \\\"master\\\"\\n" - "gain: 1.0\\n" - "pan: 0.0\\n" - "speed: 1.0\\n" - "loopcount: 0\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_overview" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_overview\"\n" @@ -143,62 +41,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/overview/overview.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_buttons" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_buttons\"\n" @@ -209,62 +66,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/buttons/buttons.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "texts_general" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"texts_general\"\n" @@ -275,62 +91,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/texts/texts_general/texts_general.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_sliders" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_sliders\"\n" @@ -341,62 +116,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/sliders/sliders.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_grid" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_grid\"\n" @@ -407,62 +141,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/grid/grid.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_input" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_input\"\n" @@ -473,62 +166,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/input/input.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_scroll" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_scroll\"\n" @@ -539,62 +191,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/scroll/scroll.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_data_list" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_data_list\"\n" @@ -605,62 +216,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/data_list/data_list.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "data_list_static_grid" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"data_list_static_grid\"\n" @@ -671,62 +241,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/data_list/static_grid/static_grid.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "data_list_dynamic_grid" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"data_list_dynamic_grid\"\n" @@ -737,62 +266,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/data_list/dynamic_grid/dynamic_grid.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "data_list_navigate" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"data_list_navigate\"\n" @@ -803,62 +291,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/data_list/navigate/navigate.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "data_list_add_remove_nodes" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"data_list_add_remove_nodes\"\n" @@ -869,62 +316,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/data_list/add_remove_nodes/add_remove_nodes.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "grid_static_grid" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"grid_static_grid\"\n" @@ -935,62 +341,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/grid/static_grid/static_grid.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "grid_animations" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"grid_animations\"\n" @@ -1001,62 +366,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/grid/grid_animations/grid_animations.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "grid_static_grid_dynamic_pos" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"grid_static_grid_dynamic_pos\"\n" @@ -1067,62 +391,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/grid/static_grid_dynamic_pos/static_grid_dynamic_pos.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "system_whitelist_blacklist" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"system_whitelist_blacklist\"\n" @@ -1133,62 +416,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/system/whitelist_blacklist/whitelist_blacklist.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "texts_adjust" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"texts_adjust\"\n" @@ -1199,62 +441,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/texts/texts_adjust/texts_adjust.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "system_message_input" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"system_message_input\"\n" @@ -1265,62 +466,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/system/message_input/message_input.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "custom_rich_input" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"custom_rich_input\"\n" @@ -1331,128 +491,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/custom/rich_input/rich_input.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } -} -embedded_instances { - id: "custom_pin_knob" - data: "components {\n" - " id: \"screen_factory\"\n" - " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" - " properties {\n" - " id: \"screen_id\"\n" - " value: \"custom_pin_knob\"\n" - " type: PROPERTY_TYPE_HASH\n" - " }\n" - " properties {\n" - " id: \"popup\"\n" - " value: \"true\"\n" - " type: PROPERTY_TYPE_BOOLEAN\n" - " }\n" - " property_decls {\n" - " }\n" - "}\n" - "embedded_components {\n" - " id: \"collectionfactory\"\n" - " type: \"collectionfactory\"\n" - " data: \"prototype: \\\"/example/examples/custom/pin_knob/pin_knob.collection\\\"\\n" - "load_dynamically: true\\n" - "dynamic_prototype: false\\n" - "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" - "}\n" - "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "system_inner_templates" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"system_inner_templates\"\n" @@ -1463,62 +516,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/system/inner_templates/inner_templates.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_swipe" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_swipe\"\n" @@ -1529,62 +541,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/swipe/swipe.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_drag" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_drag\"\n" @@ -1595,62 +566,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/drag/drag.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_checkboxes" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_checkboxes\"\n" @@ -1661,62 +591,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/checkboxes/checkboxes.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "data_list_reinit_data" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"data_list_reinit_data\"\n" @@ -1727,62 +616,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/data_list/reinit_data/reinit_data.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_layout" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_layout\"\n" @@ -1793,62 +641,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/layout/layout.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_hotkey" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_hotkey\"\n" @@ -1859,62 +666,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/hotkey/hotkey.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "data_list_with_component" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"data_list_with_component\"\n" @@ -1925,62 +691,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/data_list/with_component/with_component.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "layout_fit" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"layout_fit\"\n" @@ -1991,62 +716,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/layout/layout_fit/layout_fit.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_progress_bar" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_progress_bar\"\n" @@ -2057,62 +741,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/progress_bar/progress_bar.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "system_late_init_check" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"system_late_init_check\"\n" @@ -2123,62 +766,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/system/late_init_check/late_init_check.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "general_hover" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"general_hover\"\n" @@ -2189,62 +791,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/general/hover/hover.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "texts_lang_text" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"texts_lang_text\"\n" @@ -2255,62 +816,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/texts/lang_text/lang_text.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "custom_rich_text" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"custom_rich_text\"\n" @@ -2321,62 +841,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/custom/rich_text/rich_text.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "data_list_manage_data" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"data_list_manage_data\"\n" @@ -2387,62 +866,21 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/data_list/manage_data/manage_data.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } embedded_instances { id: "rich_text_texts" data: "components {\n" " id: \"screen_factory\"\n" " component: \"/monarch/screen_factory.script\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" " properties {\n" " id: \"screen_id\"\n" " value: \"rich_text_texts\"\n" @@ -2453,43 +891,13 @@ embedded_instances { " value: \"true\"\n" " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" - " property_decls {\n" - " }\n" "}\n" "embedded_components {\n" " id: \"collectionfactory\"\n" " type: \"collectionfactory\"\n" " data: \"prototype: \\\"/example/examples/rich_text/rich_text_texts/rich_text_texts.collection\\\"\\n" "load_dynamically: true\\n" - "dynamic_prototype: false\\n" "\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } diff --git a/example/examples/custom/pin_knob/pin_knob.collection b/example/examples/custom/pin_knob/pin_knob.collection deleted file mode 100644 index 2698ebf..0000000 --- a/example/examples/custom/pin_knob/pin_knob.collection +++ /dev/null @@ -1,37 +0,0 @@ -name: "pin_knob" -scale_along_z: 0 -embedded_instances { - id: "go" - data: "components {\n" - " id: \"rich_input\"\n" - " component: \"/example/examples/custom/pin_knob/pin_knob.gui\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" - "}\n" - "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } -} diff --git a/example/examples/custom/pin_knob/pin_knob.gui b/example/examples/custom/pin_knob/pin_knob.gui deleted file mode 100644 index d20d64f..0000000 --- a/example/examples/custom/pin_knob/pin_knob.gui +++ /dev/null @@ -1,677 +0,0 @@ -script: "/example/examples/custom/pin_knob/pin_knob.gui_script" -fonts { - name: "game" - font: "/example/assets/fonts/game.font" -} -textures { - name: "kenney" - texture: "/example/assets/images/kenney.atlas" -} -background_color { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 -} -nodes { - position { - x: 300.0 - y: 415.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 830.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL -} -nodes { - position { - x: 0.0 - y: 370.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 700.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Input custom component" - font: "game" - id: "text_hint_horizontal" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: false - parent: "root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 1.0 - shadow_alpha: 0.0 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 -} -nodes { - position { - x: -100.0 - y: 230.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "pin_knob1" - parent: "root" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/pin_knob/pin_knob.gui" - template_node_child: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 1.0 - y: 1.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "pin_knob1/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "pin_knob1" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 2.0 - y: 2.0 - z: 1.0 - w: 1.0 - } - size { - x: 36.0 - y: 36.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/slider_move" - id: "pin_knob1/pin" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "pin_knob1/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO -} -nodes { - position { - x: 0.0 - y: 13.5 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.2 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 17.0 - y: 17.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.101960786 - z: 0.101960786 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/tick" - id: "pin_knob1/notch" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "pin_knob1/pin" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO -} -nodes { - position { - x: -100.0 - y: 154.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 120.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "50" - font: "game" - id: "text_value1" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: false - parent: "root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 1.0 - shadow_alpha: 0.0 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 -} -nodes { - position { - x: 100.0 - y: 230.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "pin_knob2" - parent: "root" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/pin_knob/pin_knob.gui" - template_node_child: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 1.0 - y: 1.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "pin_knob2/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "pin_knob2" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 2.0 - y: 2.0 - z: 1.0 - w: 1.0 - } - size { - x: 36.0 - y: 36.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/slider_move" - id: "pin_knob2/pin" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "pin_knob2/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO -} -nodes { - position { - x: 0.0 - y: 13.5 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.2 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 17.0 - y: 17.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.101960786 - z: 0.101960786 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/tick" - id: "pin_knob2/notch" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "pin_knob2/pin" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO -} -nodes { - position { - x: 100.0 - y: 154.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 120.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "50" - font: "game" - id: "text_value2" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: false - parent: "root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 1.0 - shadow_alpha: 0.0 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 -} -layers { - name: "image" -} -layers { - name: "text" -} -material: "/builtins/materials/gui.material" -adjust_reference: ADJUST_REFERENCE_PARENT -max_nodes: 512 diff --git a/example/examples/custom/pin_knob/pin_knob.gui_script b/example/examples/custom/pin_knob/pin_knob.gui_script deleted file mode 100644 index cd81204..0000000 --- a/example/examples/custom/pin_knob/pin_knob.gui_script +++ /dev/null @@ -1,49 +0,0 @@ -local druid = require("druid.druid") - -local pin_knob = require("druid.custom.pin_knob.pin_knob") - - -local function on_pin_change1(self, value) - self.text1:set_to(math.ceil(value)) -end - - -local function on_pin_change2(self, value) - self.text2:set_to(math.ceil(value)) -end - - -function init(self) - self.druid = druid.new(self) - - self.text1 = self.druid:new_text("text_value1", 0) - ---@type druid.pin_knob - self.pin_knob = self.druid:new(pin_knob, on_pin_change1, "pin_knob1") - self.pin_knob:set_angle(-10, -270, 270) - - self.text2 = self.druid:new_text("text_value2", 0) - ---@type druid.pin_knob - self.pin_knob2 = self.druid:new(pin_knob, on_pin_change2, "pin_knob2") - self.pin_knob2:set_angle(0, -90, 90) - self.pin_knob2:set_friction(0.15) -end - - -function final(self) - self.druid:final() -end - - -function update(self, dt) - self.druid:update(dt) -end - - -function on_message(self, message_id, message, sender) - self.druid:on_message(message_id, message, sender) -end - - -function on_input(self, action_id, action) - return self.druid:on_input(action_id, action) -end diff --git a/example/examples/custom/rich_text/rich_text.gui b/example/examples/custom/rich_text/rich_text.gui index f2dd603..0762a48 100644 --- a/example/examples/custom/rich_text/rich_text.gui +++ b/example/examples/custom/rich_text/rich_text.gui @@ -7,5388 +7,82 @@ textures { name: "kenney" texture: "/example/assets/images/kenney.atlas" } -background_color { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 -} nodes { position { x: 300.0 y: 415.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } size { x: 600.0 y: 830.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA texture: "kenney/empty" id: "root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - layer: "" inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true } nodes { position { - x: 0.0 y: 415.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } size { x: 600.0 y: 830.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA texture: "kenney/empty" id: "scroll_view" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT parent: "root" - layer: "" inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true visible: false } nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } size { x: 600.0 y: 1800.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA texture: "kenney/empty" id: "scroll_content" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT parent: "scroll_view" - layer: "" inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true visible: false } nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } scale { x: 0.8 y: 0.8 - z: 1.0 - w: 1.0 } size { x: 500.0 y: 100.0 - z: 0.0 - w: 1.0 } color { x: 0.9490196 y: 0.9490196 z: 0.9490196 - w: 1.0 } type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA text: "This is the example page of Rich Text component" font: "game" id: "hint1" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE pivot: PIVOT_N outline { x: 0.2 - y: 0.0 z: 0.2 - w: 1.0 } shadow { x: 0.2 y: 0.2 z: 0.2 - w: 1.0 } - adjust_mode: ADJUST_MODE_FIT line_break: true parent: "scroll_content" - layer: "" inherit_alpha: true - alpha: 1.0 outline_alpha: 0.75 shadow_alpha: 0.25 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -160.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 150.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case1" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_1" - parent: "case1" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 150.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_1/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_1" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 4 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -200.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 150.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich text" - font: "game" - id: "rich_text_1/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_1/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.75 - shadow_alpha: 0.0 - overridden_fields: 4 - overridden_fields: 18 - overridden_fields: 31 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_1/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_1/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -252.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.8 - y: 0.8 - z: 1.0 - w: 1.0 - } - size { - x: 500.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.9490196 - y: 0.9490196 - z: 0.9490196 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text should match with usual text node" - font: "game" - id: "hint2" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.2 - y: 0.0 - z: 0.2 - w: 1.0 - } - shadow { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "scroll_content" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.75 - shadow_alpha: 0.25 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -400.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 120.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case2" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_2" - parent: "case2" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 112.5 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_2/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_2" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -200.0 - y: -10.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 550.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Here is example to compare Rich Text posing with usual GUI Text Node." - font: "game" - id: "rich_text_2/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_2/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_2/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_2/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 533.0 - y: 150.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.9019608 - y: 0.7019608 - z: 0.9019608 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Here is example to compare Rich Text posing with usual GUI Text Node." - font: "game" - id: "text_case_2" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case2" - layer: "" - inherit_alpha: true - alpha: 0.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -475.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.8 - y: 0.8 - z: 1.0 - w: 1.0 - } - size { - x: 500.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.9490196 - y: 0.9490196 - z: 0.9490196 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text split text to several text nodes" - font: "game" - id: "hint3" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.2 - y: 0.0 - z: 0.2 - w: 1.0 - } - shadow { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "scroll_content" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.75 - shadow_alpha: 0.25 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -620.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 120.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case3" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_3" - parent: "case3" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 112.5 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_3/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_3" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -200.0 - y: -10.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_3/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_3/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_3/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_3/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -685.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.8 - y: 0.8 - z: 1.0 - w: 1.0 - } - size { - x: 500.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.9490196 - y: 0.9490196 - z: 0.9490196 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text supports images" - font: "game" - id: "hint4" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.2 - y: 0.0 - z: 0.2 - w: 1.0 - } - shadow { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "scroll_content" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.75 - shadow_alpha: 0.25 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -800.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case4_1" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_4_1" - parent: "case4_1" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_4_1/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_4_1" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -200.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_4_1/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_4_1/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_4_1/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_4_1/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -870.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case4_2" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_4_2" - parent: "case4_2" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_4_2/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_4_2" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -200.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_4_2/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_4_2/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.5 - y: 0.5 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_4_2/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_4_2/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -940.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case4_3" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_4_3" - parent: "case4_3" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_4_3/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_4_3" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -200.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_4_3/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_4_3/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_4_3/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_4_3/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -986.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.8 - y: 0.8 - z: 1.0 - w: 1.0 - } - size { - x: 700.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.9490196 - y: 0.9490196 - z: 0.9490196 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text support all pivots (area from root node size)" - font: "game" - id: "hint5" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.2 - y: 0.0 - z: 0.2 - w: 1.0 - } - shadow { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "scroll_content" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.75 - shadow_alpha: 0.25 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: -180.0 - y: -1132.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5_NW" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_5_NW" - parent: "case5_NW" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: -75.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_5_NW/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_NW - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_NW" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: -50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.5 - y: 0.5 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_5_NW/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_5_NW/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_5_NW/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_NW/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -1132.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5_N" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_5_N" - parent: "case5_N" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_5_N/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_N" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -73.0 - y: -50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.5 - y: 0.5 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_5_N/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_5_N/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_5_N/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_N/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 180.0 - y: -1132.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5_NE" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_5_NE" - parent: "case5_NE" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 75.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_5_NE/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_NE - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_NE" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -150.0 - y: -50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.5 - y: 0.5 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_5_NE/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_5_NE/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_5_NE/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_NE/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: -180.0 - y: -1252.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5_W" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_5_W" - parent: "case5_W" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: -75.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_5_W/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_W" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.5 - y: 0.5 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_5_W/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_5_W/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_5_W/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_W/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -1252.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5_C" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_5_C" - parent: "case5_C" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_5_C/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_C" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -73.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.5 - y: 0.5 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_5_C/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_5_C/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_5_C/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_C/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 180.0 - y: -1252.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5_E" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_5_E" - parent: "case5_E" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 75.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_5_E/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_E - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_E" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -150.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.5 - y: 0.5 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_5_E/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_5_E/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_5_E/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_E/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: -180.0 - y: -1372.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5_SW" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_5_SW" - parent: "case5_SW" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: -75.0 - y: -50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_5_SW/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_SW - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_SW" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.5 - y: 0.5 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_5_SW/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_5_SW/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_5_SW/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_S - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_SW/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -1372.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5_S" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_5_S" - parent: "case5_S" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: -50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_5_S/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_S - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_S" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -75.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.5 - y: 0.5 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_5_S/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_5_S/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_5_S/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_S - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_S/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 180.0 - y: -1372.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5_SE" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_5_SE" - parent: "case5_SE" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 75.0 - y: -50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_5_SE/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_SE - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_SE" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 1 - overridden_fields: 4 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: -150.0 - y: 50.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.5 - y: 0.5 - z: 1.0 - w: 1.0 - } - size { - x: 150.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 0.9019608 - z: 0.6 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "rich_text_5_SE/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_W - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.5019608 - y: 0.7019608 - z: 0.7019608 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_5_SE/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 8 - overridden_fields: 16 - overridden_fields: 18 - overridden_fields: 32 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.75 - y: 0.75 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_5_SE/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_S - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_5_SE/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 3 - overridden_fields: 14 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: -500.0 - y: -200.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "highlight" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -1455.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.8 - y: 0.8 - z: 1.0 - w: 1.0 - } - size { - x: 700.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.9490196 - y: 0.9490196 - z: 0.9490196 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "You can get the tagged word to make logic around" - font: "game" - id: "hint" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.2 - y: 0.0 - z: 0.2 - w: 1.0 - } - shadow { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "scroll_content" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.75 - shadow_alpha: 0.25 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -1622.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 150.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.101960786 - y: 0.3019608 - z: 0.3019608 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case6" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "scroll_content" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text_6" - parent: "case6" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 150.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text_6/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_6" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 4 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 150.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich text" - font: "game" - id: "rich_text_6/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text_6/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.75 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 4 - overridden_fields: 14 - overridden_fields: 18 - overridden_fields: 31 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text_6/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text_6/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true } layers { name: "image" @@ -5398,4 +92,3 @@ layers { } material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT -max_nodes: 512 diff --git a/example/examples/data_list/with_component/button_component/button_component.lua b/example/examples/data_list/with_component/button_component/button_component.lua index 39c6c23..2609c8e 100644 --- a/example/examples/data_list/with_component/button_component/button_component.lua +++ b/example/examples/data_list/with_component/button_component/button_component.lua @@ -14,24 +14,15 @@ local component = require("druid.component") ---@field druid druid_instance local ButtonComponent = component.create("button_component") -local SCHEME = { - ROOT = "root", - TEXT = "text", - ICON = "icon", - CHECKBOX = "checkbox" -} - ---@param template string ---@param nodes table function ButtonComponent:init(template, nodes) - self:set_template(template) - self:set_nodes(nodes) - self.druid = self:get_druid() + self.druid = self:get_druid(template, nodes) - self.root = self:get_node(SCHEME.ROOT) - self.text = self.druid:new_text(SCHEME.TEXT) - self.checkbox = self:get_node(SCHEME.CHECKBOX) + self.root = self:get_node("root") + self.text = self.druid:new_text("text") + self.checkbox = self:get_node("checkbox") self.button = self.druid:new_button(self.root, self._on_click) diff --git a/example/examples/general/buttons/buttons.gui_script b/example/examples/general/buttons/buttons.gui_script index 04b3f1c..144c237 100644 --- a/example/examples/general/buttons/buttons.gui_script +++ b/example/examples/general/buttons/buttons.gui_script @@ -1,5 +1,4 @@ local druid = require("druid.druid") -local sprite_style = require("druid.styles.sprites.style") local function usual_callback() @@ -52,9 +51,6 @@ end local function setup_buttons(self) self.druid:new_button("button_usual/button", usual_callback) - local custom_style = self.druid:new_button("button_custom_style/button", usual_callback) - custom_style:set_style(sprite_style) - local long_button = self.druid:new_button("button_long_tap/button", usual_callback) long_button.on_hold_callback:subscribe(hold_callback) long_button.on_long_click:subscribe(long_tap_callback) diff --git a/example/examples/general/scroll/scroll.gui_script b/example/examples/general/scroll/scroll.gui_script index 3ad39b9..f9a5468 100644 --- a/example/examples/general/scroll/scroll.gui_script +++ b/example/examples/general/scroll/scroll.gui_script @@ -54,9 +54,10 @@ function init(self) self.druid:new_scroll("children_scroll_3", "children_scroll_content_3") -- Content with less size than view - self.druid:new_scroll("scroll_smaller_view", "scroll_smaller_content") - :set_extra_stretch_size(0) - :set_inert(false) + local small_scroll = self.druid:new_scroll("scroll_smaller_view", "scroll_smaller_content") --[[@as druid.scroll]] + small_scroll.style.SMALL_CONTENT_SCROLL = true + small_scroll:set_extra_stretch_size(0) -- it also update scroll size due the change of SMALL_CONTENT_SCROLL + small_scroll:set_inert(false) -- Scroll with points of interests self.druid:new_scroll("scroll_with_points", "scroll_with_points_content") diff --git a/example/examples/rich_text/rich_text_texts/prefab_example_rich_text.gui b/example/examples/rich_text/rich_text_texts/prefab_example_rich_text.gui index 2c49da9..aa377e3 100644 --- a/example/examples/rich_text/rich_text_texts/prefab_example_rich_text.gui +++ b/example/examples/rich_text/rich_text_texts/prefab_example_rich_text.gui @@ -1,4 +1,3 @@ -script: "" fonts { name: "game" font: "/example/assets/fonts/game.font" @@ -7,423 +6,67 @@ textures { name: "kenney" texture: "/example/assets/images/kenney.atlas" } -background_color { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 -} nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } size { x: 600.0 y: 200.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA texture: "kenney/empty" id: "root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - layer: "" inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true visible: false } nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } scale { x: 0.8 y: 0.8 - z: 1.0 - w: 1.0 } size { x: 750.0 y: 100.0 - z: 0.0 - w: 1.0 } color { - x: 1.0 - y: 1.0 z: 0.9411765 - w: 1.0 } type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA text: "Here is simple example with text" font: "game" id: "hint" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE pivot: PIVOT_N outline { x: 0.101960786 y: 0.101960786 z: 0.101960786 - w: 1.0 } shadow { x: 1.0 y: 1.0 z: 1.0 - w: 1.0 } - adjust_mode: ADJUST_MODE_FIT line_break: true parent: "root" - layer: "" inherit_alpha: true - alpha: 1.0 outline_alpha: 0.7 shadow_alpha: 0.0 - template_node_child: false - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true } nodes { position { - x: 0.0 y: -60.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } size { x: 600.0 y: 130.0 - z: 0.0 - w: 1.0 } color { - x: 1.0 - y: 1.0 z: 0.9411765 - w: 1.0 } type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" id: "area" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT parent: "root" - layer: "" inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -65.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "rich_text" - parent: "area" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 500.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "rich_text/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 4 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 300.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich text" - font: "game" - id: "rich_text/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "rich_text/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 14 - overridden_fields: 18 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "rich_text/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "rich_text/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true } material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT -max_nodes: 512 diff --git a/example/examples/rich_text/rich_text_texts/rich_text_texts.gui b/example/examples/rich_text/rich_text_texts/rich_text_texts.gui index 757aa39..6354116 100644 --- a/example/examples/rich_text/rich_text_texts/rich_text_texts.gui +++ b/example/examples/rich_text/rich_text_texts/rich_text_texts.gui @@ -15,2838 +15,37 @@ textures { name: "kenney" texture: "/example/assets/images/kenney.atlas" } -background_color { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 -} nodes { position { x: 300.0 y: 415.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } size { x: 600.0 y: 830.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA texture: "kenney/empty" id: "root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - layer: "" inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true } nodes { position { - x: 0.0 y: 415.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } size { x: 600.0 y: 1200.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 } type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA texture: "kenney/empty" id: "content" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE pivot: PIVOT_N adjust_mode: ADJUST_MODE_STRETCH parent: "root" - layer: "" inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: false - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true visible: false } -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case1" - parent: "content" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/example/examples/rich_text/rich_text_texts/prefab_example_rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 200.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "case1/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case1" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.8 - y: 0.8 - z: 1.0 - w: 1.0 - } - size { - x: 750.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Here is simple example with text" - font: "game" - id: "case1/hint" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.101960786 - y: 0.101960786 - z: 0.101960786 - w: 1.0 - } - shadow { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case1/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.7 - shadow_alpha: 0.0 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -60.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case1/area" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case1/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -65.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case1/rich_text" - parent: "case1/area" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: true - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 500.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case1/rich_text/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case1/rich_text" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 300.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich text" - font: "game" - id: "case1/rich_text/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case1/rich_text/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "case1/rich_text/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case1/rich_text/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -200.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case2" - parent: "content" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/example/examples/rich_text/rich_text_texts/prefab_example_rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 200.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "case2/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case2" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.8 - y: 0.8 - z: 1.0 - w: 1.0 - } - size { - x: 750.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Text color setup" - font: "game" - id: "case2/hint" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.101960786 - y: 0.101960786 - z: 0.101960786 - w: 1.0 - } - shadow { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case2/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.7 - shadow_alpha: 0.0 - overridden_fields: 8 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -60.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case2/area" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case2/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -65.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case2/rich_text" - parent: "case2/area" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: true - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 500.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case2/rich_text/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case2/rich_text" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 300.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich text" - font: "game" - id: "case2/rich_text/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case2/rich_text/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "case2/rich_text/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case2/rich_text/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -400.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case3" - parent: "content" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/example/examples/rich_text/rich_text_texts/prefab_example_rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 200.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "case3/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case3" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.8 - y: 0.8 - z: 1.0 - w: 1.0 - } - size { - x: 750.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Text font setup" - font: "game" - id: "case3/hint" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.101960786 - y: 0.101960786 - z: 0.101960786 - w: 1.0 - } - shadow { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case3/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.7 - shadow_alpha: 0.0 - overridden_fields: 8 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -60.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case3/area" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case3/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -65.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case3/rich_text" - parent: "case3/area" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: true - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 500.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case3/rich_text/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case3/rich_text" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 300.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich text" - font: "game" - id: "case3/rich_text/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_SW - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case3/rich_text/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 14 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "case3/rich_text/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case3/rich_text/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -600.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case4" - parent: "content" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/example/examples/rich_text/rich_text_texts/prefab_example_rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 200.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "case4/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case4" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.8 - y: 0.8 - z: 1.0 - w: 1.0 - } - size { - x: 750.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Example with
    and " - font: "game" - id: "case4/hint" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.101960786 - y: 0.101960786 - z: 0.101960786 - w: 1.0 - } - shadow { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case4/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.7 - shadow_alpha: 0.0 - overridden_fields: 8 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -60.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case4/area" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case4/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -65.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case4/rich_text" - parent: "case4/area" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: true - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 500.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case4/rich_text/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case4/rich_text" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 4 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 300.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "case4/rich_text/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_SW - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case4/rich_text/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 8 - overridden_fields: 14 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "case4/rich_text/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case4/rich_text/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -800.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case5" - parent: "content" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/example/examples/rich_text/rich_text_texts/prefab_example_rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 200.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "case5/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case5" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.8 - y: 0.8 - z: 1.0 - w: 1.0 - } - size { - x: 750.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text can adjust text by height:" - font: "game" - id: "case5/hint" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.101960786 - y: 0.101960786 - z: 0.101960786 - w: 1.0 - } - shadow { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case5/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.7 - shadow_alpha: 0.0 - overridden_fields: 8 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -60.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5/area" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case5/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -65.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case5/rich_text" - parent: "case5/area" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: true - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.8 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case5/rich_text/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case5/rich_text" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 46 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 300.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "case5/rich_text/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_SW - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case5/rich_text/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 8 - overridden_fields: 14 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "case5/rich_text/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case5/rich_text/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -1000.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case6" - parent: "content" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/example/examples/rich_text/rich_text_texts/prefab_example_rich_text.gui" - template_node_child: false - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 200.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" - id: "case6/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case6" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: false -} -nodes { - position { - x: 0.0 - y: 9.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 0.7 - y: 0.7 - z: 1.0 - w: 1.0 - } - size { - x: 800.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Disabled Line Break in text_prefab, adjust by width" - font: "game" - id: "case6/hint" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - outline { - x: 0.101960786 - y: 0.101960786 - z: 0.101960786 - w: 1.0 - } - shadow { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: true - parent: "case6/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.7 - shadow_alpha: 0.0 - overridden_fields: 1 - overridden_fields: 3 - overridden_fields: 4 - overridden_fields: 8 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -60.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 600.0 - y: 130.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 0.9411765 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case6/area" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_N - adjust_mode: ADJUST_MODE_FIT - parent: "case6/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: -65.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_TEMPLATE - id: "case6/rich_text" - parent: "case6/area" - layer: "" - inherit_alpha: true - alpha: 1.0 - template: "/druid/custom/rich_text/rich_text.gui" - template_node_child: true - custom_type: 0 - enabled: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 400.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.8 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "" - id: "case6/rich_text/root" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case6/rich_text" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - overridden_fields: 4 - overridden_fields: 5 - overridden_fields: 46 - template_node_child: true - size_mode: SIZE_MODE_MANUAL - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 300.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { - x: 0.2 - y: 0.2 - z: 0.2 - w: 1.0 - } - type: TYPE_TEXT - blend_mode: BLEND_MODE_ALPHA - text: "Rich Text" - font: "game" - id: "case6/rich_text/text_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_SW - outline { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - shadow { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - adjust_mode: ADJUST_MODE_FIT - line_break: false - parent: "case6/rich_text/root" - layer: "" - inherit_alpha: true - alpha: 1.0 - outline_alpha: 0.0 - shadow_alpha: 0.0 - overridden_fields: 8 - overridden_fields: 14 - overridden_fields: 18 - template_node_child: true - text_leading: 1.0 - text_tracking: 0.0 - custom_type: 0 - enabled: true - visible: true -} -nodes { - position { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - size { - x: 200.0 - y: 100.0 - z: 0.0 - w: 1.0 - } - color { - x: 1.0 - y: 1.0 - z: 1.0 - w: 1.0 - } - type: TYPE_BOX - blend_mode: BLEND_MODE_ALPHA - texture: "items/checkmark" - id: "case6/rich_text/icon_prefab" - xanchor: XANCHOR_NONE - yanchor: YANCHOR_NONE - pivot: PIVOT_CENTER - adjust_mode: ADJUST_MODE_FIT - parent: "case6/rich_text/root" - layer: "" - inherit_alpha: true - slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 - } - clipping_mode: CLIPPING_MODE_NONE - clipping_visible: true - clipping_inverted: false - alpha: 1.0 - template_node_child: true - size_mode: SIZE_MODE_AUTO - custom_type: 0 - enabled: true - visible: true -} layers { name: "image" } @@ -2855,4 +54,3 @@ layers { } material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT -max_nodes: 512 diff --git a/example/game.appmanifest b/example/game.appmanifest index 251e444..9fd8707 100644 --- a/example/game.appmanifest +++ b/example/game.appmanifest @@ -1,71 +1,76 @@ platforms: armv7-ios: context: - excludeLibs: [physics, LinearMath, BulletDynamics, BulletCollision, Box2D, record, vpx, profilerext, liveupdate] - excludeSymbols: [ProfilerExt] - libs: [physics_null, record_null, profilerext_null, liveupdate_null] + excludeLibs: [liveupdate, physics, LinearMath, BulletDynamics, BulletCollision, Box2D, script_box2d, record, vpx] + excludeSymbols: [ScriptBox2DExt] + libs: [physics_null, liveupdate_null, record_null] linkFlags: [] arm64-ios: context: - excludeLibs: [physics, LinearMath, BulletDynamics, BulletCollision, Box2D, record, vpx, profilerext, liveupdate] - excludeSymbols: [ProfilerExt] - libs: [physics_null, record_null, profilerext_null, liveupdate_null] + excludeLibs: [liveupdate, physics, LinearMath, BulletDynamics, BulletCollision, Box2D, script_box2d, record, vpx] + excludeSymbols: [ScriptBox2DExt] + libs: [physics_null, liveupdate_null, record_null] linkFlags: [] x86_64-ios: context: - excludeLibs: [physics, LinearMath, BulletDynamics, BulletCollision, Box2D, record, vpx, profilerext, liveupdate] - excludeSymbols: [ProfilerExt] - libs: [physics_null, record_null, profilerext_null, liveupdate_null] + excludeLibs: [liveupdate, physics, LinearMath, BulletDynamics, BulletCollision, Box2D, script_box2d, record, vpx] + excludeSymbols: [ScriptBox2DExt] + libs: [physics_null, liveupdate_null, record_null] linkFlags: [] armv7-android: context: - excludeLibs: [physics, LinearMath, BulletDynamics, BulletCollision, Box2D, record, vpx, profilerext, liveupdate] + excludeLibs: [liveupdate, physics, LinearMath, BulletDynamics, BulletCollision, Box2D, script_box2d, record, vpx] excludeJars: [] - excludeSymbols: [ProfilerExt] - libs: [physics_null, record_null, profilerext_null, liveupdate_null] + excludeSymbols: [ScriptBox2DExt] + libs: [physics_null, liveupdate_null, record_null] linkFlags: [] arm64-android: context: - excludeLibs: [physics, LinearMath, BulletDynamics, BulletCollision, Box2D, record, vpx, profilerext, liveupdate] + excludeLibs: [liveupdate, physics, LinearMath, BulletDynamics, BulletCollision, Box2D, script_box2d, record, vpx] excludeJars: [] - excludeSymbols: [ProfilerExt] - libs: [physics_null, record_null, profilerext_null, liveupdate_null] + excludeSymbols: [ScriptBox2DExt] + libs: [physics_null, liveupdate_null, record_null] linkFlags: [] + arm64-osx: + context: + excludeLibs: [physics, LinearMath, BulletDynamics, BulletCollision, Box2D, script_box2d, record, vpx, liveupdate] + excludeSymbols: [ScriptBox2DExt] + libs: [physics_null, record_null, liveupdate_null] x86_64-osx: context: - excludeLibs: [physics, LinearMath, BulletDynamics, BulletCollision, Box2D, record, vpx, profilerext, liveupdate] - excludeSymbols: [ProfilerExt] - libs: [physics_null, record_null, profilerext_null, liveupdate_null] + excludeLibs: [liveupdate, physics, LinearMath, BulletDynamics, BulletCollision, Box2D, script_box2d, record, vpx] + excludeSymbols: [ScriptBox2DExt] + libs: [physics_null, liveupdate_null, record_null] linkFlags: [] x86_64-linux: context: - excludeLibs: [physics, LinearMath, BulletDynamics, BulletCollision, Box2D, record, vpx, profilerext, liveupdate] - excludeSymbols: [ProfilerExt] - libs: [physics_null, record_null, profilerext_null, liveupdate_null] + excludeLibs: [liveupdate, physics, LinearMath, BulletDynamics, BulletCollision, Box2D, script_box2d, record, vpx] + excludeSymbols: [ScriptBox2DExt] + libs: [physics_null, liveupdate_null, record_null] linkFlags: [] x86-win32: context: - excludeLibs: [libphysics, libLinearMath, libBulletDynamics, libBulletCollision, libBox2D, librecord, vpx, libprofilerext, libliveupdate] - excludeSymbols: [ProfilerExt] - libs: [libphysics_null.lib, librecord_null.lib, libprofilerext_null.lib, libliveupdate_null.lib] + excludeLibs: [libliveupdate, libphysics, libLinearMath, libBulletDynamics, libBulletCollision, libBox2D, libscript_box2d, librecord, vpx] + excludeSymbols: [ScriptBox2DExt] + libs: [libphysics_null.lib, libliveupdate_null.lib, librecord_null.lib] linkFlags: [] x86_64-win32: context: - excludeLibs: [libphysics, libLinearMath, libBulletDynamics, libBulletCollision, libBox2D, librecord, vpx, libprofilerext, libliveupdate] - excludeSymbols: [ProfilerExt] - libs: [libphysics_null.lib, librecord_null.lib, libprofilerext_null.lib, libliveupdate_null.lib] + excludeLibs: [libliveupdate, libphysics, libLinearMath, libBulletDynamics, libBulletCollision, libBox2D, libscript_box2d, librecord, vpx] + excludeSymbols: [ScriptBox2DExt] + libs: [libphysics_null.lib, libliveupdate_null.lib, librecord_null.lib] linkFlags: [] js-web: context: - excludeLibs: [physics, LinearMath, BulletDynamics, BulletCollision, Box2D, record, vpx, profilerext, liveupdate] + excludeLibs: [liveupdate, physics, LinearMath, BulletDynamics, BulletCollision, Box2D, script_box2d, record, vpx] excludeJsLibs: [] - excludeSymbols: [ProfilerExt] - libs: [physics_null, record_null, profilerext_null, liveupdate_null] + excludeSymbols: [ScriptBox2DExt] + libs: [physics_null, liveupdate_null, record_null] linkFlags: [] wasm-web: context: - excludeLibs: [physics, LinearMath, BulletDynamics, BulletCollision, Box2D, record, vpx, profilerext, liveupdate] + excludeLibs: [liveupdate, physics, LinearMath, BulletDynamics, BulletCollision, Box2D, script_box2d, record, vpx] excludeJsLibs: [] - excludeSymbols: [ProfilerExt] - libs: [physics_null, record_null, profilerext_null, liveupdate_null] + excludeSymbols: [ScriptBox2DExt] + libs: [physics_null, liveupdate_null, record_null] linkFlags: [] diff --git a/game.project b/game.project index ef1cc91..3df4888 100644 --- a/game.project +++ b/game.project @@ -1,5 +1,5 @@ [bootstrap] -main_collection = /example/example.collectionc +main_collection = /test/test.collectionc [script] shared_state = 1 @@ -15,7 +15,7 @@ high_dpi = 1 title = druid version = 0.11.0 publisher = Insality -developer = Insality +developer = Maksim Tuprikov dependencies#0 = https://github.com/insalitygames/deftest/archive/master.zip dependencies#1 = https://github.com/britzl/monarch/archive/refs/tags/3.3.0.zip diff --git a/media/druid_hero.png b/media/druid_hero.png new file mode 100644 index 0000000..2f55dfd Binary files /dev/null and b/media/druid_hero.png differ diff --git a/media/druid_logo.png b/media/druid_logo.png index 6b5174b..4f3c65c 100644 Binary files a/media/druid_logo.png and b/media/druid_logo.png differ diff --git a/media/druid_thumb.png b/media/druid_thumb.png new file mode 100644 index 0000000..4601d35 Binary files /dev/null and b/media/druid_thumb.png differ diff --git a/settings_deployer b/settings_deployer index 92e4328..07634c7 100644 --- a/settings_deployer +++ b/settings_deployer @@ -1,17 +1,17 @@ -#!/bin/bash - -# If true, it will check and download latest bob version. It will ignore bob_sha param -use_latest_bob=false - -# Set patch (last value after dot) game version value as total git commits count (1.2.0 -> 1.2.{commits_count}) -# You allow to get SHA commit from version via: git rev-list --all --reverse | sed -n {N}p -enable_incremental_version=true +# Path to bob folder. It will find and save new bob.jar files inside +bob_folder=./ # You can point bob version for project in format "filename:sha" -bob_sha="1.6.0:d9e9c49ab946c058f29a8b688c862d70f30e9c43" +bob_sha="181:fd1ad4c17bfdcd890ea7176f2672c35102384419" # Select Defold channel. Values: stable, beta, alpha bob_channel="stable" +# If true, it will check and download latest bob version. It will ignore bob_sha param +use_latest_bob=false + +# Select Defold build server +build_server="https://build.defold.com" + # Is need to build html report -is_build_html_report=true +is_build_html_report=true \ No newline at end of file diff --git a/unit_test.txt b/test/test.ini similarity index 100% rename from unit_test.txt rename to test/test.ini diff --git a/test/tests/test_button.lua b/test/tests/test_button.lua index 154803f..057135b 100644 --- a/test/tests/test_button.lua +++ b/test/tests/test_button.lua @@ -63,7 +63,7 @@ return function() assert(on_long_click_mock.calls == 0) druid:on_input(mock_input.click_pressed(10, 10)) - mock_time.elapse(0.5) + mock_time.elapse(1) druid:on_input(mock_input.click_released(20, 10)) assert(on_click_mock.calls == 1) @@ -144,14 +144,15 @@ return function() instance.on_hold_callback:subscribe(on_hold_callback) druid:on_input(mock_input.click_pressed(10, 10)) - mock_time.elapse(0.5) -- time between hold treshold and autorelease hold time - druid:on_input(mock_input.click_repeated(10, 10)) + mock_time.elapse(1) -- time between hold treshold and autorelease hold time + druid:on_input(mock_input.input_empty(10, 10)) + pprint(on_long_click_mock) assert(on_click_mock.calls == 0) - assert(on_hold_callback_mock.calls == 1) - assert(on_hold_callback_mock.params[1] == context) - assert(on_hold_callback_mock.params[2] == button_params) - assert(on_hold_callback_mock.params[3] == instance) + assert(on_long_click_mock.calls == 1) + assert(on_long_click_mock.params[1] == context) + assert(on_long_click_mock.params[2] == button_params) + assert(on_long_click_mock.params[3] == instance) druid:on_input(mock_input.click_released(10, 10)) @@ -257,8 +258,8 @@ return function() instance:set_enabled(false) local is_clicked_pressed = druid:on_input(mock_input.click_pressed(10, 10)) local is_clicked_released = druid:on_input(mock_input.click_released(10, 10)) - assert(is_clicked_pressed == false) - assert(is_clicked_released == false) + assert(is_clicked_pressed == true) + assert(is_clicked_released == true) assert(on_click_mock.calls == 0) assert(instance:is_enabled() == false) diff --git a/utils/annotations_manual.lua b/utils/annotations_manual.lua index d87b665..ab4169d 100644 --- a/utils/annotations_manual.lua +++ b/utils/annotations_manual.lua @@ -1,10 +1,14 @@ -- Manual Annotations -- +---@class druid.component: druid.base_component + ---@class druid.rich_text.metrics ---@field width number ---@field height number ---@field offset_x number|nil ---@field offset_y number|nil +---@field max_ascent number +---@field max_descent number ---@field node_size vector3|nil @For images only ---@class druid.rich_text.lines_metrics @@ -21,7 +25,7 @@ ---@field scale vector3 ---@field size vector3 ---@field metrics druid.rich_text.metrics ----@field pivot number @ The gui.PIVOT_* constant +---@field pivot userdata @ The gui.PIVOT_* constant ---@field text string ---@field shadow vector4 ---@field outline vector4 @@ -31,6 +35,9 @@ ---@field anchor number ---@field br boolean ---@field nobr boolean +---@field source_text string +---@field image_color vector4 +---@field text_color vector4 ---@class druid.rich_text.image ---@field texture string @@ -42,6 +49,7 @@ ---@field parent node ---@field size number ---@field fonts table +---@field scale vector3 ---@field color vector4 ---@field shadow vector4 ---@field outline vector4 @@ -49,11 +57,46 @@ ---@field image_pixel_grid_snap boolean ---@field combine_words boolean ---@field default_animation string ----@field node_prefab node ---@field text_prefab node +---@field adjust_scale number +---@field default_texture string +---@field is_multiline boolean +---@field text_leading number +---@field font hash +---@field width number +---@field height number ---@class GUITextMetrics ---@field width number ---@field height number ---@field max_ascent number ---@field max_descent number + +---@class utf8 +---@field len fun(s: string):number +---@field sub fun(s: string, start_index: number, length: number) +---@field reverse fun() +---@field char fun() +---@field unicode fun() +---@field gensub fun() +---@field byte fun() +---@field find fun() +---@field match fun(s: string, m: string) +---@field gmatch fun(s: string, m: string) +---@field gsub fun() +---@field dump fun() +---@field format fun() +---@field lower fun() +---@field upper fun() +---@field rep fun() + + +---Add generics to some functions. + +---Create new component. +---@generic T: druid.base_component +---@param self druid_instance +---@param component T Component module +---@param ... any Other component params to pass it to component:init function +---@return T Component instance +function druid_instance.new(self, component, ...) end \ No newline at end of file
  • Return current text adjust type
    get_text_index_by_width(self, width)Get chars count by width
    get_text_size(self, text) Calculate text width with font with respect to trailing space
    init(self, node, value[, adjust_type=downscale])init(self, node, value, adjust_type) The Text constructor