diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 65cd61a9..0a039c3c 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 8e0296c7..690997ac 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/README.md b/README.md index 329ab66a..84f0cb52 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. @@ -23,11 +23,19 @@ To integrate the **Druid** extension into your own project, add this project as 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)_**. @@ -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/docs_md/game_examples.md b/docs_md/game_examples.md deleted file mode 100644 index 9735b3db..00000000 --- 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 464d609a..44f95d85 100644 --- a/druid/annotations.lua +++ b/druid/annotations.lua @@ -588,6 +588,7 @@ 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) local druid__hover = {} @@ -998,9 +999,10 @@ function druid__rich_text.init(self, template, nodes) end 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 diff --git a/druid/base/button.lua b/druid/base/button.lua index 73c58a6f..f4068017 100755 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -343,6 +343,7 @@ function Button.on_input(self, action_id, action) 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 +366,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 +382,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,16 +402,16 @@ 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 diff --git a/druid/base/hover.lua b/druid/base/hover.lua index 607181f9..bbb7a0cf 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} diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index c75956c6..4d22d9bf 100755 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -216,6 +216,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 +261,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 +311,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 @@ -338,6 +351,20 @@ function Scroll.set_size(self, size, offset) end +--- Set scroll view size. +-- @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 + + --- Enable or disable scroll inert. -- If disabled, scroll through points (if exist) -- If no points, just simple drag without inertion @@ -583,14 +610,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) @@ -692,7 +719,7 @@ 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 @@ -704,7 +731,7 @@ function Scroll._update_hand_scroll(self, dt) 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 +773,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 +815,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 bfa48ad9..02b3f2a3 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -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) @@ -337,6 +341,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 diff --git a/druid/component.lua b/druid/component.lua index 4b277001..e5c438ad 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -336,7 +336,7 @@ 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 @@ -445,8 +445,8 @@ end -- @tparam BaseComponent self @{BaseComponent} -- @tparam component children 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 @@ -454,10 +454,11 @@ end -- @tparam BaseComponent self @{BaseComponent} -- @tparam component children 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 diff --git a/druid/custom/rich_input/rich_input.lua b/druid/custom/rich_input/rich_input.lua index 68d35606..a1310d08 100644 --- a/druid/custom/rich_input/rich_input.lua +++ b/druid/custom/rich_input/rich_input.lua @@ -24,6 +24,7 @@ --- local component = require("druid.component") +local input = require("druid.extended.input") local RichInput = component.create("druid.rich_input") @@ -74,7 +75,7 @@ function RichInput.init(self, template, nodes) self.druid = self:get_druid() self.root = self:get_node(SCHEME.ROOT) - self.input = self.druid:new_input(self:get_node(SCHEME.BUTTON), self:get_node(SCHEME.INPUT)) + self.input = self.druid:new(input, self:get_node(SCHEME.BUTTON), self:get_node(SCHEME.INPUT)) self.cursor = self:get_node(SCHEME.CURSOR) self.input:set_text("") diff --git a/druid/custom/rich_text/rich_text.lua b/druid/custom/rich_text/rich_text.lua index 8b542db9..dd2d802a 100644 --- a/druid/custom/rich_text/rich_text.lua +++ b/druid/custom/rich_text/rich_text.lua @@ -227,9 +227,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 diff --git a/druid/event.lua b/druid/event.lua index 3ad2b9ab..429f7117 100644 --- a/druid/event.lua +++ b/druid/event.lua @@ -102,7 +102,7 @@ function M.unsubscribe(self, callback, callback_context) return false end - tremove(self, event_index --[[@as number]]) + tremove(self, event_index) return true end diff --git a/druid/extended/data_list.lua b/druid/extended/data_list.lua index f3e5be15..88abf814 100644 --- a/druid/extended/data_list.lua +++ b/druid/extended/data_list.lua @@ -15,12 +15,6 @@ --- 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 - --- The current progress of scroll posititon -- @tfield number scroll_progress @@ -49,13 +43,11 @@ local DataList = component.create("data_list") -- @tparam StaticGrid|DynamicGrid 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 @@ -64,25 +56,21 @@ function DataList.init(self, scroll, grid, create_function) self._create_function = create_function 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 @@ -92,7 +80,7 @@ end -- @treturn druid.data_list Current DataList instance function DataList.set_data(self, data) self._data = data or {} - self:_update_data_info() + self.scroll:set_size(self.grid:get_size_for(#self._data)) self:_refresh() return self @@ -118,8 +106,7 @@ function DataList.add(self, data, index, shift_policy) 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 @@ -129,10 +116,8 @@ end -- @tparam number shift_policy The constant from const.SHIFT.* -- @local 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 @@ -145,7 +130,6 @@ 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 +139,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,13 +189,8 @@ 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 @@ -247,11 +204,11 @@ function DataList._add_at(self, 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 + component = instance, } + self.grid:add(node, index, const.SHIFT.NO_SHIFT) self.on_element_add:trigger(self:get_context(), index, node, instance) end @@ -264,12 +221,14 @@ end 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 instance = self._data_visual[index].component + gui.delete_node(node) if instance then - self.druid:remove(instance) + --- We should remove instance from druid that spawned component + instance._meta.druid:remove(instance) end self._data_visual[index] = nil @@ -281,102 +240,32 @@ end -- @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 - + local start_pos = -self.scroll.position + 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) - 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 - end - end + 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:_check_elements_from(self.top_index, -1) - self:_check_elements_from(self.top_index + 1, 1) + self.top_index = start_index + self.last_index = end_index + -- Clear from non range elements 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 + if index < start_index or index > end_index then + self:_remove_at(index) end + 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/styles/default/style.lua b/druid/styles/default/style.lua index 29921a66..7a61d0a2 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,19 +23,21 @@ 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) + gui.animate(node, gui.PROP_SCALE, self.start_scale, gui.EASING_OUTBACK, 0.24) + settings.play_sound(M.button.BTN_SOUND) end, @@ -84,8 +76,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 } diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 15ad41b7..6beeb168 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -193,10 +193,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 @@ -293,23 +289,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 +317,7 @@ function DruidInstance.remove(self, component) component:on_remove() end table.remove(all_components, i) + is_removed = true end end @@ -330,6 +331,8 @@ function DruidInstance.remove(self, component) end end end + + return is_removed end @@ -556,7 +559,7 @@ 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 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) diff --git a/settings_deployer b/settings_deployer index 92e4328e..07634c7e 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/tests/test.ini similarity index 100% rename from unit_test.txt rename to test/tests/test.ini