mirror of
https://github.com/Insality/druid.git
synced 2025-06-27 10:27:47 +02:00
Merge pull request #113 from Insality/43-infinity-scroll
43 infinity scroll
This commit is contained in:
commit
b19dc33b4a
@ -140,15 +140,27 @@ Desc
|
|||||||
- Add EmmyLua annotations. See how to use it FAQ
|
- Add EmmyLua annotations. See how to use it FAQ
|
||||||
- Lang text now can be initialized without default locale id
|
- Lang text now can be initialized without default locale id
|
||||||
- **#116** You can pass Text component in Input component instead of text node
|
- **#116** You can pass Text component in Input component instead of text node
|
||||||
- **#124** Add _set_click_zone_ functon to Scroll component (just link to Drag:set_click_zone inside scroll component)
|
- **#124** Add `Scroll:set_click_zone` function. This is just link to `Drag:set_click_zone` function inside scroll component.
|
||||||
- **#102** __[BREAKING]__ Removed _increase_input_priority_ component function. Use _component:set_input_priority_ function instead. The bigger priority value processed first. The value 10 is default for Druid components, the 100 value is maximum priority for acquire input in _drag_ and _input_ components
|
- **#102** __[BREAKING]__ Removed `component:increase_input_priority` component function. Use `component:set_input_priority` function instead. The bigger priority value processed first. The value 10 is default for Druid components, the 100 value is maximum priority for acquire input in _drag_ and _input_ components
|
||||||
-- Add constants for priorities: _const.PRIORITY_INPUT_, _const.PRIORITY_INPUT_HIGH_, _const.PRIORITY_INPUT_MAX_.
|
-- Add constants for priorities: _const.PRIORITY_INPUT_, _const.PRIORITY_INPUT_HIGH_, _const.PRIORITY_INPUT_MAX_.
|
||||||
-- __[BREAKING]__ If you use in you custom components interest: __component.ON_INPUT_HIGH__ you should replace it with __const.PRIORITY_INPUT_HIGH__ as third param, and place it with usual __component.ON_INPUT__. For example
|
-- __[BREAKING]__ If you use in you custom components interest: `component.ON_INPUT_HIGH` you should replace it with `const.PRIORITY_INPUT_HIGH` as third param, and place it with usual `component.ON_INPUT`. For example:
|
||||||
_before:_
|
_before:_
|
||||||
```lua
|
```lua
|
||||||
local Drag = component.create("drag", { component.ON_INPUT_HIGH })
|
local Drag = component.create("drag", { component.ON_INPUT_HIGH })
|
||||||
```
|
```
|
||||||
_after:_
|
_after:_
|
||||||
```lua
|
```lua
|
||||||
local Drag = component.create("drag", { component.ON_INPUT }, const.PRIORITY_INPUT_HIGH)
|
local Drag = component.create("drag", { component.ON_INPUT }, const.PRIORITY_INPUT_HIGH)
|
||||||
```
|
```
|
||||||
|
- **#123** Add scroll for Scroll component via mouse wheel or touchpad:
|
||||||
|
-- Added Scroll style params: `WHEEL_SCROLL_SPEED`, `WHEEL_SCROLL_INVERTED`
|
||||||
|
-- Mouse scroll working when cursor is hover on scroll view node
|
||||||
|
-- Vertical scroll have more priority than horizontal
|
||||||
|
-- Fix: When Hover component node became disabled, reset hover state (throw on_hover and on_mouse_hover events)
|
||||||
|
-- By default mouse scroll is disabled
|
||||||
|
-- This is basic implementation, it is work not perfect
|
||||||
|
- **#43** Add Data List Druid extended component. Component used to manage huge amount of data to make stuff like "infinity" scroll.
|
||||||
|
- Add context argument to Druid Event. You can pass this argument to forward it first in your callbacks (for example - object context)
|
||||||
|
- __[BREAKING]__ Add _SHIFT_POLICY_ for _Static_ and _Dynamic_ Grids. It mean how nodes will be shifted if you append data between nodes. There are `const.SHIFT.RIGHT`, `const.SHIFT.LEFT` and `const.SHIFT.NO_SHIFT`.
|
||||||
|
-- Please check your `StaticGrid:remove` and `DynamicGrid:remove` functions
|
||||||
|
|
||||||
|
@ -71,8 +71,10 @@ local function end_touch(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
self.is_drag = false
|
self.is_drag = false
|
||||||
self.is_touch = false
|
if self.is_touch then
|
||||||
self.on_touch_end:trigger(self:get_context())
|
self.is_touch = false
|
||||||
|
self.on_touch_end:trigger(self:get_context())
|
||||||
|
end
|
||||||
self:reset_input_priority()
|
self:reset_input_priority()
|
||||||
self.touch_id = 0
|
self.touch_id = 0
|
||||||
end
|
end
|
||||||
|
@ -40,11 +40,14 @@ function Hover.on_input(self, action_id, action)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Disable nil (it's mouse) hover or mobile platforms
|
||||||
if not action_id and helper.is_mobile() then
|
if not action_id and helper.is_mobile() then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if not helper.is_enabled(self.node) or not self._is_enabled then
|
if not helper.is_enabled(self.node) or not self._is_enabled then
|
||||||
|
self:set_hover(false)
|
||||||
|
self:set_mouse_hover(false)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -54,10 +54,11 @@
|
|||||||
|
|
||||||
|
|
||||||
local Event = require("druid.event")
|
local Event = require("druid.event")
|
||||||
|
local const = require("druid.const")
|
||||||
local helper = require("druid.helper")
|
local helper = require("druid.helper")
|
||||||
local component = require("druid.component")
|
local component = require("druid.component")
|
||||||
|
|
||||||
local Scroll = component.create("scroll", { component.ON_UPDATE, component.ON_LAYOUT_CHANGE })
|
local Scroll = component.create("scroll", { component.ON_INPUT, component.ON_UPDATE, component.ON_LAYOUT_CHANGE })
|
||||||
|
|
||||||
|
|
||||||
local function inverse_lerp(min, max, current)
|
local function inverse_lerp(min, max, current)
|
||||||
@ -68,14 +69,17 @@ end
|
|||||||
--- Update vector with next conditions:
|
--- Update vector with next conditions:
|
||||||
-- Field x have to <= field z
|
-- Field x have to <= field z
|
||||||
-- Field y have to <= field w
|
-- Field y have to <= field w
|
||||||
local function get_border_vector(vector)
|
local function get_border_vector(vector, offset)
|
||||||
if vector.x > vector.z then
|
if vector.x > vector.z then
|
||||||
vector.x, vector.z = vector.z, vector.x
|
vector.x, vector.z = vector.z, vector.x
|
||||||
end
|
end
|
||||||
if vector.y > vector.w then
|
if vector.y > vector.w then
|
||||||
vector.y, vector.w = vector.w, vector.y
|
vector.y, vector.w = vector.w, vector.y
|
||||||
end
|
end
|
||||||
|
vector.x = vector.x - offset.x
|
||||||
|
vector.z = vector.z - offset.x
|
||||||
|
vector.y = vector.y - offset.y
|
||||||
|
vector.w = vector.w - offset.y
|
||||||
return vector
|
return vector
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -99,6 +103,8 @@ end
|
|||||||
-- @tfield[opt=0.2] number ANIM_SPEED Scroll gui.animation speed for scroll_to function
|
-- @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=0] number EXTRA_STRETCH_SIZE extra size in pixels outside of scroll (stretch effect)
|
||||||
-- @tfield[opt=false] bool SMALL_CONTENT_SCROLL If true, content node with size less than view node size can be scrolled
|
-- @tfield[opt=false] bool SMALL_CONTENT_SCROLL If true, content node with size less than view node size can be scrolled
|
||||||
|
-- @tfield[opt=0] bool WHEEL_SCROLL_SPEED The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling
|
||||||
|
-- @tfield[opt=false] bool WHEEL_SCROLL_INVERTED If true, invert direction for touchpad and mouse wheel scroll
|
||||||
function Scroll.on_style_change(self, style)
|
function Scroll.on_style_change(self, style)
|
||||||
self.style = {}
|
self.style = {}
|
||||||
self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0
|
self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0
|
||||||
@ -112,6 +118,8 @@ function Scroll.on_style_change(self, style)
|
|||||||
self.style.INERT_SPEED = style.INERT_SPEED or 30
|
self.style.INERT_SPEED = style.INERT_SPEED or 30
|
||||||
self.style.POINTS_DEADZONE = style.POINTS_DEADZONE or 20
|
self.style.POINTS_DEADZONE = style.POINTS_DEADZONE or 20
|
||||||
self.style.SMALL_CONTENT_SCROLL = style.SMALL_CONTENT_SCROLL or false
|
self.style.SMALL_CONTENT_SCROLL = style.SMALL_CONTENT_SCROLL or false
|
||||||
|
self.style.WHEEL_SCROLL_SPEED = style.WHEEL_SCROLL_SPEED or 0
|
||||||
|
self.style.WHEEL_SCROLL_INVERTED = style.WHEEL_SCROLL_INVERTED or false
|
||||||
|
|
||||||
self._is_inert = not (self.style.FRICT == 0 or
|
self._is_inert = not (self.style.FRICT == 0 or
|
||||||
self.style.FRICT_HOLD == 0 or
|
self.style.FRICT_HOLD == 0 or
|
||||||
@ -129,6 +137,8 @@ function Scroll.init(self, view_node, content_node)
|
|||||||
self.view_node = self:get_node(view_node)
|
self.view_node = self:get_node(view_node)
|
||||||
self.content_node = self:get_node(content_node)
|
self.content_node = self:get_node(content_node)
|
||||||
|
|
||||||
|
self.view_size = vmath.mul_per_elem(gui.get_size(self.view_node), gui.get_scale(self.view_node))
|
||||||
|
|
||||||
self.position = gui.get_position(self.content_node)
|
self.position = gui.get_position(self.content_node)
|
||||||
self.target_position = vmath.vector3(self.position)
|
self.target_position = vmath.vector3(self.position)
|
||||||
self.inertion = vmath.vector3(0)
|
self.inertion = vmath.vector3(0)
|
||||||
@ -137,6 +147,10 @@ function Scroll.init(self, view_node, content_node)
|
|||||||
self.drag.on_touch_start:subscribe(self._on_touch_start)
|
self.drag.on_touch_start:subscribe(self._on_touch_start)
|
||||||
self.drag.on_touch_end:subscribe(self._on_touch_end)
|
self.drag.on_touch_end:subscribe(self._on_touch_end)
|
||||||
|
|
||||||
|
self.hover = self.druid:new_hover(view_node)
|
||||||
|
self.hover.on_mouse_hover:subscribe(self._on_mouse_hover)
|
||||||
|
self._is_mouse_hover = false
|
||||||
|
|
||||||
self.on_scroll = Event()
|
self.on_scroll = Event()
|
||||||
self.on_scroll_to = Event()
|
self.on_scroll_to = Event()
|
||||||
self.on_point_scroll = Event()
|
self.on_point_scroll = Event()
|
||||||
@ -144,10 +158,12 @@ function Scroll.init(self, view_node, content_node)
|
|||||||
self.selected = nil
|
self.selected = nil
|
||||||
self.is_animate = false
|
self.is_animate = false
|
||||||
|
|
||||||
|
self._offset = vmath.vector3(0)
|
||||||
self._is_horizontal_scroll = true
|
self._is_horizontal_scroll = true
|
||||||
self._is_vertical_scroll = true
|
self._is_vertical_scroll = true
|
||||||
self._grid_on_change = nil
|
self._grid_on_change = nil
|
||||||
self._grid_on_change_callback = nil
|
self._grid_on_change_callback = nil
|
||||||
|
self._outside_offset_vector = vmath.vector3(0)
|
||||||
|
|
||||||
self:_update_size()
|
self:_update_size()
|
||||||
end
|
end
|
||||||
@ -159,6 +175,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
function Scroll.update(self, dt)
|
function Scroll.update(self, dt)
|
||||||
|
self:_update_params(dt)
|
||||||
if self.drag.is_drag then
|
if self.drag.is_drag then
|
||||||
self:_update_hand_scroll(dt)
|
self:_update_hand_scroll(dt)
|
||||||
else
|
else
|
||||||
@ -167,6 +184,11 @@ function Scroll.update(self, dt)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Scroll.on_input(self, action_id, action)
|
||||||
|
return self:_process_scroll_wheel(action_id, action)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function Scroll.on_remove(self)
|
function Scroll.on_remove(self)
|
||||||
self:bind_grid(nil)
|
self:bind_grid(nil)
|
||||||
end
|
end
|
||||||
@ -260,8 +282,12 @@ end
|
|||||||
-- It will change content gui node size
|
-- It will change content gui node size
|
||||||
-- @tparam Scroll self
|
-- @tparam Scroll self
|
||||||
-- @tparam vector3 size The new size for content node
|
-- @tparam vector3 size The new size for content node
|
||||||
|
-- @tparam vector3 offset Offset value to set, where content is starts
|
||||||
-- @treturn druid.scroll Current scroll instance
|
-- @treturn druid.scroll Current scroll instance
|
||||||
function Scroll.set_size(self, size)
|
function Scroll.set_size(self, size, offset)
|
||||||
|
if offset then
|
||||||
|
self._offset = offset
|
||||||
|
end
|
||||||
gui.set_size(self.content_node, size)
|
gui.set_size(self.content_node, size)
|
||||||
self:_update_size()
|
self:_update_size()
|
||||||
|
|
||||||
@ -351,6 +377,28 @@ function Scroll.set_vertical_scroll(self, state)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check node if it visible now on scroll.
|
||||||
|
-- Extra border is not affected. Return true for elements in extra scroll zone
|
||||||
|
-- @tparam Scroll self
|
||||||
|
-- @tparma node node The node to check
|
||||||
|
-- @treturn boolean True, if node in visible scroll area
|
||||||
|
function Scroll.is_node_in_view(self, node)
|
||||||
|
local node_border = helper.get_border(node, gui.get_position(node))
|
||||||
|
local view_border = helper.get_border(self.view_node, -(self.position - self._outside_offset_vector))
|
||||||
|
|
||||||
|
-- Check is vertical outside (Left or Right):
|
||||||
|
if node_border.z < view_border.x or node_border.x > view_border.z then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check is horizontal outside (Up or Down):
|
||||||
|
if node_border.w > view_border.y or node_border.y < view_border.w then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Bind the grid component (Static or Dynamic) to recalculate
|
--- Bind the grid component (Static or Dynamic) to recalculate
|
||||||
-- scroll size on grid changes
|
-- scroll size on grid changes
|
||||||
@ -371,9 +419,9 @@ function Scroll.bind_grid(self, grid)
|
|||||||
|
|
||||||
self._grid_on_change = grid.on_change_items
|
self._grid_on_change = grid.on_change_items
|
||||||
self._grid_on_change_callback = self._grid_on_change:subscribe(function()
|
self._grid_on_change_callback = self._grid_on_change:subscribe(function()
|
||||||
self:set_size(grid:get_size())
|
self:set_size(grid:get_size(), grid:get_offset())
|
||||||
end)
|
end)
|
||||||
self:set_size(grid:get_size())
|
self:set_size(grid:get_size(), grid:get_offset())
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@ -436,19 +484,23 @@ function Scroll._check_soft_zone(self)
|
|||||||
|
|
||||||
-- Right border (minimum x)
|
-- Right border (minimum x)
|
||||||
if target.x < border.x then
|
if target.x < border.x then
|
||||||
target.x = helper.step(target.x, border.x, math.abs(target.x - border.x) * speed)
|
local step = math.max(math.abs(target.x - border.x) * speed, 1)
|
||||||
|
target.x = helper.step(target.x, border.x, step)
|
||||||
end
|
end
|
||||||
-- Left border (maximum x)
|
-- Left border (maximum x)
|
||||||
if target.x > border.z then
|
if target.x > border.z then
|
||||||
target.x = helper.step(target.x, border.z, math.abs(target.x - border.z) * speed)
|
local step = math.max(math.abs(target.x - border.z) * speed, 1)
|
||||||
|
target.x = helper.step(target.x, border.z, step)
|
||||||
end
|
end
|
||||||
-- Top border (maximum y)
|
-- Top border (maximum y)
|
||||||
if target.y < border.y then
|
if target.y < border.y then
|
||||||
target.y = helper.step(target.y, border.y, math.abs(target.y - border.y) * speed)
|
local step = math.max(math.abs(target.y - border.y) * speed, 1)
|
||||||
|
target.y = helper.step(target.y, border.y, step)
|
||||||
end
|
end
|
||||||
-- Bot border (minimum y)
|
-- Bot border (minimum y)
|
||||||
if target.y > border.w then
|
if target.y > border.w then
|
||||||
target.y = helper.step(target.y, border.w, math.abs(target.y - border.w) * speed)
|
local step = math.max(math.abs(target.y - border.w) * speed, 1)
|
||||||
|
target.y = helper.step(target.y, border.w, step)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -539,11 +591,11 @@ end
|
|||||||
function Scroll._check_threshold(self)
|
function Scroll._check_threshold(self)
|
||||||
local is_stopped = false
|
local is_stopped = false
|
||||||
|
|
||||||
if self.inertion.x ~= 0 and math.abs(self.inertion.x) < self.style.INERT_THRESHOLD then
|
if math.abs(self.inertion.x) < self.style.INERT_THRESHOLD then
|
||||||
is_stopped = true
|
is_stopped = true
|
||||||
self.inertion.x = 0
|
self.inertion.x = 0
|
||||||
end
|
end
|
||||||
if self.inertion.y ~= 0 and math.abs(self.inertion.y) < self.style.INERT_THRESHOLD then
|
if math.abs(self.inertion.y) < self.style.INERT_THRESHOLD then
|
||||||
is_stopped = true
|
is_stopped = true
|
||||||
self.inertion.y = 0
|
self.inertion.y = 0
|
||||||
end
|
end
|
||||||
@ -601,12 +653,11 @@ end
|
|||||||
|
|
||||||
function Scroll._update_size(self)
|
function Scroll._update_size(self)
|
||||||
local view_border = helper.get_border(self.view_node)
|
local view_border = helper.get_border(self.view_node)
|
||||||
local view_size = vmath.mul_per_elem(gui.get_size(self.view_node), gui.get_scale(self.view_node))
|
|
||||||
|
|
||||||
local content_border = helper.get_border(self.content_node)
|
local content_border = helper.get_border(self.content_node)
|
||||||
local content_size = vmath.mul_per_elem(gui.get_size(self.content_node), gui.get_scale(self.content_node))
|
local content_size = vmath.mul_per_elem(gui.get_size(self.content_node), gui.get_scale(self.content_node))
|
||||||
|
|
||||||
self.available_pos = get_border_vector(view_border - content_border)
|
self.available_pos = get_border_vector(view_border - content_border, self._offset)
|
||||||
self.available_size = get_size_vector(self.available_pos)
|
self.available_size = get_size_vector(self.available_pos)
|
||||||
|
|
||||||
self.drag.can_x = self.available_size.x > 0 and self._is_horizontal_scroll
|
self.drag.can_x = self.available_size.x > 0 and self._is_horizontal_scroll
|
||||||
@ -619,25 +670,80 @@ function Scroll._update_size(self)
|
|||||||
local stretch_size = self.style.EXTRA_STRETCH_SIZE
|
local stretch_size = self.style.EXTRA_STRETCH_SIZE
|
||||||
|
|
||||||
if self.drag.can_x then
|
if self.drag.can_x then
|
||||||
local sign = content_size.x > view_size.x and 1 or -1
|
local sign = content_size.x > self.view_size.x and 1 or -1
|
||||||
content_border_extra.x = content_border_extra.x - stretch_size * sign
|
content_border_extra.x = content_border_extra.x - stretch_size * sign
|
||||||
content_border_extra.z = content_border_extra.z + stretch_size * sign
|
content_border_extra.z = content_border_extra.z + stretch_size * sign
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.drag.can_y then
|
if self.drag.can_y then
|
||||||
local sign = content_size.y > view_size.y and 1 or -1
|
local sign = content_size.y > self.view_size.y and 1 or -1
|
||||||
content_border_extra.y = content_border_extra.y + stretch_size * sign
|
content_border_extra.y = content_border_extra.y + stretch_size * sign
|
||||||
content_border_extra.w = content_border_extra.w - stretch_size * sign
|
content_border_extra.w = content_border_extra.w - stretch_size * sign
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self.style.SMALL_CONTENT_SCROLL then
|
if not self.style.SMALL_CONTENT_SCROLL then
|
||||||
self.drag.can_x = content_size.x > view_size.x
|
self.drag.can_x = content_size.x > self.view_size.x
|
||||||
self.drag.can_y = content_size.y > view_size.y
|
self.drag.can_y = content_size.y > self.view_size.y
|
||||||
end
|
end
|
||||||
|
|
||||||
self.available_pos_extra = get_border_vector(view_border - content_border_extra)
|
self.available_pos_extra = get_border_vector(view_border - content_border_extra, self._offset)
|
||||||
self.available_size_extra = get_size_vector(self.available_pos_extra)
|
self.available_size_extra = get_size_vector(self.available_pos_extra)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Scroll._update_params(self, dt)
|
||||||
|
local t = self.target_position
|
||||||
|
local b = self.available_pos
|
||||||
|
|
||||||
|
self._outside_offset_vector.x = 0
|
||||||
|
self._outside_offset_vector.y = 0
|
||||||
|
|
||||||
|
-- Right border (minimum x)
|
||||||
|
if t.x < b.x then
|
||||||
|
self._outside_offset_vector.x = t.x - b.x
|
||||||
|
end
|
||||||
|
-- Left border (maximum x)
|
||||||
|
if t.x > b.z then
|
||||||
|
self._outside_offset_vector.x = t.x - b.z
|
||||||
|
end
|
||||||
|
-- Top border (minimum y)
|
||||||
|
if t.y < b.y then
|
||||||
|
self._outside_offset_vector.y = t.y - b.y
|
||||||
|
end
|
||||||
|
-- Bot border (maximum y)
|
||||||
|
if t.y > b.w then
|
||||||
|
self._outside_offset_vector.y = t.y - b.w
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Scroll._process_scroll_wheel(self, action_id, action)
|
||||||
|
if not self._is_mouse_hover or self.style.WHEEL_SCROLL_SPEED == 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if action_id ~= const.ACTION_SCROLL_UP and action_id ~= const.ACTION_SCROLL_DOWN then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local koef = (action_id == const.ACTION_SCROLL_UP) and 1 or -1
|
||||||
|
if self.style.WHEEL_SCROLL_INVERTED then
|
||||||
|
koef = -koef
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.drag.can_y then
|
||||||
|
self.inertion.y = (self.inertion.y + self.style.WHEEL_SCROLL_SPEED * koef) * self.style.FRICT_HOLD
|
||||||
|
else
|
||||||
|
self.inertion.x = (self.inertion.x + self.style.WHEEL_SCROLL_SPEED * koef) * self.style.FRICT_HOLD
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Scroll._on_mouse_hover(self, state)
|
||||||
|
self._is_mouse_hover = state
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
return Scroll
|
return Scroll
|
||||||
|
@ -49,6 +49,19 @@ local component = require("druid.component")
|
|||||||
local StaticGrid = component.create("static_grid", { component.ON_LAYOUT_CHANGE })
|
local StaticGrid = component.create("static_grid", { component.ON_LAYOUT_CHANGE })
|
||||||
|
|
||||||
|
|
||||||
|
local function _extend_border(border, pos, size, pivot)
|
||||||
|
local left = pos.x - size.x/2 - (size.x * pivot.x)
|
||||||
|
local right = pos.x + size.x/2 - (size.x * pivot.x)
|
||||||
|
local top = pos.y + size.y/2 - (size.y * pivot.y)
|
||||||
|
local bottom = pos.y - size.y/2 - (size.y * pivot.y)
|
||||||
|
|
||||||
|
border.x = math.min(border.x, left)
|
||||||
|
border.y = math.max(border.y, top)
|
||||||
|
border.z = math.max(border.z, right)
|
||||||
|
border.w = math.min(border.w, bottom)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Component init function
|
--- Component init function
|
||||||
-- @tparam StaticGrid self
|
-- @tparam StaticGrid self
|
||||||
-- @tparam node parent The gui node parent, where items will be placed
|
-- @tparam node parent The gui node parent, where items will be placed
|
||||||
@ -67,8 +80,15 @@ function StaticGrid.init(self, parent, element, in_row)
|
|||||||
self.node_size = gui.get_size(self._prefab)
|
self.node_size = gui.get_size(self._prefab)
|
||||||
self.node_pivot = const.PIVOTS[gui.get_pivot(self._prefab)]
|
self.node_pivot = const.PIVOTS[gui.get_pivot(self._prefab)]
|
||||||
|
|
||||||
|
self._grid_horizonal_offset = self.node_size.x * (self.in_row - 1) * self.anchor.x
|
||||||
|
self._zero_offset = vmath.vector3(
|
||||||
|
self.node_size.x * self.node_pivot.x - self.node_size.x * self.pivot.x - self._grid_horizonal_offset,
|
||||||
|
self.node_size.y * self.node_pivot.y - self.node_size.y * self.pivot.y,
|
||||||
|
0)
|
||||||
|
|
||||||
self.border = vmath.vector4(0) -- Current grid content size
|
self.border = vmath.vector4(0) -- Current grid content size
|
||||||
|
|
||||||
|
|
||||||
self.on_add_item = Event()
|
self.on_add_item = Event()
|
||||||
self.on_remove_item = Event()
|
self.on_remove_item = Event()
|
||||||
self.on_change_items = Event()
|
self.on_change_items = Event()
|
||||||
@ -88,8 +108,8 @@ function StaticGrid.get_pos(self, index)
|
|||||||
local row = math.ceil(index / self.in_row) - 1
|
local row = math.ceil(index / self.in_row) - 1
|
||||||
local col = (index - row * self.in_row) - 1
|
local col = (index - row * self.in_row) - 1
|
||||||
|
|
||||||
_temp_pos.x = col * self.node_size.x
|
_temp_pos.x = col * self.node_size.x + self._zero_offset.x
|
||||||
_temp_pos.y = -row * self.node_size.y
|
_temp_pos.y = -row * self.node_size.y + self._zero_offset.y
|
||||||
_temp_pos.z = 0
|
_temp_pos.z = 0
|
||||||
|
|
||||||
return _temp_pos
|
return _temp_pos
|
||||||
@ -145,25 +165,32 @@ end
|
|||||||
-- @tparam StaticGrid self
|
-- @tparam StaticGrid self
|
||||||
-- @tparam node item Gui node
|
-- @tparam node item Gui node
|
||||||
-- @tparam[opt] number index The item position. By default add as last item
|
-- @tparam[opt] number index The item position. By default add as last item
|
||||||
function StaticGrid.add(self, item, index)
|
-- @tparam[opt=SHIFT.RIGHT] number shift_policy How shift nodes, if required. See const.SHIFT
|
||||||
|
function StaticGrid.add(self, item, index, shift_policy)
|
||||||
|
shift_policy = shift_policy or const.SHIFT.RIGHT
|
||||||
index = index or ((self.last_index or 0) + 1)
|
index = index or ((self.last_index or 0) + 1)
|
||||||
|
|
||||||
if self.nodes[index] then
|
if self.nodes[index] then
|
||||||
-- Move nodes to right
|
if shift_policy == const.SHIFT.RIGHT then
|
||||||
for i = self.last_index, index, -1 do
|
for i = self.last_index, index, -1 do
|
||||||
self.nodes[i + 1] = self.nodes[i]
|
self.nodes[i + 1] = self.nodes[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if shift_policy == const.SHIFT.LEFT then
|
||||||
|
for i = self.first_index, index do
|
||||||
|
self.nodes[i - 1] = self.nodes[i]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.nodes[index] = item
|
self.nodes[index] = item
|
||||||
|
|
||||||
gui.set_parent(item, self.parent)
|
gui.set_parent(item, self.parent)
|
||||||
|
|
||||||
-- Add new item instantly in new pos. Break update function for correct positioning
|
-- Add new item instantly in new pos. Break update function for correct positioning
|
||||||
self:_update_indexes()
|
self:_update_indexes()
|
||||||
self:_update_borders()
|
self:_update_borders()
|
||||||
|
|
||||||
gui.set_position(item, self:get_pos(index) + self:_get_zero_offset())
|
gui.set_position(item, self:get_pos(index))
|
||||||
|
|
||||||
self:_update_pos()
|
self:_update_pos()
|
||||||
|
|
||||||
@ -175,19 +202,25 @@ end
|
|||||||
--- Remove the item from the grid. Note that gui node will be not deleted
|
--- Remove the item from the grid. Note that gui node will be not deleted
|
||||||
-- @tparam StaticGrid self
|
-- @tparam StaticGrid self
|
||||||
-- @tparam number index The grid node index to remove
|
-- @tparam number index The grid node index to remove
|
||||||
-- @tparam bool is_shift_nodes If true, will shift nodes left after index
|
-- @tparam[opt=SHIFT.RIGHT] number shift_policy How shift nodes, if required. See const.SHIFT
|
||||||
-- @treturn Node The deleted gui node from grid
|
-- @treturn Node The deleted gui node from grid
|
||||||
function StaticGrid.remove(self, index, is_shift_nodes)
|
function StaticGrid.remove(self, index, shift_policy)
|
||||||
|
shift_policy = shift_policy or const.SHIFT.RIGHT
|
||||||
assert(self.nodes[index], "No grid item at given index " .. index)
|
assert(self.nodes[index], "No grid item at given index " .. index)
|
||||||
|
|
||||||
local remove_node = self.nodes[index]
|
local remove_node = self.nodes[index]
|
||||||
self.nodes[index] = nil
|
self.nodes[index] = nil
|
||||||
|
|
||||||
if is_shift_nodes then
|
if shift_policy == const.SHIFT.RIGHT then
|
||||||
for i = index, self.last_index do
|
for i = index, self.last_index do
|
||||||
self.nodes[i] = self.nodes[i + 1]
|
self.nodes[i] = self.nodes[i + 1]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if shift_policy == const.SHIFT.LEFT then
|
||||||
|
for i = index, self.first_index, -1 do
|
||||||
|
self.nodes[i] = self.nodes[i - 1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
self:_update()
|
self:_update()
|
||||||
|
|
||||||
@ -209,6 +242,37 @@ function StaticGrid.get_size(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function StaticGrid.get_size_for(self, count)
|
||||||
|
if not count or count == 0 then
|
||||||
|
return vmath.vector3(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local border = vmath.vector4(math.huge, -math.huge, -math.huge, math.huge)
|
||||||
|
|
||||||
|
local size = self.node_size
|
||||||
|
local pivot = self.node_pivot
|
||||||
|
_extend_border(border, self:get_pos(1), size, pivot)
|
||||||
|
_extend_border(border, self:get_pos(count), size, pivot)
|
||||||
|
if count >= self.in_row then
|
||||||
|
_extend_border(border, self:get_pos(self.in_row), size, pivot)
|
||||||
|
end
|
||||||
|
|
||||||
|
return vmath.vector3(
|
||||||
|
border.z - border.x,
|
||||||
|
border.y - border.w,
|
||||||
|
0)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Return grid content borders
|
||||||
|
-- @tparam StaticGrid self
|
||||||
|
-- @treturn vector3 The grid content borders
|
||||||
|
function StaticGrid.get_borders(self)
|
||||||
|
return self.border
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Return array of all node positions
|
--- Return array of all node positions
|
||||||
-- @tparam StaticGrid self
|
-- @tparam StaticGrid self
|
||||||
-- @treturn vector3[] All grid node positions
|
-- @treturn vector3[] All grid node positions
|
||||||
@ -253,18 +317,19 @@ function StaticGrid.clear(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Return elements offset for correct posing nodes. Correct posing at
|
--- Return StaticGrid offset, where StaticGrid content starts.
|
||||||
-- parent pivot node (0:0) with adjusting of node sizes and anchoring
|
-- @tparam StaticGrid self The StaticGrid instance
|
||||||
-- @tparam StaticGrid self
|
-- @treturn vector3 The StaticGrid offset
|
||||||
-- @treturn vector3 The offset vector
|
function StaticGrid:get_offset()
|
||||||
-- @local
|
local borders = self:get_borders()
|
||||||
function StaticGrid._get_zero_offset(self)
|
local size = self:get_size()
|
||||||
-- zero offset: center pos - border size * anchor
|
|
||||||
return vmath.vector3(
|
local offset = vmath.vector3(
|
||||||
-((self.border.x + self.border.z)/2 + (self.border.z - self.border.x) * self.pivot.x),
|
(borders.z + borders.x)/2 + size.x * self.pivot.x,
|
||||||
-((self.border.y + self.border.w)/2 + (self.border.y - self.border.w) * self.pivot.y),
|
(borders.y + borders.w)/2 + size.y * self.pivot.y,
|
||||||
0
|
0)
|
||||||
)
|
|
||||||
|
return offset
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -309,17 +374,7 @@ function StaticGrid._update_borders(self)
|
|||||||
local size = self.node_size
|
local size = self.node_size
|
||||||
local pivot = self.node_pivot
|
local pivot = self.node_pivot
|
||||||
for index, node in pairs(self.nodes) do
|
for index, node in pairs(self.nodes) do
|
||||||
local pos = self:get_pos(index)
|
_extend_border(self.border, self:get_pos(index), size, pivot)
|
||||||
|
|
||||||
local left = pos.x - size.x/2 - (size.x * pivot.x)
|
|
||||||
local right = pos.x + size.x/2 - (size.x * pivot.x)
|
|
||||||
local top = pos.y + size.y/2 - (size.y * pivot.y)
|
|
||||||
local bottom = pos.y - size.y/2 - (size.y * pivot.y)
|
|
||||||
|
|
||||||
self.border.x = math.min(self.border.x, left)
|
|
||||||
self.border.y = math.max(self.border.y, top)
|
|
||||||
self.border.z = math.max(self.border.z, right)
|
|
||||||
self.border.w = math.min(self.border.w, bottom)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -329,12 +384,8 @@ end
|
|||||||
-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback
|
-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback
|
||||||
-- @local
|
-- @local
|
||||||
function StaticGrid._update_pos(self, is_instant)
|
function StaticGrid._update_pos(self, is_instant)
|
||||||
local zero_offset = self:_get_zero_offset()
|
|
||||||
|
|
||||||
for i, node in pairs(self.nodes) do
|
for i, node in pairs(self.nodes) do
|
||||||
local pos = self:get_pos(i)
|
local pos = self:get_pos(i)
|
||||||
pos.x = pos.x + zero_offset.x
|
|
||||||
pos.y = pos.y + zero_offset.y
|
|
||||||
|
|
||||||
if is_instant then
|
if is_instant then
|
||||||
gui.set_position(node, pos)
|
gui.set_position(node, pos)
|
||||||
|
@ -69,6 +69,13 @@ M.OS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
M.SHIFT = {
|
||||||
|
NO_SHIFT = 0,
|
||||||
|
LEFT = -1,
|
||||||
|
RIGHT = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
M.SIDE = {
|
M.SIDE = {
|
||||||
X = "x",
|
X = "x",
|
||||||
Y = "y"
|
Y = "y"
|
||||||
|
@ -22,11 +22,15 @@ end
|
|||||||
--- Subscribe callback on event
|
--- Subscribe callback on event
|
||||||
-- @tparam DruidEvent self
|
-- @tparam DruidEvent self
|
||||||
-- @tparam function callback Callback itself
|
-- @tparam function callback Callback itself
|
||||||
function DruidEvent.subscribe(self, callback)
|
-- @tparam table context Additional context as first param to callback call
|
||||||
|
function DruidEvent.subscribe(self, callback, context)
|
||||||
assert(type(self) == "table", "You should subscribe to event with : syntax")
|
assert(type(self) == "table", "You should subscribe to event with : syntax")
|
||||||
assert(type(callback) == "function", "Callback should be function")
|
assert(type(callback) == "function", "Callback should be function")
|
||||||
|
|
||||||
table.insert(self._callbacks, callback)
|
table.insert(self._callbacks, {
|
||||||
|
callback = callback,
|
||||||
|
context = context
|
||||||
|
})
|
||||||
|
|
||||||
return callback
|
return callback
|
||||||
end
|
end
|
||||||
@ -35,10 +39,11 @@ end
|
|||||||
--- Unsubscribe callback on event
|
--- Unsubscribe callback on event
|
||||||
-- @tparam DruidEvent self
|
-- @tparam DruidEvent self
|
||||||
-- @tparam function callback Callback itself
|
-- @tparam function callback Callback itself
|
||||||
function DruidEvent.unsubscribe(self, callback)
|
-- @tparam table context Additional context as first param to callback call
|
||||||
for i = 1, #self._callbacks do
|
function DruidEvent.unsubscribe(self, callback, context)
|
||||||
if self._callbacks[i] == callback then
|
for index, callback_info in ipairs(self._callbacks) do
|
||||||
table.remove(self._callbacks, i)
|
if callback_info.callback == callback and callback_info.context == context then
|
||||||
|
table.remove(self._callbacks, index)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -64,8 +69,12 @@ end
|
|||||||
-- @tparam DruidEvent self
|
-- @tparam DruidEvent self
|
||||||
-- @tparam any ... All event params
|
-- @tparam any ... All event params
|
||||||
function DruidEvent.trigger(self, ...)
|
function DruidEvent.trigger(self, ...)
|
||||||
for i = 1, #self._callbacks do
|
for index, callback_info in ipairs(self._callbacks) do
|
||||||
self._callbacks[i](...)
|
if callback_info.context then
|
||||||
|
callback_info.callback(callback_info.context, ...)
|
||||||
|
else
|
||||||
|
callback_info.callback(...)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
302
druid/extended/data_list.lua
Normal file
302
druid/extended/data_list.lua
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
--- Component to manage data for huge dataset in scroll.
|
||||||
|
-- It requires Druid Scroll and Druid Grid (Static or Dynamic) components
|
||||||
|
-- @module DataList
|
||||||
|
-- @within BaseComponent
|
||||||
|
-- @alias druid.data_list
|
||||||
|
|
||||||
|
|
||||||
|
--- The Druid scroll component
|
||||||
|
-- @tfield Scroll scroll
|
||||||
|
|
||||||
|
--- The Druid Grid component
|
||||||
|
-- @tfield StaticGrid grid
|
||||||
|
|
||||||
|
--- The current visual top data index
|
||||||
|
-- @tfield number top_index
|
||||||
|
|
||||||
|
--- The current visual last data index
|
||||||
|
-- @tfield number last_index
|
||||||
|
|
||||||
|
|
||||||
|
local const = require("druid.const")
|
||||||
|
local helper = require("druid.helper")
|
||||||
|
local component = require("druid.component")
|
||||||
|
|
||||||
|
local DataList = component.create("data_list")
|
||||||
|
|
||||||
|
|
||||||
|
--- Data list constructor
|
||||||
|
-- @tparam Scroll self
|
||||||
|
-- @tparam node view_node GUI view scroll node
|
||||||
|
-- @tparam node content_node GUI content scroll node
|
||||||
|
function DataList.init(self, data, scroll, grid, create_function)
|
||||||
|
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
|
||||||
|
|
||||||
|
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:set_data(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Druid System on_remove function
|
||||||
|
-- @tparam DataList self
|
||||||
|
function DataList.on_remove(self)
|
||||||
|
self.scroll.on_scroll:unsubscribe(self._check_elements, self)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set new data set for DataList component
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @tparam table data The new data array
|
||||||
|
function DataList.set_data(self, data)
|
||||||
|
self._data = data
|
||||||
|
self:_update_data_info()
|
||||||
|
self:_refresh()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add element to DataList. Currenly untested
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @tparam table data
|
||||||
|
-- @tparam number index
|
||||||
|
-- @tparam number shift_policy The constant from const.SHIFT.*
|
||||||
|
-- @local
|
||||||
|
function DataList.add(self, data, index, shift_policy)
|
||||||
|
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()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Remove element from DataList. Currenly untested
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @tparam number index
|
||||||
|
-- @tparam number shift_policy The constant from const.SHIFT.*
|
||||||
|
-- @local
|
||||||
|
function DataList.remove(self, index, shift_policy)
|
||||||
|
table.remove(self._data, index)
|
||||||
|
self:_refresh()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Remove element from DataList by data value. Currenly untested
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @tparam tabe data
|
||||||
|
-- @tparam number shift_policy The constant from const.SHIFT.*
|
||||||
|
-- @local
|
||||||
|
function DataList.remove_by_data(self, data, shift_policy)
|
||||||
|
local index = helper.contains(self._data, data)
|
||||||
|
if index then
|
||||||
|
table.remove(self._data, index)
|
||||||
|
self:_refresh()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Clear the DataList and refresh visuals
|
||||||
|
-- @tparam DataList self
|
||||||
|
function DataList.clear(self)
|
||||||
|
self._data = {}
|
||||||
|
self:_refresh()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Return first index from data. It not always equals to 1
|
||||||
|
-- @tparam DataList self
|
||||||
|
function DataList.get_first_index(self)
|
||||||
|
return self._data_first_index
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Return last index from data
|
||||||
|
-- @tparam DataList self
|
||||||
|
function DataList.get_last_index(self)
|
||||||
|
return self._data_last_index
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Return amount of data
|
||||||
|
-- @tparam DataList self
|
||||||
|
function DataList.get_length(self)
|
||||||
|
return self._data_length
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Return index for data value
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @tparam table data
|
||||||
|
function DataList.get_index(self, data)
|
||||||
|
for index, value in pairs(self._data) do
|
||||||
|
if value == data then
|
||||||
|
return index
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Instant scroll to element with passed index
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @tparam number index
|
||||||
|
function DataList.scroll_to_index(self, index)
|
||||||
|
self.top_index = helper.clamp(index, 1, #self._data)
|
||||||
|
self:_refresh()
|
||||||
|
self.scroll.on_scroll:trigger(self:get_context(), self)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add element at passed index
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @tparam number index
|
||||||
|
-- @local
|
||||||
|
function DataList._add_at(self, index)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Remove element from passed index
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @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)
|
||||||
|
|
||||||
|
if self._data_visual[index].component then
|
||||||
|
self.druid:remove(self._data_visual[index].component)
|
||||||
|
end
|
||||||
|
self._data_visual[index] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Fully refresh all DataList elements
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @local
|
||||||
|
function DataList._refresh(self)
|
||||||
|
for index, _ in pairs(self._data_visual) do
|
||||||
|
self:_remove_at(index)
|
||||||
|
end
|
||||||
|
self:_check_elements()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check elements which should be created
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @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
|
||||||
|
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check elements which should be created.
|
||||||
|
-- Start from index with step until element is outside of scroll view
|
||||||
|
-- @tparam DataList self
|
||||||
|
-- @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
|
||||||
|
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
|
||||||
|
-- @local
|
||||||
|
function DataList._update_data_info(self)
|
||||||
|
self._data_first_index = false
|
||||||
|
self._data_last_index = false
|
||||||
|
self._data_length = 0
|
||||||
|
|
||||||
|
for index, data in pairs(self._data) do
|
||||||
|
self._data_first_index = math.min(self._data_first_index or index, index)
|
||||||
|
self._data_last_index = math.max(self._data_last_index or index, index)
|
||||||
|
self._data_length = self._data_length + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if self._data_length == 0 then
|
||||||
|
self._data_first_index = 1
|
||||||
|
self._data_last_index = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return DataList
|
@ -21,7 +21,7 @@
|
|||||||
--- Parent gui node
|
--- Parent gui node
|
||||||
-- @tfield node parent
|
-- @tfield node parent
|
||||||
|
|
||||||
--- List of all grid nodes
|
--- List of all grid elements. Contains from node, pos, size, pivot
|
||||||
-- @tfield node[] nodes
|
-- @tfield node[] nodes
|
||||||
|
|
||||||
--- The first index of node in grid
|
--- The first index of node in grid
|
||||||
@ -136,18 +136,19 @@ end
|
|||||||
-- @tparam DynamicGrid self
|
-- @tparam DynamicGrid self
|
||||||
-- @tparam node node Gui node
|
-- @tparam node node Gui node
|
||||||
-- @tparam[opt] number index The node position. By default add as last node
|
-- @tparam[opt] number index The node position. By default add as last node
|
||||||
-- @tparam[opt=false] bool is_shift_left If true, shift all nodes to the left, otherwise shift nodes to the right
|
-- @tparam[opt=SHIFT.RIGHT] number shift_policy How shift nodes, if required. See const.SHIFT
|
||||||
function DynamicGrid.add(self, node, index, is_shift_left)
|
function DynamicGrid.add(self, node, index, shift_policy)
|
||||||
local delta = is_shift_left and -1 or 1
|
shift_policy = shift_policy or const.SHIFT.RIGHT
|
||||||
|
local delta = shift_policy -- -1 or 1 or 0
|
||||||
|
|
||||||
-- By default add node at end
|
-- By default add node at end
|
||||||
index = index or ((self.last_index or 0) + 1)
|
index = index or ((self.last_index or 0) + 1)
|
||||||
|
|
||||||
-- If node exist at index place, shifting them
|
-- If node exist at index place, shifting them
|
||||||
local is_shift = self.nodes[index]
|
local is_shift = self.nodes[index] and shift_policy ~= const.SHIFT.NO_SHIFT
|
||||||
if is_shift then
|
if is_shift then
|
||||||
-- We need to iterate from index to start or end grid, depends of shift side
|
-- We need to iterate from index to start or end grid, depends of shift side
|
||||||
local start_index = is_shift_left and self.first_index or self.last_index
|
local start_index = shift_policy == const.SHIFT.LEFT and self.first_index or self.last_index
|
||||||
for i = start_index, index, -delta do
|
for i = start_index, index, -delta do
|
||||||
self.nodes[i + delta] = self.nodes[i]
|
self.nodes[i + delta] = self.nodes[i]
|
||||||
end
|
end
|
||||||
@ -158,14 +159,13 @@ function DynamicGrid.add(self, node, index, is_shift_left)
|
|||||||
-- After shifting we should recalc node poses
|
-- After shifting we should recalc node poses
|
||||||
if is_shift then
|
if is_shift then
|
||||||
-- We need to iterate from placed node to start or end grid, depends of shift side
|
-- We need to iterate from placed node to start or end grid, depends of shift side
|
||||||
local target_index = is_shift_left and self.first_index or self.last_index
|
local target_index = shift_policy == const.SHIFT.LEFT and self.first_index or self.last_index
|
||||||
for i = index + delta, target_index + delta, delta do
|
for i = index + delta, target_index + delta, delta do
|
||||||
local move_node = self.nodes[i]
|
local move_node = self.nodes[i]
|
||||||
move_node.pos = self:get_pos(i, move_node.node, i - delta)
|
move_node.pos = self:get_pos(i, move_node.node, i - delta)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Sync grid data
|
-- Sync grid data
|
||||||
self:_update()
|
self:_update()
|
||||||
|
|
||||||
@ -178,9 +178,11 @@ end
|
|||||||
-- @tparam DynamicGrid self
|
-- @tparam DynamicGrid self
|
||||||
-- @tparam number index The grid node index to remove
|
-- @tparam number index The grid node index to remove
|
||||||
-- @tparam[opt=false] bool is_shift_left If true, shift all nodes to the left, otherwise shift nodes to the right
|
-- @tparam[opt=false] bool is_shift_left If true, shift all nodes to the left, otherwise shift nodes to the right
|
||||||
|
-- @tparam[opt=SHIFT.RIGHT] number shift_policy How shift nodes, if required. See const.SHIFT
|
||||||
-- @treturn Node The deleted gui node from grid
|
-- @treturn Node The deleted gui node from grid
|
||||||
function DynamicGrid.remove(self, index, is_shift_left)
|
function DynamicGrid.remove(self, index, shift_policy)
|
||||||
local delta = is_shift_left and -1 or 1
|
shift_policy = shift_policy or const.SHIFT.RIGHT
|
||||||
|
local delta = shift_policy -- -1 or 1 or 0
|
||||||
|
|
||||||
assert(self.nodes[index], "No grid item at given index " .. index)
|
assert(self.nodes[index], "No grid item at given index " .. index)
|
||||||
|
|
||||||
@ -189,11 +191,13 @@ function DynamicGrid.remove(self, index, is_shift_left)
|
|||||||
self.nodes[index] = nil
|
self.nodes[index] = nil
|
||||||
|
|
||||||
-- After delete node, we should shift nodes and recalc their poses, depends from is_shift_left
|
-- After delete node, we should shift nodes and recalc their poses, depends from is_shift_left
|
||||||
local target_index = is_shift_left and self.first_index or self.last_index
|
if shift_policy ~= const.SHIFT.NO_SHIFT then
|
||||||
for i = index, target_index, delta do
|
local target_index = shift_policy == const.SHIFT.LEFT and self.first_index or self.last_index
|
||||||
self.nodes[i] = self.nodes[i + delta]
|
for i = index, target_index, delta do
|
||||||
if self.nodes[i] then
|
self.nodes[i] = self.nodes[i + delta]
|
||||||
self.nodes[i].pos = self:get_pos(i, self.nodes[i].node, i - delta)
|
if self.nodes[i] then
|
||||||
|
self.nodes[i].pos = self:get_pos(i, self.nodes[i].node, i - delta)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -220,6 +224,29 @@ function DynamicGrid.get_size(self, border)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Return DynamicGrid offset, where DynamicGrid content starts.
|
||||||
|
-- @tparam DynamicGrid self The DynamicGrid instance
|
||||||
|
-- @treturn vector3 The DynamicGrid offset
|
||||||
|
function DynamicGrid.get_offset(self)
|
||||||
|
local size = self:get_size()
|
||||||
|
local borders = self:get_borders()
|
||||||
|
local offset = vmath.vector3(
|
||||||
|
(borders.z + borders.x)/2 + size.x * self.pivot.x,
|
||||||
|
(borders.y + borders.w)/2 + size.y * self.pivot.y,
|
||||||
|
0)
|
||||||
|
|
||||||
|
return offset
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Return grid content borders
|
||||||
|
-- @tparam DynamicGrid self
|
||||||
|
-- @treturn vector3 The grid content borders
|
||||||
|
function DynamicGrid.get_borders(self)
|
||||||
|
return self.border
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Return grid index by node
|
--- Return grid index by node
|
||||||
-- @tparam DynamicGrid self
|
-- @tparam DynamicGrid self
|
||||||
-- @tparam node node The gui node in the grid
|
-- @tparam node node The gui node in the grid
|
||||||
@ -283,7 +310,7 @@ function DynamicGrid._add_node(self, node, index, origin_index)
|
|||||||
|
|
||||||
-- Add new item instantly in new pos
|
-- Add new item instantly in new pos
|
||||||
gui.set_parent(node, self.parent)
|
gui.set_parent(node, self.parent)
|
||||||
gui.set_position(node, self.nodes[index].pos + self:_get_zero_offset())
|
gui.set_position(node, self.nodes[index].pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -348,13 +375,11 @@ end
|
|||||||
-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback
|
-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback
|
||||||
-- @local
|
-- @local
|
||||||
function DynamicGrid._update_pos(self, is_instant)
|
function DynamicGrid._update_pos(self, is_instant)
|
||||||
local offset = self:_get_zero_offset()
|
|
||||||
|
|
||||||
for index, node in pairs(self.nodes) do
|
for index, node in pairs(self.nodes) do
|
||||||
if is_instant then
|
if is_instant then
|
||||||
gui.set_position(node.node, node.pos + offset)
|
gui.set_position(node.node, node.pos)
|
||||||
else
|
else
|
||||||
self._set_position_function(node.node, node.pos + offset)
|
self._set_position_function(node.node, node.pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -381,25 +406,12 @@ function DynamicGrid._get_next_node_pos(self, origin_node_index, new_node, place
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function DynamicGrid._get_node_size(self, node)
|
function DynamicGrid._get_node_size(self, node)
|
||||||
return vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node))
|
return vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Return elements offset for correct posing nodes. Correct posing at
|
|
||||||
-- parent pivot node (0:0) with adjusting of node sizes and anchoring
|
|
||||||
-- @tparam DynamicGrid self
|
|
||||||
-- @treturn vector3 The offset vector
|
|
||||||
-- @local
|
|
||||||
function DynamicGrid._get_zero_offset(self)
|
|
||||||
-- zero offset: center pos - border size * anchor
|
|
||||||
return vmath.vector3(
|
|
||||||
-((self.border.x + self.border.z)/2 + (self.border.z - self.border.x) * self.pivot.x),
|
|
||||||
-((self.border.y + self.border.w)/2 + (self.border.y - self.border.w) * self.pivot.y),
|
|
||||||
0)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--- Return side vector to correct node shifting
|
--- Return side vector to correct node shifting
|
||||||
function DynamicGrid._get_side_vector(self, side, is_forward)
|
function DynamicGrid._get_side_vector(self, side, is_forward)
|
||||||
if side == const.SIDE.X then
|
if side == const.SIDE.X then
|
||||||
|
@ -194,19 +194,30 @@ function M.is_web()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Distance from node to size border
|
--- Distance from node position to his borders
|
||||||
-- @function helper.get_border
|
-- @function helper.get_border
|
||||||
-- @return vector4 (left, top, right, down)
|
-- @tparam node node The gui node to check
|
||||||
function M.get_border(node)
|
-- @tparam vector3 offset The offset to add to result
|
||||||
|
-- @return vector4 Vector with distance to node border: (left, top, right, down)
|
||||||
|
function M.get_border(node, offset)
|
||||||
local pivot = gui.get_pivot(node)
|
local pivot = gui.get_pivot(node)
|
||||||
local pivot_offset = M.get_pivot_offset(pivot)
|
local pivot_offset = M.get_pivot_offset(pivot)
|
||||||
local size = vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node))
|
local size = vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node))
|
||||||
return vmath.vector4(
|
local border = vmath.vector4(
|
||||||
-size.x*(0.5 + pivot_offset.x),
|
-size.x*(0.5 + pivot_offset.x),
|
||||||
size.y*(0.5 - pivot_offset.y),
|
size.y*(0.5 - pivot_offset.y),
|
||||||
size.x*(0.5 - pivot_offset.x),
|
size.x*(0.5 - pivot_offset.x),
|
||||||
-size.y*(0.5 + pivot_offset.y)
|
-size.y*(0.5 + pivot_offset.y)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if offset then
|
||||||
|
border.x = border.x + offset.x
|
||||||
|
border.y = border.y + offset.y
|
||||||
|
border.z = border.z + offset.x
|
||||||
|
border.w = border.w + offset.y
|
||||||
|
end
|
||||||
|
|
||||||
|
return border
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ local progress = require("druid.extended.progress")
|
|||||||
local radio_group = require("druid.extended.radio_group")
|
local radio_group = require("druid.extended.radio_group")
|
||||||
local slider = require("druid.extended.slider")
|
local slider = require("druid.extended.slider")
|
||||||
local timer = require("druid.extended.timer")
|
local timer = require("druid.extended.timer")
|
||||||
|
local data_list = require("druid.extended.data_list")
|
||||||
|
|
||||||
|
|
||||||
local DruidInstance = class("druid.druid_instance")
|
local DruidInstance = class("druid.druid_instance")
|
||||||
@ -541,6 +542,15 @@ function DruidInstance.new_checkbox_group(self, nodes, callback, click_nodes)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Create data list basic component
|
||||||
|
-- @function druid:new_data_list
|
||||||
|
-- @tparam args ... drag init args
|
||||||
|
-- @treturn Component data list component
|
||||||
|
function DruidInstance.new_data_list(self, ...)
|
||||||
|
return DruidInstance.create(self, data_list, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Create radio_group component
|
--- Create radio_group component
|
||||||
-- @tparam DruidInstance self
|
-- @tparam DruidInstance self
|
||||||
-- @tparam node[] nodes Array of gui node
|
-- @tparam node[] nodes Array of gui node
|
||||||
|
@ -3,9 +3,8 @@
|
|||||||
platforms:
|
platforms:
|
||||||
x86_64-osx:
|
x86_64-osx:
|
||||||
context:
|
context:
|
||||||
excludeLibs: ["physics","LinearMath","BulletDynamics","BulletCollision","Box2D","record","vpx","profilerext"]
|
excludeLibs: ["physics","LinearMath","BulletDynamics","BulletCollision","Box2D","record","vpx"]
|
||||||
excludeSymbols: ["ProfilerExt"]
|
libs: ["physics_null","record_null"]
|
||||||
libs: ["physics_null","record_null","profilerext_null"]
|
|
||||||
linkFlags: []
|
linkFlags: []
|
||||||
|
|
||||||
x86_64-linux:
|
x86_64-linux:
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@ local scroll_page = require("example.page.scroll_page")
|
|||||||
local slider_page = require("example.page.slider_page")
|
local slider_page = require("example.page.slider_page")
|
||||||
local input_page = require("example.page.input_page")
|
local input_page = require("example.page.input_page")
|
||||||
local grid_page = require("example.page.grid_page")
|
local grid_page = require("example.page.grid_page")
|
||||||
|
local infinity_page = require("example.page.infinity_page")
|
||||||
|
|
||||||
local pages = {
|
local pages = {
|
||||||
"main_page",
|
"main_page",
|
||||||
@ -20,6 +21,7 @@ local pages = {
|
|||||||
"slider_page",
|
"slider_page",
|
||||||
"input_page",
|
"input_page",
|
||||||
"grid_page",
|
"grid_page",
|
||||||
|
"infinity_page",
|
||||||
}
|
}
|
||||||
|
|
||||||
local function on_control_button(self, delta)
|
local function on_control_button(self, delta)
|
||||||
@ -29,6 +31,10 @@ local function on_control_button(self, delta)
|
|||||||
|
|
||||||
self.header:translate(pages[self.page])
|
self.header:translate(pages[self.page])
|
||||||
local node = gui.get_node("C_Anchor")
|
local node = gui.get_node("C_Anchor")
|
||||||
|
|
||||||
|
for i = 1, #pages do
|
||||||
|
gui.set_enabled(gui.get_node(pages[i]), i == self.page)
|
||||||
|
end
|
||||||
gui.animate(node, "position.x", (self.page-1) * -600, gui.EASING_OUTSINE, 0.2)
|
gui.animate(node, "position.x", (self.page-1) * -600, gui.EASING_OUTSINE, 0.2)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -74,6 +80,7 @@ function init(self)
|
|||||||
slider_page.setup_page(self)
|
slider_page.setup_page(self)
|
||||||
input_page.setup_page(self)
|
input_page.setup_page(self)
|
||||||
grid_page.setup_page(self)
|
grid_page.setup_page(self)
|
||||||
|
infinity_page.setup_page(self)
|
||||||
|
|
||||||
init_top_panel(self)
|
init_top_panel(self)
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ local en = {
|
|||||||
slider_page = "Slider page",
|
slider_page = "Slider page",
|
||||||
input_page = "Input page",
|
input_page = "Input page",
|
||||||
grid_page = "Grid page",
|
grid_page = "Grid page",
|
||||||
|
infinity_page = "Infinity scroll",
|
||||||
ui_section_button = "Button",
|
ui_section_button = "Button",
|
||||||
ui_section_text = "Text",
|
ui_section_text = "Text",
|
||||||
ui_section_timer = "Timer",
|
ui_section_timer = "Timer",
|
||||||
@ -29,6 +30,7 @@ local ru = {
|
|||||||
slider_page = "Слайдеры",
|
slider_page = "Слайдеры",
|
||||||
input_page = "Текст. ввод",
|
input_page = "Текст. ввод",
|
||||||
grid_page = "Сетка",
|
grid_page = "Сетка",
|
||||||
|
infinity_page = "Беск. скролл",
|
||||||
ui_section_button = "Кнопка",
|
ui_section_button = "Кнопка",
|
||||||
ui_section_text = "Текст",
|
ui_section_text = "Текст",
|
||||||
ui_section_timer = "Таймер",
|
ui_section_timer = "Таймер",
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
local const = require("druid.const")
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
|
||||||
@ -6,12 +8,12 @@ local function simple_animate(node, pos)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function remove_node(self, button, is_shift)
|
local function remove_node(self, button, no_shift)
|
||||||
gui.delete_node(button.node)
|
gui.delete_node(button.node)
|
||||||
|
|
||||||
self.druid:remove(button)
|
self.druid:remove(button)
|
||||||
local index = self.grid_static_grid:get_index_by_node(button.node)
|
local index = self.grid_static_grid:get_index_by_node(button.node)
|
||||||
self.grid_static_grid:remove(index, is_shift)
|
self.grid_static_grid:remove(index, no_shift and const.SHIFT.NO_SHIFT or const.SHIFT.RIGHT)
|
||||||
for i = 1, #self.grid_node_buttons do
|
for i = 1, #self.grid_node_buttons do
|
||||||
if self.grid_node_buttons[i] == button then
|
if self.grid_node_buttons[i] == button then
|
||||||
table.remove(self.grid_node_buttons, i)
|
table.remove(self.grid_node_buttons, i)
|
||||||
@ -27,10 +29,10 @@ local function add_node(self, index)
|
|||||||
gui.set_enabled(cloned["grid_nodes_prefab"], true)
|
gui.set_enabled(cloned["grid_nodes_prefab"], true)
|
||||||
|
|
||||||
local button = self.druid:new_button(cloned["grid_nodes_prefab"], function(_, params, button)
|
local button = self.druid:new_button(cloned["grid_nodes_prefab"], function(_, params, button)
|
||||||
remove_node(self, button, true)
|
remove_node(self, button)
|
||||||
end)
|
end)
|
||||||
button.on_long_click:subscribe(function()
|
button.on_long_click:subscribe(function()
|
||||||
remove_node(self, button)
|
remove_node(self, button, true)
|
||||||
end)
|
end)
|
||||||
button:set_click_zone(self.grid_static_scroll.view_node)
|
button:set_click_zone(self.grid_static_scroll.view_node)
|
||||||
|
|
||||||
@ -72,12 +74,12 @@ local function init_static_grid(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function remove_dynamic_node(self, button, is_shift_left)
|
local function remove_dynamic_node(self, button, shift_policy)
|
||||||
gui.delete_node(button.node)
|
gui.delete_node(button.node)
|
||||||
|
|
||||||
self.druid:remove(button)
|
self.druid:remove(button)
|
||||||
local index = self.grid_dynamic_grid:get_index_by_node(button.node)
|
local index = self.grid_dynamic_grid:get_index_by_node(button.node)
|
||||||
self.grid_dynamic_grid:remove(index, is_shift_left)
|
self.grid_dynamic_grid:remove(index, shift_policy)
|
||||||
for i = 1, #self.dynamic_node_buttons do
|
for i = 1, #self.dynamic_node_buttons do
|
||||||
if self.dynamic_node_buttons[i] == button then
|
if self.dynamic_node_buttons[i] == button then
|
||||||
table.remove(self.dynamic_node_buttons, i)
|
table.remove(self.dynamic_node_buttons, i)
|
||||||
@ -89,6 +91,7 @@ end
|
|||||||
|
|
||||||
local function add_node_dynamic(self, index, is_shift_left)
|
local function add_node_dynamic(self, index, is_shift_left)
|
||||||
local node = gui.clone(self.prefab_dynamic)
|
local node = gui.clone(self.prefab_dynamic)
|
||||||
|
gui.set_color(node, vmath.vector4(math.random() * 0.2 + 0.8))
|
||||||
gui.set_enabled(node, true)
|
gui.set_enabled(node, true)
|
||||||
gui.set_size(node, vmath.vector3(250, math.random(60, 150), 0))
|
gui.set_size(node, vmath.vector3(250, math.random(60, 150), 0))
|
||||||
self.grid_dynamic_grid:add(node, index, is_shift_left)
|
self.grid_dynamic_grid:add(node, index, is_shift_left)
|
||||||
@ -97,24 +100,51 @@ local function add_node_dynamic(self, index, is_shift_left)
|
|||||||
remove_dynamic_node(self, button)
|
remove_dynamic_node(self, button)
|
||||||
end)
|
end)
|
||||||
button.on_long_click:subscribe(function()
|
button.on_long_click:subscribe(function()
|
||||||
remove_dynamic_node(self, button, true)
|
remove_dynamic_node(self, button, const.SHIFT.LEFT)
|
||||||
end)
|
end)
|
||||||
button:set_click_zone(self.grid_dynamic_scroll.view_node)
|
button:set_click_zone(self.grid_dynamic_scroll.view_node)
|
||||||
table.insert(self.dynamic_node_buttons, button)
|
table.insert(self.dynamic_node_buttons, button)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function remove_dynamic_hor_node(self, button, shift_policy)
|
||||||
|
gui.delete_node(button.node)
|
||||||
|
|
||||||
|
self.druid:remove(button)
|
||||||
|
local index = self.grid_dynamic_hor_grid:get_index_by_node(button.node)
|
||||||
|
self.grid_dynamic_hor_grid:remove(index, shift_policy)
|
||||||
|
for i = 1, #self.dynamic_node_hor_buttons do
|
||||||
|
if self.dynamic_node_hor_buttons[i] == button then
|
||||||
|
table.remove(self.dynamic_node_hor_buttons, i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local function add_node_dynamic_hor(self, index)
|
local function add_node_dynamic_hor(self, index)
|
||||||
local node = gui.clone(self.prefab_hor_dynamic)
|
local node = gui.clone(self.prefab_hor_dynamic)
|
||||||
|
gui.set_color(node, vmath.vector4(math.random() * 0.2 + 0.8))
|
||||||
gui.set_enabled(node, true)
|
gui.set_enabled(node, true)
|
||||||
gui.set_size(node, vmath.vector3(80 + math.random(0, 80), 80, 0))
|
gui.set_size(node, vmath.vector3(80 + math.random(0, 80), 80, 0))
|
||||||
|
|
||||||
|
local button = self.druid:new_button(node, function(_, params, button)
|
||||||
|
remove_dynamic_hor_node(self, button)
|
||||||
|
end)
|
||||||
|
button.on_long_click:subscribe(function()
|
||||||
|
remove_dynamic_hor_node(self, button, const.SHIFT.LEFT)
|
||||||
|
end)
|
||||||
|
button:set_click_zone(self.grid_dynamic_hor_scroll.view_node)
|
||||||
|
|
||||||
self.grid_dynamic_hor_grid:add(node, index)
|
self.grid_dynamic_hor_grid:add(node, index)
|
||||||
|
table.insert(self.dynamic_node_hor_buttons, button)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function init_dynamic_grid(self)
|
local function init_dynamic_grid(self)
|
||||||
-- Vertical horizontal grid
|
-- Vertical horizontal grid
|
||||||
self.dynamic_node_buttons = {}
|
self.dynamic_node_buttons = {}
|
||||||
|
self.dynamic_node_hor_buttons = {}
|
||||||
|
|
||||||
self.prefab_dynamic = gui.get_node("grid_dynamic_prefab")
|
self.prefab_dynamic = gui.get_node("grid_dynamic_prefab")
|
||||||
gui.set_enabled(self.prefab_dynamic, false)
|
gui.set_enabled(self.prefab_dynamic, false)
|
||||||
@ -123,7 +153,7 @@ local function init_dynamic_grid(self)
|
|||||||
add_node_dynamic(self, i)
|
add_node_dynamic(self, i)
|
||||||
end
|
end
|
||||||
self.druid:new_button("button_add_start_dynamic/button", function()
|
self.druid:new_button("button_add_start_dynamic/button", function()
|
||||||
local start_index = (self.grid_dynamic_grid.first_index or 2) - 1
|
local start_index = self.grid_dynamic_grid.first_index or 1
|
||||||
add_node_dynamic(self, start_index)
|
add_node_dynamic(self, start_index)
|
||||||
end)
|
end)
|
||||||
self.druid:new_button("button_add_end_dynamic/button", function()
|
self.druid:new_button("button_add_end_dynamic/button", function()
|
||||||
@ -139,7 +169,8 @@ local function init_dynamic_grid(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
self.druid:new_button("button_add_start_dynamic_hor/button", function()
|
self.druid:new_button("button_add_start_dynamic_hor/button", function()
|
||||||
add_node_dynamic_hor(self, 1)
|
local start_index = self.grid_dynamic_hor_grid.first_index or 1
|
||||||
|
add_node_dynamic_hor(self, start_index)
|
||||||
end)
|
end)
|
||||||
self.druid:new_button("button_add_end_dynamic_hor/button", function()
|
self.druid:new_button("button_add_end_dynamic_hor/button", function()
|
||||||
add_node_dynamic_hor(self)
|
add_node_dynamic_hor(self)
|
||||||
@ -148,7 +179,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
function M.setup_page(self)
|
function M.setup_page(self)
|
||||||
self.grid_page_scroll = self.druid:new_scroll("grid_page", "grid_page_content")
|
self.druid:new_scroll("grid_page", "grid_page_content")
|
||||||
|
|
||||||
self.grid_static_grid = self.druid:new_static_grid("grid_nodes", "grid_nodes_prefab", 5)
|
self.grid_static_grid = self.druid:new_static_grid("grid_nodes", "grid_nodes_prefab", 5)
|
||||||
:set_position_function(simple_animate)
|
:set_position_function(simple_animate)
|
||||||
|
180
example/page/infinity_page.lua
Normal file
180
example/page/infinity_page.lua
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
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 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
|
||||||
|
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 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
|
||||||
|
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 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
|
||||||
|
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)
|
||||||
|
|
||||||
|
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
|
||||||
|
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)
|
||||||
|
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function setup_infinity_list(self)
|
||||||
|
local data = {}
|
||||||
|
for i = 1, 50 do
|
||||||
|
table.insert(data, i)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.infinity_list = self.druid:new_data_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_data_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(25)
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
self.infinity_list_small = self.druid:new_data_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_data_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)
|
||||||
|
|
||||||
|
timer.delay(1, false, function()
|
||||||
|
self.infinity_list_dynamic:scroll_to_index(25)
|
||||||
|
end)
|
||||||
|
|
||||||
|
self.infinity_list_dynamic_hor = self.druid:new_data_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)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function M.setup_page(self)
|
||||||
|
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_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_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_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)
|
||||||
|
|
||||||
|
setup_infinity_list(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return M
|
Loading…
x
Reference in New Issue
Block a user