diff --git a/druid/extended/infinity_list.lua b/druid/extended/infinity_list.lua index d439820..9a5ac25 100644 --- a/druid/extended/infinity_list.lua +++ b/druid/extended/infinity_list.lua @@ -8,216 +8,217 @@ local M = component.create("infinity_list") function M:init(data_list, scroll, grid, create_function) - self.view_size = gui.get_size(scroll.view_node) - self.prefab_size = grid.node_size - self.druid = self:get_druid() - self.scroll = scroll - self.grid = grid - self.scroll:bind_grid(grid) + self.view_size = gui.get_size(scroll.view_node) + self.prefab_size = grid.node_size + self.druid = self:get_druid() + self.scroll = scroll + self.grid = grid + self.scroll:bind_grid(grid) - --- Current visual elements indexes - self.top_index = 1 - self.last_index = 1 + --- Current visual elements indexes + self.top_index = 1 + self.last_index = 1 - self._data = {} - self._data_first_index = false - self._data_last_index = false - self._data_length = 0 + self._data = {} + self._data_first_index = false + self._data_last_index = false + self._data_length = 0 - self.create_function = create_function + self.create_function = create_function - self._data_visual = {} + self._data_visual = {} - self.scroll.on_scroll:subscribe(self._check_elements, self) + self.scroll.on_scroll:subscribe(self._check_elements, self) - self:set_data(data_list) + self:set_data(data_list) end function M:on_remove() - self.scroll.on_scroll:unsubscribe(self._check_elements, self) + self.scroll.on_scroll:unsubscribe(self._check_elements, self) end function M:set_data(data_list) - self._data = data_list - self:_update_data_info() - self:_refresh() + self._data = data_list + self:_update_data_info() + self:_refresh() end function M:add(data, index, shift_policy) - index = index or self._data_last_index + 1 - shift_policy = shift_policy or const.SHIFT.RIGHT + index = index or self._data_last_index + 1 + shift_policy = shift_policy or const.SHIFT.RIGHT - if self._data[index] then - if shift_policy == const.SHIFT.RIGHT then - for i = self._data_last_index, index, -1 do - self._data[i + 1] = self._data[i] - end - end - if shift_policy == const.SHIFT.LEFT then - for i = self._data_first_index, index do - self._data[i - 1] = self._data[i] - end - end - end - self._data[index] = data - self:_update_data_info() - self:_check_elements() + if self._data[index] then + if shift_policy == const.SHIFT.RIGHT then + for i = self._data_last_index, index, -1 do + self._data[i + 1] = self._data[i] + end + end + if shift_policy == const.SHIFT.LEFT then + for i = self._data_first_index, index do + self._data[i - 1] = self._data[i] + end + end + end + self._data[index] = data + self:_update_data_info() + self:_check_elements() end function M:remove(index, shift_policy) - table.remove(self._data, index) - self:_refresh() + table.remove(self._data, index) + self:_refresh() end function M:remove_by_data(data, shift_policy) - local index = helper.contains(self._data, data) - if index then - table.remove(self._data, index) - self:_refresh() - end + local index = helper.contains(self._data, data) + if index then + table.remove(self._data, index) + self:_refresh() + end end function M:clear() - self._data = {} - self:_refresh() + self._data = {} + self:_refresh() end function M:get_first_index() - return self._data_first_index + return self._data_first_index end function M:get_last_index() - return self._data_last_index + return self._data_last_index end function M:get_length() - return self._data_length + return self._data_length end function M:get_index(data) - for index, value in pairs(self._data) do - if value == data then - return index - end - end - return nil + for index, value in pairs(self._data) do + if value == data then + return index + end + end + + return nil end function M:scroll_to_index(index) - self.top_index = helper.clamp(index, 1, #self._data) - self:_refresh() - self.scroll.on_scroll:trigger(self:get_context(), self) + self.top_index = helper.clamp(index, 1, #self._data) + self:_refresh() + self.scroll.on_scroll:trigger(self:get_context(), self) end function M:_add_at(index) - if self._data_visual[index] then - self:_remove_at(index) - end + if self._data_visual[index] then + self:_remove_at(index) + end - local node, instance = self.create_function(self._data[index], index) - self.grid:add(node, index, const.SHIFT.NO_SHIFT) - self._data_visual[index] = { - node = node, - component = instance - } + local node, instance = self.create_function(self._data[index], index) + self.grid:add(node, index, const.SHIFT.NO_SHIFT) + self._data_visual[index] = { + node = node, + component = instance + } end function M:_remove_at(index) - self.grid:remove(index, const.SHIFT.NO_SHIFT) + self.grid:remove(index, const.SHIFT.NO_SHIFT) - local node = self._data_visual[index].node - gui.delete_node(node) + local node = self._data_visual[index].node + gui.delete_node(node) - if self._data_visual[index].component then - self.druid:remove(self._data_visual[index].component) - end - self._data_visual[index] = nil + if self._data_visual[index].component then + self.druid:remove(self._data_visual[index].component) + end + self._data_visual[index] = nil end function M:_refresh() - for index, _ in pairs(self._data_visual) do - self:_remove_at(index) - end - self:_check_elements() + for index, _ in pairs(self._data_visual) do + self:_remove_at(index) + end + self:_check_elements() end function M:_check_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 - end - end + 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 - self:_check_elements_from(self.top_index - 1, -1) - self:_check_elements_from(self.top_index, 1) + self:_check_elements_from(self.top_index - 1, -1) + self:_check_elements_from(self.top_index, 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 + 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 end function M:_check_elements_from(index, step) - local is_outside = false - while not is_outside do - if not self._data[index] then - break - end + local is_outside = false + while not is_outside do + if not self._data[index] then + break + end - if not self._data_visual[index] then - self:_add_at(index) - end + if not self._data_visual[index] then + self:_add_at(index) + end - if not self.scroll:is_node_in_view(self._data_visual[index].node) then - is_outside = true + 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 + -- 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 + index = index + step + end end function M:_update_data_info() - self._data_first_index = false - self._data_last_index = false - self._data_length = 0 + 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 + for index, data in pairs(self._data) do + self._data_first_index = math.min(self._data_first_index or index, index) + self._data_last_index = math.max(self._data_last_index or index, index) + self._data_length = self._data_length + 1 + end - if self._data_length == 0 then - self._data_first_index = 1 - self._data_last_index = 1 - end + if self._data_length == 0 then + self._data_first_index = 1 + self._data_last_index = 1 + end end diff --git a/example/page/infinity_page.lua b/example/page/infinity_page.lua index b2f305e..132d951 100644 --- a/example/page/infinity_page.lua +++ b/example/page/infinity_page.lua @@ -1,175 +1,175 @@ - local M = {} + local M = {} local function create_infinity_instance(self, record, index) - local instance = gui.clone_tree(self.infinity_prefab) - gui.set_enabled(instance["infinity_prefab"], true) - gui.set_text(instance["infinity_text"], "Record " .. record) + local instance = gui.clone_tree(self.infinity_prefab) + gui.set_enabled(instance["infinity_prefab"], true) + gui.set_text(instance["infinity_text"], "Record " .. record) - local button = self.druid:new_button(instance["infinity_prefab"], function() - print("Infinity click on", record) - self.infinity_list:add(self.infinity_list:get_length() + 1) - end) - button.on_long_click:subscribe(function() - -- self.infinity_list:remove_by_data(record) - end) + local button = self.druid:new_button(instance["infinity_prefab"], function() + print("Infinity click on", record) + self.infinity_list:add(self.infinity_list:get_length() + 1) + end) + button.on_long_click:subscribe(function() + -- self.infinity_list:remove_by_data(record) + end) - return instance["infinity_prefab"], button + return instance["infinity_prefab"], button end local function create_infinity_instance_hor(self, record, index) - local instance = gui.clone_tree(self.infinity_prefab) - gui.set_enabled(instance["infinity_prefab"], true) - gui.set_text(instance["infinity_text"], "Record " .. record) + local instance = gui.clone_tree(self.infinity_prefab) + gui.set_enabled(instance["infinity_prefab"], true) + gui.set_text(instance["infinity_text"], "Record " .. record) - local button = self.druid:new_button(instance["infinity_prefab"], function() - print("Infinity click on", record) - -- self.infinity_list_hor:remove_by_data(record) - end) + local button = self.druid:new_button(instance["infinity_prefab"], function() + print("Infinity click on", record) + -- self.infinity_list_hor:remove_by_data(record) + end) - return instance["infinity_prefab"], button + return instance["infinity_prefab"], button end local function create_infinity_instance_small(self, record, index) - local instance = gui.clone_tree(self.infinity_prefab_small) - gui.set_enabled(instance["infinity_prefab_small"], true) - gui.set_text(instance["infinity_text_3"], record) + local instance = gui.clone_tree(self.infinity_prefab_small) + gui.set_enabled(instance["infinity_prefab_small"], true) + gui.set_text(instance["infinity_text_3"], record) - local button = self.druid:new_button(instance["infinity_prefab_small"], function() - print("Infinity click on", record) - -- self.infinity_list_small:remove_by_data(record) - end) - button:set_click_zone(self.infinity_scroll_3.view_node) + local button = self.druid:new_button(instance["infinity_prefab_small"], function() + print("Infinity click on", record) + -- self.infinity_list_small:remove_by_data(record) + end) + button:set_click_zone(self.infinity_scroll_3.view_node) - return instance["infinity_prefab_small"], button + return instance["infinity_prefab_small"], button end local function create_infinity_instance_dynamic(self, record, index) - local instance = gui.clone_tree(self.infinity_prefab_dynamic) - gui.set_enabled(instance["infinity_prefab_dynamic"], true) - gui.set_text(instance["infinity_text_dynamic"], "Record " .. record) + local instance = gui.clone_tree(self.infinity_prefab_dynamic) + gui.set_enabled(instance["infinity_prefab_dynamic"], true) + gui.set_text(instance["infinity_text_dynamic"], "Record " .. record) - gui.set_size(instance["infinity_prefab_dynamic"], vmath.vector3(200, 60 + index * 3, 0)) - local button = self.druid:new_button(instance["infinity_prefab_dynamic"], function() - print("Dynamic click on", record) - -- self.infinity_list_dynamic:remove_by_data(record) - end) - button:set_click_zone(self.infinity_scroll_dynamic.view_node) + gui.set_size(instance["infinity_prefab_dynamic"], vmath.vector3(200, 60 + index * 3, 0)) + local button = self.druid:new_button(instance["infinity_prefab_dynamic"], function() + print("Dynamic click on", record) + -- self.infinity_list_dynamic:remove_by_data(record) + end) + button:set_click_zone(self.infinity_scroll_dynamic.view_node) - return instance["infinity_prefab_dynamic"], button + return instance["infinity_prefab_dynamic"], button end local function create_infinity_instance_dynamic_hor(self, record, index) - local instance = gui.clone_tree(self.infinity_prefab_dynamic) - gui.set_enabled(instance["infinity_prefab_dynamic"], true) - gui.set_text(instance["infinity_text_dynamic"], "Record " .. record) + local instance = gui.clone_tree(self.infinity_prefab_dynamic) + gui.set_enabled(instance["infinity_prefab_dynamic"], true) + gui.set_text(instance["infinity_text_dynamic"], "Record " .. record) - gui.set_size(instance["infinity_prefab_dynamic"], vmath.vector3(150 + 2 * index, 60, 0)) - local button = self.druid:new_button(instance["infinity_prefab_dynamic"], function() - print("Dynamic click on", record) - -- self.infinity_list_dynamic_hor:remove_by_data(record) - end) - button:set_click_zone(self.infinity_scroll_dynamic_hor.view_node) + gui.set_size(instance["infinity_prefab_dynamic"], vmath.vector3(150 + 2 * index, 60, 0)) + local button = self.druid:new_button(instance["infinity_prefab_dynamic"], function() + print("Dynamic click on", record) + -- self.infinity_list_dynamic_hor:remove_by_data(record) + end) + button:set_click_zone(self.infinity_scroll_dynamic_hor.view_node) - return instance["infinity_prefab_dynamic"], button + return instance["infinity_prefab_dynamic"], button end local function setup_infinity_list(self) - local data = {} - for i = 1, 50 do - table.insert(data, i) - end + local data = {} + for i = 1, 50 do + table.insert(data, i) + end - self.infinity_list = self.druid:new_infinity_list(data, self.infinity_scroll, self.infinity_grid, function(record, index) - -- function should return gui_node, [druid_component] - local root, button = create_infinity_instance(self, record, index) - button:set_click_zone(self.infinity_scroll.view_node) - return root, button - end) + self.infinity_list = self.druid:new_infinity_list(data, self.infinity_scroll, self.infinity_grid, function(record, index) + -- function should return gui_node, [druid_component] + local root, button = create_infinity_instance(self, record, index) + button:set_click_zone(self.infinity_scroll.view_node) + return root, button + end) - self.infinity_list_hor = self.druid:new_infinity_list(data, self.infinity_scroll_hor, self.infinity_grid_hor, function(record, index) - -- function should return gui_node, [druid_component] - local root, button = create_infinity_instance_hor(self, record, index) - button:set_click_zone(self.infinity_scroll_hor.view_node) - return root, button - end) + self.infinity_list_hor = self.druid:new_infinity_list(data, self.infinity_scroll_hor, self.infinity_grid_hor, function(record, index) + -- function should return gui_node, [druid_component] + local root, button = create_infinity_instance_hor(self, record, index) + button:set_click_zone(self.infinity_scroll_hor.view_node) + return root, button + end) - -- scroll to some index - -- local pos = self.infinity_grid:get_pos(25) - -- self.infinity_scroll:scroll_to(pos, true) - -- timer.delay(1, false, function() - -- self.infinity_list:scroll_to_index(1) - -- end) + -- scroll to some index + -- local pos = self.infinity_grid:get_pos(25) + -- self.infinity_scroll:scroll_to(pos, true) + timer.delay(1, false, function() + self.infinity_list:scroll_to_index(25) + end) - self.infinity_list_small = self.druid:new_infinity_list(data, self.infinity_scroll_3, self.infinity_grid_3, function(record, index) - -- function should return gui_node, [druid_component] - return create_infinity_instance_small(self, record, index) - end) + self.infinity_list_small = self.druid:new_infinity_list(data, self.infinity_scroll_3, self.infinity_grid_3, function(record, index) + -- function should return gui_node, [druid_component] + return create_infinity_instance_small(self, record, index) + end) - self.infinity_list_dynamic = self.druid:new_infinity_list(data, self.infinity_scroll_dynamic, self.infinity_grid_dynamic, function(record, index) - -- function should return gui_node, [druid_component] - return create_infinity_instance_dynamic(self, record, index) - end) + self.infinity_list_dynamic = self.druid:new_infinity_list(data, self.infinity_scroll_dynamic, self.infinity_grid_dynamic, function(record, index) + -- function should return gui_node, [druid_component] + return create_infinity_instance_dynamic(self, record, index) + end) - self.infinity_list_dynamic_hor = self.druid:new_infinity_list(data, self.infinity_scroll_dynamic_hor, self.infinity_grid_dynamic_hor, function(record, index) - -- function should return gui_node, [druid_component] - return create_infinity_instance_dynamic_hor(self, record, index) - end) + self.infinity_list_dynamic_hor = self.druid:new_infinity_list(data, self.infinity_scroll_dynamic_hor, self.infinity_grid_dynamic_hor, function(record, index) + -- function should return gui_node, [druid_component] + return create_infinity_instance_dynamic_hor(self, record, index) + end) end local function toggle_stencil(self) - self._is_stencil = not self._is_stencil - local mode = self._is_stencil and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE - gui.set_clipping_mode(self.infinity_scroll.view_node, mode) - gui.set_clipping_mode(self.infinity_scroll_hor.view_node, mode) - gui.set_clipping_mode(self.infinity_scroll_3.view_node, mode) - gui.set_clipping_mode(self.infinity_scroll_dynamic.view_node, mode) - gui.set_clipping_mode(self.infinity_scroll_dynamic_hor.view_node, mode) + self._is_stencil = not self._is_stencil + local mode = self._is_stencil and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE + gui.set_clipping_mode(self.infinity_scroll.view_node, mode) + gui.set_clipping_mode(self.infinity_scroll_hor.view_node, mode) + gui.set_clipping_mode(self.infinity_scroll_3.view_node, mode) + gui.set_clipping_mode(self.infinity_scroll_dynamic.view_node, mode) + gui.set_clipping_mode(self.infinity_scroll_dynamic_hor.view_node, mode) end function M.setup_page(self) - self.druid:new_scroll("infinity_page", "infinity_page_content") + self.druid:new_scroll("infinity_page", "infinity_page_content") - self.infinity_prefab = gui.get_node("infinity_prefab") - self.infinity_prefab_small = gui.get_node("infinity_prefab_small") - self.infinity_prefab_dynamic = gui.get_node("infinity_prefab_dynamic") - gui.set_enabled(self.infinity_prefab, false) - gui.set_enabled(self.infinity_prefab_small, false) - gui.set_enabled(self.infinity_prefab_dynamic, false) + self.infinity_prefab = gui.get_node("infinity_prefab") + self.infinity_prefab_small = gui.get_node("infinity_prefab_small") + self.infinity_prefab_dynamic = gui.get_node("infinity_prefab_dynamic") + gui.set_enabled(self.infinity_prefab, false) + gui.set_enabled(self.infinity_prefab_small, false) + gui.set_enabled(self.infinity_prefab_dynamic, false) - self.infinity_scroll = self.druid:new_scroll("infinity_scroll_stencil", "infinity_scroll_content") - :set_horizontal_scroll(false) - self.infinity_grid = self.druid:new_static_grid("infinity_scroll_content", "infinity_prefab", 1) + self.infinity_scroll = self.druid:new_scroll("infinity_scroll_stencil", "infinity_scroll_content") + :set_horizontal_scroll(false) + self.infinity_grid = self.druid:new_static_grid("infinity_scroll_content", "infinity_prefab", 1) - self.infinity_scroll_hor = self.druid:new_scroll("infinity_scroll_stencil_hor", "infinity_scroll_content_hor") - :set_vertical_scroll(false) - self.infinity_grid_hor = self.druid:new_static_grid("infinity_scroll_content_hor", "infinity_prefab", 999) + self.infinity_scroll_hor = self.druid:new_scroll("infinity_scroll_stencil_hor", "infinity_scroll_content_hor") + :set_vertical_scroll(false) + self.infinity_grid_hor = self.druid:new_static_grid("infinity_scroll_content_hor", "infinity_prefab", 999) - self.infinity_scroll_3 = self.druid:new_scroll("infinity_scroll_3_stencil", "infinity_scroll_3_content") - :set_horizontal_scroll(false) - self.infinity_grid_3 = self.druid:new_static_grid("infinity_scroll_3_content", "infinity_prefab_small", 3) + self.infinity_scroll_3 = self.druid:new_scroll("infinity_scroll_3_stencil", "infinity_scroll_3_content") + :set_horizontal_scroll(false) + self.infinity_grid_3 = self.druid:new_static_grid("infinity_scroll_3_content", "infinity_prefab_small", 3) - self.infinity_scroll_dynamic = self.druid:new_scroll("infinity_scroll_stencil_dynamic", "infinity_scroll_content_dynamic") - :set_horizontal_scroll(false) - self.infinity_grid_dynamic = self.druid:new_dynamic_grid("infinity_scroll_content_dynamic") + self.infinity_scroll_dynamic = self.druid:new_scroll("infinity_scroll_stencil_dynamic", "infinity_scroll_content_dynamic") + :set_horizontal_scroll(false) + self.infinity_grid_dynamic = self.druid:new_dynamic_grid("infinity_scroll_content_dynamic") - self.infinity_scroll_dynamic_hor = self.druid:new_scroll("infinity_scroll_stencil_dynamic_hor", "infinity_scroll_content_dynamic_hor") - :set_vertical_scroll(false) - self.infinity_grid_dynamic_hor = self.druid:new_dynamic_grid("infinity_scroll_content_dynamic_hor") + self.infinity_scroll_dynamic_hor = self.druid:new_scroll("infinity_scroll_stencil_dynamic_hor", "infinity_scroll_content_dynamic_hor") + :set_vertical_scroll(false) + self.infinity_grid_dynamic_hor = self.druid:new_dynamic_grid("infinity_scroll_content_dynamic_hor") - self._is_stencil = true - self.druid:new_button("button_toggle_stencil/button", toggle_stencil) + self._is_stencil = true + self.druid:new_button("button_toggle_stencil/button", toggle_stencil) - setup_infinity_list(self) + setup_infinity_list(self) end