From 05425fb76c78cc3a3682729de5481f7ee3db0010 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 28 Apr 2020 18:13:43 +0300 Subject: [PATCH] Scroll refactoring process --- druid/base/drag.lua | 214 +++++++++++ druid/base/grid.lua | 4 +- druid/base/scroll.lua | 609 ++++++++++---------------------- druid/base/scroll_legacy.lua | 538 ++++++++++++++++++++++++++++ druid/const.lua | 11 + druid/helper.lua | 28 ++ druid/styles/default/style.lua | 18 +- druid/system/druid_instance.lua | 7 + example/gui/main/main.gui | 183 +++++++++- example/page/main.lua | 3 +- example/page/scroll.lua | 20 +- 11 files changed, 1196 insertions(+), 439 deletions(-) create mode 100644 druid/base/drag.lua create mode 100644 druid/base/scroll_legacy.lua diff --git a/druid/base/drag.lua b/druid/base/drag.lua new file mode 100644 index 0000000..8c31b7f --- /dev/null +++ b/druid/base/drag.lua @@ -0,0 +1,214 @@ +--- Component to handle drag action on node +-- @module druid.drag + +--- Components fields +-- @table Fields + +--- Component events +-- @table Events + +--- Component style params +-- @table Style + +local Event = require("druid.event") +local const = require("druid.const") +local helper = require("druid.helper") +local component = require("druid.component") + +local M = component.create("drag", { const.ON_INPUT_HIGH }) + + +local function start_touch(self, touch) + self.is_touch = true + self.is_drag = false + + self.touch_start_pos.x = touch.screen_x + self.touch_start_pos.y = touch.screen_y + + self.screen_x = touch.screen_x + self.screen_y = touch.screen_y + + self.on_touch_start:trigger(self:get_context()) +end + + +local function end_touch(self) + if self.is_drag then + self.on_drag_end:trigger(self:get_context()) + end + + self.is_drag = false + self.is_touch = false + self.on_touch_end:trigger(self:get_context()) + self.touch_id = 0 +end + + +local function process_touch(self, touch) + if not self.can_x then + self.touch_start_pos.x = touch.screen_x + end + if not self.can_y then + self.touch_start_pos.y = touch.screen_y + end + + local distance = helper.distance(touch.screen_x, touch.screen_y, self.touch_start_pos.x, self.touch_start_pos.y) + if not self.is_drag and distance >= self.drag_deadzone then + self.is_drag = true + self.on_drag_start:trigger(self:get_context()) + end +end + + +local function find_touch(action_id, action, touch_id) + local act = const.ACTION_TOUCH + + if action_id ~= act then + return + end + + if action.touch then + local touch = action.touch + for i = 1, #touch do + if touch[i].id == touch_id then + return touch[i] + end + end + return touch[1] + else + return action + end +end + + +local function on_touch_release(self, action_id, action) + if #action.touch >= 2 then + -- Find next unpressed touch + local next_touch + for i = 1, #action.touch do + if not action.touch[i].released then + next_touch = action.touch[i] + break + end + end + + if next_touch then + self.screen_x = next_touch.screen_x + self.screen_y = next_touch.screen_y + self.touch_id = next_touch.id + else + end_touch(self) + end + elseif #action.touch == 1 then + end_touch(self) + end +end + + +--- Component init function +-- @function drag:init +function M.init(self, node, on_drag_callback) + self.style = self:get_style() + self.node = self:get_node(node) + + self.drag_deadzone = self.style.DRAG_DEADZONE or 10 + + self.dx = 0 + self.dy = 0 + self.touch_id = 0 + self.screen_x = 0 + self.screen_y = 0 + self.is_touch = false + self.is_drag = false + self.touch_start_pos = vmath.vector3(0) + + self.can_x = true + self.can_y = true + + self.click_zone = nil + self.on_touch_start = Event() + self.on_touch_end = Event() + self.on_drag_start = Event() + self.on_drag = Event(on_drag_callback) + self.on_drag_end = Event() +end + + +function M.on_input(self, action_id, action) + if action_id ~= const.ACTION_TOUCH then + return + end + + if not helper.is_enabled(self.node) then + return false + end + + local is_pick = gui.pick_node(self.node, action.x, action.y) + if self.click_zone then + is_pick = is_pick and gui.pick_node(self.click_zone, action.x, action.y) + end + + if not is_pick and not self.is_drag then + end_touch(self) + return false + end + + self.dx = 0 + self.dy = 0 + + local touch = find_touch(action_id, action, self.touch_id) + if not touch then + return false + end + + if touch.id then + self.touch_id = touch.id + end + + if touch.pressed and not self.is_touch then + start_touch(self, touch) + end + + if touch.released and self.is_touch then + if action.touch then + -- Mobile + on_touch_release(action_id, action, self) + else + -- PC + end_touch(self) + end + end + + if self.is_touch then + process_touch(self, touch) + end + + local touch_modified = find_touch(action_id, action, self.touch_id) + if touch_modified and self.is_drag then + self.dx = touch_modified.screen_x - self.screen_x + self.dy = touch_modified.screen_y - self.screen_y + end + + if touch then + self.screen_x = touch.screen_x + self.screen_y = touch.screen_y + end + + if self.is_drag then + self.on_drag:trigger(self:get_context(), self.dx, self.dy) + end + + return self.is_drag +end + + +--- Strict drag click area. Useful for +-- restrict events outside stencil node +-- @function drag:set_click_zone +-- @tparam node zone Gui node +function M.set_click_zone(self, zone) + self.click_zone = self:get_node(zone) +end + + +return M diff --git a/druid/base/grid.lua b/druid/base/grid.lua index 9bdd8e8..02fa03c 100644 --- a/druid/base/grid.lua +++ b/druid/base/grid.lua @@ -20,7 +20,7 @@ -- @tfield vector3 border_offer The border offset for correct anchor calculations local Event = require("druid.event") -local const = require("druid.const") +local helper = require("druid.helper") local component = require("druid.component") local M = component.create("grid") @@ -37,7 +37,7 @@ function M.init(self, parent, element, in_row) self.offset = vmath.vector3(0) - local pivot = const.PIVOTS[gui.get_pivot(self.parent)] + local pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) self.anchor = vmath.vector3(0.5 + pivot.x, 0.5 - pivot.y, 0) self.in_row = in_row or 1 diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 56a50aa..694fb13 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -1,261 +1,38 @@ ---- Component to handle scroll content. --- Scroll consist from two nodes: scroll parent and scroll input --- Scroll input the user input zone, it's static --- Scroll parent the scroll moving part, it will change position. --- Setup initial scroll size by changing scroll parent size. If scroll parent --- size will be less than scroll_input size, no scroll is available. For scroll --- parent size should be more than input size +--- -- @module druid.scroll +--- Components fields +-- @table Fields + --- Component events -- @table Events --- @tfield druid_event on_scroll On scroll move callback --- @tfield druid_event on_scroll_to On scroll_to function callback --- @tfield druid_event on_point_scroll On scroll_to_index function callback - ---- Component fields --- @table Fields --- @tfield node node Scroll parent node --- @tfield node input_zone Scroll input node --- @tfield vector3 zone_size Current scroll content size --- @tfield number soft_size Soft zone size from style table --- @tfield vector3 center_offset Distance from node to node's center --- @tfield bool is_inert Flag, if scroll now moving by inertion --- @tfield vector3 inert Current inert speed --- @tfield vector3 pos Current scroll posisition --- @tfield vector3 target Current scroll target position --- Component style params -- @table Style --- @tfield number FRICT_HOLD Multiplier for inertion, while touching --- @tfield number FRICT Multiplier for free inertion --- @tfield number INERT_THRESHOLD Scroll speed to stop inertion --- @tfield number INERT_SPEED Multiplier for inertion speed --- @tfield number DEADZONE Deadzone for start scrol in pixels --- @tfield number SOFT_ZONE_SIZE Size of outside zone in pixels (for scroll back moving) --- @tfield number BACK_SPEED Scroll back returning lerp speed --- @tfield number ANIM_SPEED Scroll gui.animation speed for scroll_to function local Event = require("druid.event") -local helper = require("druid.helper") local const = require("druid.const") +local helper = require("druid.helper") local component = require("druid.component") -local M = component.create("scroll", { const.ON_UPDATE, const.ON_INPUT_HIGH }) +local M = component.create("scroll", { const.ON_UPDATE }) --- Global on all scrolls --- TODO: remove it -M.current_scroll = nil - - -local function get_border(node) - local pivot = gui.get_pivot(node) - local pivot_offset = helper.get_pivot_offset(pivot) - local size = vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node)) - return vmath.vector4( - -size.x*(0.5 + pivot_offset.x), - size.y*(0.5 + pivot_offset.y), - size.x*(0.5 - pivot_offset.x), - -size.y*(0.5 - pivot_offset.y) - ) -end - - -local function update_border(self) - local input_border = get_border(self.input_zone) - local content_border = get_border(self.node) - - -- border.x - min content.x node pos - -- border.y - min content.y node pos - -- border.z - max content.x node pos - -- border.w - max content.y node pos - self.border = vmath.vector4( - input_border.x - content_border.x, - -input_border.w + content_border.w, - input_border.z - content_border.z, - -input_border.y + content_border.y - ) - self.can_x = (self.border.x ~= self.border.z) - self.can_y = (self.border.y ~= self.border.w) -end - - - -local function set_pos(self, pos) - if self.pos.x ~= pos.x or self.pos.y ~= pos.y then - self.pos.x = pos.x - self.pos.y = pos.y - gui.set_position(self.node, self.pos) - - self.on_scroll:trigger(self:get_context(), self.pos) - end -end - - ---- Return scroll, if it outside of scroll area --- Using the lerp with BACK_SPEED koef -local function check_soft_target(self) - local t = self.target - local b = self.border - - if t.y < b.y then - t.y = helper.step(t.y, b.y, math.abs(t.y - b.y) * self.style.BACK_SPEED) - end - if t.x > b.x then - t.x = helper.step(t.x, b.x, math.abs(t.x - b.x) * self.style.BACK_SPEED) - end - if t.y > b.w then - t.y = helper.step(t.y, b.w, math.abs(t.y - b.w) * self.style.BACK_SPEED) - end - if t.x < b.z then - t.x = helper.step(t.x, b.z, math.abs(t.x - b.z) * self.style.BACK_SPEED) - end -end - - ---- Free inert update function -local function update_hand_scroll(self, dt) - local inert = self.inert - local delta_x = self.target.x - self.pos.x - local delta_y = self.target.y - self.pos.y - - if helper.sign(delta_x) ~= helper.sign(inert.x) then - inert.x = 0 - end - if helper.sign(delta_y) ~= helper.sign(inert.y) then - inert.y = 0 - end - - inert.x = inert.x + delta_x - inert.y = inert.y + delta_y - - inert.x = math.abs(inert.x) * helper.sign(delta_x) - inert.y = math.abs(inert.y) * helper.sign(delta_y) - - inert.x = inert.x * self.style.FRICT_HOLD - inert.y = inert.y * self.style.FRICT_HOLD - - set_pos(self, self.target) -end - - -local function get_zone_center(self) - return self.pos + self.center_offset -end - - ---- Find closer point of interest --- if no inert, scroll to next point by scroll direction --- if inert, find next point by scroll director --- @local -local function check_points(self) - if not self.points then - return - end - - local inert = self.inert - if not self.is_inert then - if math.abs(inert.x) > self.style.DEADZONE then - self:scroll_to_index(self.selected - helper.sign(inert.x)) - return - end - if math.abs(inert.y) > self.style.DEADZONE then - self:scroll_to_index(self.selected + helper.sign(inert.y)) - return - end - end - - -- Find closest point and point by scroll direction - -- Scroll to one of them (by scroll direction in priority) - local temp_dist = math.huge - local temp_dist_on_inert = math.huge - local index = false - local index_on_inert = false - local pos = get_zone_center(self) - for i = 1, #self.points do - local p = self.points[i] - local dist = helper.distance(pos.x, pos.y, p.x, p.y) - local on_inert = true - -- If inert ~= 0, scroll only by move direction - if inert.x ~= 0 and helper.sign(inert.x) ~= helper.sign(p.x - pos.x) then - on_inert = false - end - if inert.y ~= 0 and helper.sign(inert.y) ~= helper.sign(p.y - pos.y) then - on_inert = false - end - - if dist < temp_dist then - index = i - temp_dist = dist - end - if on_inert and dist < temp_dist_on_inert then - index_on_inert = i - temp_dist_on_inert = dist - end - end - - self:scroll_to_index(index_on_inert or index) -end - - -local function check_threshold(self) - local inert = self.inert - if not self.is_inert or vmath.length(inert) < self.style.INERT_THRESHOLD then - check_points(self) - inert.x = 0 - inert.y = 0 - end -end - - -local function update_free_inert(self, dt) - local inert = self.inert - if inert.x ~= 0 or inert.y ~= 0 then - self.target.x = self.pos.x + (inert.x * dt * self.style.INERT_SPEED) - self.target.y = self.pos.y + (inert.y * dt * self.style.INERT_SPEED) - - inert.x = inert.x * self.style.FRICT - inert.y = inert.y * self.style.FRICT - - -- Stop, when low inert speed and go to points - check_threshold(self) - end - - check_soft_target(self) - set_pos(self, self.target) -end - - ---- Cancel animation on other animation or input touch -local function cancel_animate(self) - if self.animate then - self.target = gui.get_position(self.node) - self.pos.x = self.target.x - self.pos.y = self.target.y - gui.cancel_animation(self.node, gui.PROP_POSITION) - self.animate = false - end -end - - -local function add_delta(self, dx, dy) - local t = self.target - local b = self.border - local soft = self.soft_size - - -- TODO: Can we calc it more easier? - -- A lot of calculations for every side of border +local function on_scroll_drag(self, dx, dy) + dy = -dy + local t = self.target_pos + local b = self.available_soft_pos + local soft = 100 -- Handle soft zones -- Percent - multiplier for delta. Less if outside of scroll zone local x_perc = 1 local y_perc = 1 - if t.x > b.x and dx < 0 then + if t.x < b.x and dx < 0 then x_perc = (soft - (b.x - t.x)) / soft end - if t.x < b.z and dx > 0 then + if t.x > b.z and dx > 0 then x_perc = (soft - (t.x - b.z)) / soft end -- If disabled scroll by x @@ -263,11 +40,11 @@ local function add_delta(self, dx, dy) x_perc = 0 end - if t.y < b.y and dy < 0 then - y_perc = (soft - (b.y - t.y)) / soft + if t.y > b.y and dy < 0 then + y_perc = (soft - (t.y - b.y)) / soft end - if t.y > b.w and dy > 0 then - y_perc = (soft - (t.y - b.w)) / soft + if t.y < b.w and dy > 0 then + y_perc = (soft - (b.w - t.y)) / soft end -- If disabled scroll by y if not self.can_y then @@ -276,121 +53,203 @@ local function add_delta(self, dx, dy) -- Reset inert if outside of scroll zone if x_perc ~= 1 then - self.inert.x = 0 + self.inertion.x = 0 end if y_perc ~= 1 then - self.inert.y = 0 + self.inertion.y = 0 end t.x = t.x + dx * x_perc - t.y = t.y + dy * y_perc + t.y = t.y - dy * y_perc +end + + +local function set_pos(self, position) + if self.current_pos.x ~= position.x or self.current_pos.y ~= position.y then + self.current_pos.x = position.x + self.current_pos.y = position.y + gui.set_position(self.content_node, position) + + self.on_scroll:trigger(self:get_context(), self.current_pos) + end +end + + +local function update_hand_scroll(self, dt) + local dx = self.target_pos.x - self.current_pos.x + local dy = self.target_pos.y - self.current_pos.y + + if helper.sign(dx) ~= helper.sign(self.inertion.x) then + self.inertion.x = 0 + end + if helper.sign(dy) ~= helper.sign(self.inertion.y) then + self.inertion.y = 0 + end + + self.inertion.x = self.inertion.x + dx + self.inertion.y = self.inertion.y + dy + + self.inertion.x = math.abs(self.inertion.x) * helper.sign(dx) + self.inertion.y = math.abs(self.inertion.y) * helper.sign(dy) + + self.inertion.x = self.inertion.x * self.style.FRICT_HOLD + self.inertion.y = self.inertion.y * self.style.FRICT_HOLD + + set_pos(self, self.target_pos) +end + + +local function check_soft_zone(self) + local t = self.target_pos + local b = self.available_soft_pos + + if t.y > b.y then + t.y = helper.step(t.y, b.y, math.abs(t.y - b.y) * self.style.BACK_SPEED) + end + if t.x < b.x then + t.x = helper.step(t.x, b.x, math.abs(t.x - b.x) * self.style.BACK_SPEED) + end + if t.y < b.w then + t.y = helper.step(t.y, b.w, math.abs(t.y - b.w) * self.style.BACK_SPEED) + end + if t.x > b.z then + t.x = helper.step(t.x, b.z, math.abs(t.x - b.z) * self.style.BACK_SPEED) + end +end + + +local function check_threshold(self) + if vmath.length(self.inertion) < self.style.INERT_THRESHOLD then + self.inertion.x = 0 + self.inertion.y = 0 + end +end + + +local function update_free_scroll(self, dt) + local target = self.target_pos + + -- Inertion apply + target.x = self.current_pos.x + self.inertion.x * self.style.INERT_SPEED * dt + target.y = self.current_pos.y + self.inertion.y * self.style.INERT_SPEED * dt + + -- Inertion friction + self.inertion = self.inertion * self.style.FRICT + + check_threshold(self) + check_soft_zone(self) + set_pos(self, target) +end + + +local function on_touch_start(self) + self.inertion.x = 0 + self.inertion.y = 0 + self.target_pos.x = self.current_pos.x + self.target_pos.y = self.current_pos.y +end + + +local function update_size(self) + self.view_size = helper.get_border(self.view_node) + self.content_soft_size = helper.get_border(self.content_node) + + self.available_soft_pos = vmath.vector4( + self.content_soft_size.x - self.view_size.x, + self.content_soft_size.y - self.view_size.y, + self.content_soft_size.z - self.view_size.z, + self.content_soft_size.w - self.view_size.w + ) + + self.can_x = math.abs(self.available_soft_pos.x - self.available_soft_pos.z) > 0 + self.can_y = math.abs(self.available_soft_pos.y - self.available_soft_pos.w) > 0 + + self.drag.can_x = self.can_x + self.drag.can_y = self.can_y + + self.content_size = helper.get_border(self.content_node) + + if self.can_x then + self.content_size.x = self.content_size.x + self.style.EXTRA_STRECH_SIZE.x + self.content_size.z = self.content_size.z + self.style.EXTRA_STRECH_SIZE.z + end + + if self.can_y then + self.content_size.y = self.content_size.y + self.style.EXTRA_STRECH_SIZE.y + self.content_size.w = self.content_size.w + self.style.EXTRA_STRECH_SIZE.w + end + + self.available_pos = vmath.vector4( + self.content_size.x - self.view_size.x, + self.content_size.y - self.view_size.y, + self.content_size.z - self.view_size.z, + self.content_size.w - self.view_size.w + ) + + print("view", self.view_size) + print("soft size", self.content_soft_size) + print("content size", self.content_size) + print(self.can_x, self.can_y) + print("available pos", self.available_pos) + print("current pos", self.current_pos) +end + + +--- Cancel animation on other animation or input touch +local function cancel_animate(self) + if self.animate then + self.target_pos = gui.get_position(self.content_node) + self.current_pos.x = self.target_pos.x + self.current_pos.y = self.target_pos.y + gui.cancel_animation(self.content_node, gui.PROP_POSITION) + self.animate = false + end end --- Component init function --- @function scroll:init --- @tparam node scroll_parent Gui node where placed scroll content. This node will change position --- @tparam node input_zone Gui node where input is catched -function M.init(self, scroll_parent, input_zone) +-- @function swipe:init +-- @tparam node node Gui node +-- @tparam function on_swipe_callback Swipe callback for on_swipe_end event +function M.init(self, view_zone, content_zone) + self.druid = self:get_druid() self.style = self:get_style() - self.node = self:get_node(scroll_parent) - self.input_zone = self:get_node(input_zone) - self.zone_size = gui.get_size(self.input_zone) - self.soft_size = self.style.SOFT_ZONE_SIZE + self.view_node = self:get_node(view_zone) + self.content_node = self:get_node(content_zone) - -- Distance from node to node's center - local offset = helper.get_pivot_offset(gui.get_pivot(self.input_zone)) - self.center_offset = vmath.vector3(self.zone_size) - self.center_offset.x = self.center_offset.x * offset.x - self.center_offset.y = self.center_offset.y * offset.y - self.is_inert = true - self.inert = vmath.vector3(0) - self.pos = gui.get_position(self.node) - self.target = vmath.vector3(self.pos) + self.current_pos = gui.get_position(self.content_node) + self.target_pos = vmath.vector3(self.current_pos) + self.inertion = vmath.vector3() - self.input = { - touch = false, - start_x = 0, - start_y = 0, - side = false, - } - - update_border(self) + self.drag = self.druid:new_drag(view_zone, on_scroll_drag) + self.drag.on_touch_start:subscribe(on_touch_start) self.on_scroll = Event() self.on_scroll_to = Event() self.on_point_scroll = Event() + + update_size(self) +end + + +function M.set_size(self, size) + pprint(size) + gui.set_size(self.content_node, size) + update_size(self) end function M.update(self, dt) - if self.input.touch then - if M.current_scroll == self then - update_hand_scroll(self, dt) - end + if self.drag.is_drag then + update_hand_scroll(self, dt) else - update_free_inert(self, dt) + update_free_scroll(self, dt) end end -function M.on_input(self, action_id, action) - if action_id ~= const.ACTION_TOUCH then - return false - end - local inp = self.input - local inert = self.inert - local result = false - - if gui.pick_node(self.input_zone, action.x, action.y) then - if action.pressed then - inp.touch = true - inp.start_x = action.x - inp.start_y = action.y - inert.x = 0 - inert.y = 0 - self.target.x = self.pos.x - self.target.y = self.pos.y - else - local dist = helper.distance(action.x, action.y, inp.start_x, inp.start_y) - if not M.current_scroll and dist >= self.style.DEADZONE then - local dx = math.abs(inp.start_x - action.x) - local dy = math.abs(inp.start_y - action.y) - inp.side = (dx > dy) and const.SIDE.X or const.SIDE.Y - - -- Check scroll side if we can scroll - if (self.can_x and inp.side == const.SIDE.X or - self.can_y and inp.side == const.SIDE.Y) then - M.current_scroll = self - end - end - end - end - - if inp.touch and not action.pressed then - if M.current_scroll == self then - add_delta(self, action.dx, action.dy) - result = true - end - end - - if action.released then - inp.touch = false - inp.side = false - if M.current_scroll == self then - M.current_scroll = nil - result = true - end - - check_threshold(self) - end - - return result -end - - --- Start scroll to target point -- @function scroll:scroll_to -- @tparam point vector3 target point @@ -422,11 +281,6 @@ function M.scroll_to(self, point, is_instant) end ---- Start scroll to target scroll percent --- @function scroll:scroll_to_percent --- @tparam point vector3 target percent --- @tparam[opt] bool is_instant instant scroll flag --- @usage scroll:scroll_to_percent(vmath.vector3(0.5, 0, 0)) function M.scroll_to_percent(self, percent, is_instant) local border = self.border @@ -447,91 +301,14 @@ function M.scroll_to_percent(self, percent, is_instant) end ---- Scroll to item in scroll by point index --- @function scroll:init --- @tparam number index Point index --- @tparam[opt] bool skip_cb If true, skip the point callback -function M.scroll_to_index(self, index, skip_cb) - index = helper.clamp(index, 1, #self.points) +function M.get_percent(self) + local y_dist = self.available_soft_pos.y - self.available_soft_pos.w + local y_perc = y_dist ~= 0 and (self.current_pos.y - self.available_soft_pos.w) / y_dist or 1 - if self.selected ~= index then - self.selected = index + local x_dist = self.available_soft_pos.z - self.available_soft_pos.x + local x_perc = x_dist ~= 0 and (self.current_pos.x - self.available_soft_pos.z) / x_dist or 1 - if not skip_cb then - self.on_point_scroll:trigger(self:get_context(), index, self.points[index]) - end - end - - self:scroll_to(self.points[index]) -end - - ---- Set points of interest. --- Scroll will always centered on closer points --- @function scroll:set_points --- @tparam table points Array of vector3 points -function M.set_points(self, points) - self.points = points - -- cause of parent move in other side by y - for i = 1, #self.points do - self.points[i].y = -self.points[i].y - end - - table.sort(self.points, function(a, b) - return a.x > b.x or a.y < b.y - end) - check_threshold(self) -end - - ---- Enable or disable scroll inert. --- If disabled, scroll through points (if exist) --- If no points, just simple drag without inertion --- @function scroll:set_inert --- @tparam bool state Inert scroll state -function M.set_inert(self, state) - self.is_inert = state -end - - ---- Set the callback on scrolling to point (if exist) --- @function scroll:on_point_move --- @tparam function callback Callback on scroll to point of interest -function M.on_point_move(self, callback) - self.on_point_scroll:subscribe(callback) -end - - ---- Set the scroll possibly area --- @function scroll:set_border --- @tparam vector3 border Size of scrolling area -function M.set_border(self, content_size) - gui.set_size(self.node, content_size) - update_border(self) -end - - ---- Return current scroll progress --- @function scroll:get_scroll_percent --- @treturn vector3 Scroll progress -function M.get_scroll_percent(self) - local border = self.border - local size_x = math.abs(border.z - border.x) - if size_x == 0 then - size_x = 1 - end - - local size_y = math.abs(border.w - border.y) - if size_y == 0 then - size_y = 1 - end - local pos = self.pos - - return vmath.vector3( - (border.x - pos.x) / size_x, - (border.y - pos.y) / size_y, - 0 - ) + return vmath.vector3(x_perc, y_perc, 0) end diff --git a/druid/base/scroll_legacy.lua b/druid/base/scroll_legacy.lua new file mode 100644 index 0000000..56a50aa --- /dev/null +++ b/druid/base/scroll_legacy.lua @@ -0,0 +1,538 @@ +--- Component to handle scroll content. +-- Scroll consist from two nodes: scroll parent and scroll input +-- Scroll input the user input zone, it's static +-- Scroll parent the scroll moving part, it will change position. +-- Setup initial scroll size by changing scroll parent size. If scroll parent +-- size will be less than scroll_input size, no scroll is available. For scroll +-- parent size should be more than input size +-- @module druid.scroll + +--- Component events +-- @table Events +-- @tfield druid_event on_scroll On scroll move callback +-- @tfield druid_event on_scroll_to On scroll_to function callback +-- @tfield druid_event on_point_scroll On scroll_to_index function callback + +--- Component fields +-- @table Fields +-- @tfield node node Scroll parent node +-- @tfield node input_zone Scroll input node +-- @tfield vector3 zone_size Current scroll content size +-- @tfield number soft_size Soft zone size from style table +-- @tfield vector3 center_offset Distance from node to node's center +-- @tfield bool is_inert Flag, if scroll now moving by inertion +-- @tfield vector3 inert Current inert speed +-- @tfield vector3 pos Current scroll posisition +-- @tfield vector3 target Current scroll target position + +--- Component style params +-- @table Style +-- @tfield number FRICT_HOLD Multiplier for inertion, while touching +-- @tfield number FRICT Multiplier for free inertion +-- @tfield number INERT_THRESHOLD Scroll speed to stop inertion +-- @tfield number INERT_SPEED Multiplier for inertion speed +-- @tfield number DEADZONE Deadzone for start scrol in pixels +-- @tfield number SOFT_ZONE_SIZE Size of outside zone in pixels (for scroll back moving) +-- @tfield number BACK_SPEED Scroll back returning lerp speed +-- @tfield number ANIM_SPEED Scroll gui.animation speed for scroll_to function + +local Event = require("druid.event") +local helper = require("druid.helper") +local const = require("druid.const") +local component = require("druid.component") + +local M = component.create("scroll", { const.ON_UPDATE, const.ON_INPUT_HIGH }) + + +-- Global on all scrolls +-- TODO: remove it +M.current_scroll = nil + + +local function get_border(node) + local pivot = gui.get_pivot(node) + local pivot_offset = helper.get_pivot_offset(pivot) + local size = vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node)) + return vmath.vector4( + -size.x*(0.5 + pivot_offset.x), + size.y*(0.5 + pivot_offset.y), + size.x*(0.5 - pivot_offset.x), + -size.y*(0.5 - pivot_offset.y) + ) +end + + +local function update_border(self) + local input_border = get_border(self.input_zone) + local content_border = get_border(self.node) + + -- border.x - min content.x node pos + -- border.y - min content.y node pos + -- border.z - max content.x node pos + -- border.w - max content.y node pos + self.border = vmath.vector4( + input_border.x - content_border.x, + -input_border.w + content_border.w, + input_border.z - content_border.z, + -input_border.y + content_border.y + ) + self.can_x = (self.border.x ~= self.border.z) + self.can_y = (self.border.y ~= self.border.w) +end + + + +local function set_pos(self, pos) + if self.pos.x ~= pos.x or self.pos.y ~= pos.y then + self.pos.x = pos.x + self.pos.y = pos.y + gui.set_position(self.node, self.pos) + + self.on_scroll:trigger(self:get_context(), self.pos) + end +end + + +--- Return scroll, if it outside of scroll area +-- Using the lerp with BACK_SPEED koef +local function check_soft_target(self) + local t = self.target + local b = self.border + + if t.y < b.y then + t.y = helper.step(t.y, b.y, math.abs(t.y - b.y) * self.style.BACK_SPEED) + end + if t.x > b.x then + t.x = helper.step(t.x, b.x, math.abs(t.x - b.x) * self.style.BACK_SPEED) + end + if t.y > b.w then + t.y = helper.step(t.y, b.w, math.abs(t.y - b.w) * self.style.BACK_SPEED) + end + if t.x < b.z then + t.x = helper.step(t.x, b.z, math.abs(t.x - b.z) * self.style.BACK_SPEED) + end +end + + +--- Free inert update function +local function update_hand_scroll(self, dt) + local inert = self.inert + local delta_x = self.target.x - self.pos.x + local delta_y = self.target.y - self.pos.y + + if helper.sign(delta_x) ~= helper.sign(inert.x) then + inert.x = 0 + end + if helper.sign(delta_y) ~= helper.sign(inert.y) then + inert.y = 0 + end + + inert.x = inert.x + delta_x + inert.y = inert.y + delta_y + + inert.x = math.abs(inert.x) * helper.sign(delta_x) + inert.y = math.abs(inert.y) * helper.sign(delta_y) + + inert.x = inert.x * self.style.FRICT_HOLD + inert.y = inert.y * self.style.FRICT_HOLD + + set_pos(self, self.target) +end + + +local function get_zone_center(self) + return self.pos + self.center_offset +end + + +--- Find closer point of interest +-- if no inert, scroll to next point by scroll direction +-- if inert, find next point by scroll director +-- @local +local function check_points(self) + if not self.points then + return + end + + local inert = self.inert + if not self.is_inert then + if math.abs(inert.x) > self.style.DEADZONE then + self:scroll_to_index(self.selected - helper.sign(inert.x)) + return + end + if math.abs(inert.y) > self.style.DEADZONE then + self:scroll_to_index(self.selected + helper.sign(inert.y)) + return + end + end + + -- Find closest point and point by scroll direction + -- Scroll to one of them (by scroll direction in priority) + local temp_dist = math.huge + local temp_dist_on_inert = math.huge + local index = false + local index_on_inert = false + local pos = get_zone_center(self) + for i = 1, #self.points do + local p = self.points[i] + local dist = helper.distance(pos.x, pos.y, p.x, p.y) + local on_inert = true + -- If inert ~= 0, scroll only by move direction + if inert.x ~= 0 and helper.sign(inert.x) ~= helper.sign(p.x - pos.x) then + on_inert = false + end + if inert.y ~= 0 and helper.sign(inert.y) ~= helper.sign(p.y - pos.y) then + on_inert = false + end + + if dist < temp_dist then + index = i + temp_dist = dist + end + if on_inert and dist < temp_dist_on_inert then + index_on_inert = i + temp_dist_on_inert = dist + end + end + + self:scroll_to_index(index_on_inert or index) +end + + +local function check_threshold(self) + local inert = self.inert + if not self.is_inert or vmath.length(inert) < self.style.INERT_THRESHOLD then + check_points(self) + inert.x = 0 + inert.y = 0 + end +end + + +local function update_free_inert(self, dt) + local inert = self.inert + if inert.x ~= 0 or inert.y ~= 0 then + self.target.x = self.pos.x + (inert.x * dt * self.style.INERT_SPEED) + self.target.y = self.pos.y + (inert.y * dt * self.style.INERT_SPEED) + + inert.x = inert.x * self.style.FRICT + inert.y = inert.y * self.style.FRICT + + -- Stop, when low inert speed and go to points + check_threshold(self) + end + + check_soft_target(self) + set_pos(self, self.target) +end + + +--- Cancel animation on other animation or input touch +local function cancel_animate(self) + if self.animate then + self.target = gui.get_position(self.node) + self.pos.x = self.target.x + self.pos.y = self.target.y + gui.cancel_animation(self.node, gui.PROP_POSITION) + self.animate = false + end +end + + +local function add_delta(self, dx, dy) + local t = self.target + local b = self.border + local soft = self.soft_size + + -- TODO: Can we calc it more easier? + -- A lot of calculations for every side of border + + -- Handle soft zones + -- Percent - multiplier for delta. Less if outside of scroll zone + local x_perc = 1 + local y_perc = 1 + + if t.x > b.x and dx < 0 then + x_perc = (soft - (b.x - t.x)) / soft + end + if t.x < b.z and dx > 0 then + x_perc = (soft - (t.x - b.z)) / soft + end + -- If disabled scroll by x + if not self.can_x then + x_perc = 0 + end + + if t.y < b.y and dy < 0 then + y_perc = (soft - (b.y - t.y)) / soft + end + if t.y > b.w and dy > 0 then + y_perc = (soft - (t.y - b.w)) / soft + end + -- If disabled scroll by y + if not self.can_y then + y_perc = 0 + end + + -- Reset inert if outside of scroll zone + if x_perc ~= 1 then + self.inert.x = 0 + end + if y_perc ~= 1 then + self.inert.y = 0 + end + + t.x = t.x + dx * x_perc + t.y = t.y + dy * y_perc +end + + +--- Component init function +-- @function scroll:init +-- @tparam node scroll_parent Gui node where placed scroll content. This node will change position +-- @tparam node input_zone Gui node where input is catched +function M.init(self, scroll_parent, input_zone) + self.style = self:get_style() + self.node = self:get_node(scroll_parent) + self.input_zone = self:get_node(input_zone) + + self.zone_size = gui.get_size(self.input_zone) + self.soft_size = self.style.SOFT_ZONE_SIZE + + -- Distance from node to node's center + local offset = helper.get_pivot_offset(gui.get_pivot(self.input_zone)) + self.center_offset = vmath.vector3(self.zone_size) + self.center_offset.x = self.center_offset.x * offset.x + self.center_offset.y = self.center_offset.y * offset.y + + self.is_inert = true + self.inert = vmath.vector3(0) + self.pos = gui.get_position(self.node) + self.target = vmath.vector3(self.pos) + + self.input = { + touch = false, + start_x = 0, + start_y = 0, + side = false, + } + + update_border(self) + + self.on_scroll = Event() + self.on_scroll_to = Event() + self.on_point_scroll = Event() +end + + +function M.update(self, dt) + if self.input.touch then + if M.current_scroll == self then + update_hand_scroll(self, dt) + end + else + update_free_inert(self, dt) + end +end + + +function M.on_input(self, action_id, action) + if action_id ~= const.ACTION_TOUCH then + return false + end + local inp = self.input + local inert = self.inert + local result = false + + if gui.pick_node(self.input_zone, action.x, action.y) then + if action.pressed then + inp.touch = true + inp.start_x = action.x + inp.start_y = action.y + inert.x = 0 + inert.y = 0 + self.target.x = self.pos.x + self.target.y = self.pos.y + else + local dist = helper.distance(action.x, action.y, inp.start_x, inp.start_y) + if not M.current_scroll and dist >= self.style.DEADZONE then + local dx = math.abs(inp.start_x - action.x) + local dy = math.abs(inp.start_y - action.y) + inp.side = (dx > dy) and const.SIDE.X or const.SIDE.Y + + -- Check scroll side if we can scroll + if (self.can_x and inp.side == const.SIDE.X or + self.can_y and inp.side == const.SIDE.Y) then + M.current_scroll = self + end + end + end + end + + if inp.touch and not action.pressed then + if M.current_scroll == self then + add_delta(self, action.dx, action.dy) + result = true + end + end + + if action.released then + inp.touch = false + inp.side = false + if M.current_scroll == self then + M.current_scroll = nil + result = true + end + + check_threshold(self) + end + + return result +end + + +--- Start scroll to target point +-- @function scroll:scroll_to +-- @tparam point vector3 target point +-- @tparam[opt] bool is_instant instant scroll flag +-- @usage scroll:scroll_to(vmath.vector3(0, 50, 0)) +-- @usage scroll:scroll_to(vmath.vector3(0), true) +function M.scroll_to(self, point, is_instant) + local b = self.border + local target = vmath.vector3(point) + target.x = helper.clamp(point.x - self.center_offset.x, b.x, b.z) + target.y = helper.clamp(point.y - self.center_offset.y, b.y, b.w) + + cancel_animate(self) + + self.animate = not is_instant + + if is_instant then + self.target = target + set_pos(self, target) + else + gui.animate(self.node, gui.PROP_POSITION, target, gui.EASING_OUTSINE, self.style.ANIM_SPEED, 0, function() + self.animate = false + self.target = target + set_pos(self, target) + end) + end + + self.on_scroll_to:trigger(self:get_context(), target, is_instant) +end + + +--- Start scroll to target scroll percent +-- @function scroll:scroll_to_percent +-- @tparam point vector3 target percent +-- @tparam[opt] bool is_instant instant scroll flag +-- @usage scroll:scroll_to_percent(vmath.vector3(0.5, 0, 0)) +function M.scroll_to_percent(self, percent, is_instant) + local border = self.border + + local size_x = math.abs(border.z - border.x) + if size_x == 0 then + size_x = 1 + end + local size_y = math.abs(border.w - border.y) + if size_y == 0 then + size_y = 1 + end + + local pos = vmath.vector3( + -size_x * percent.x + border.x, + -size_y * percent.y + border.y, + 0) + M.scroll_to(self, pos, is_instant) +end + + +--- Scroll to item in scroll by point index +-- @function scroll:init +-- @tparam number index Point index +-- @tparam[opt] bool skip_cb If true, skip the point callback +function M.scroll_to_index(self, index, skip_cb) + index = helper.clamp(index, 1, #self.points) + + if self.selected ~= index then + self.selected = index + + if not skip_cb then + self.on_point_scroll:trigger(self:get_context(), index, self.points[index]) + end + end + + self:scroll_to(self.points[index]) +end + + +--- Set points of interest. +-- Scroll will always centered on closer points +-- @function scroll:set_points +-- @tparam table points Array of vector3 points +function M.set_points(self, points) + self.points = points + -- cause of parent move in other side by y + for i = 1, #self.points do + self.points[i].y = -self.points[i].y + end + + table.sort(self.points, function(a, b) + return a.x > b.x or a.y < b.y + end) + check_threshold(self) +end + + +--- Enable or disable scroll inert. +-- If disabled, scroll through points (if exist) +-- If no points, just simple drag without inertion +-- @function scroll:set_inert +-- @tparam bool state Inert scroll state +function M.set_inert(self, state) + self.is_inert = state +end + + +--- Set the callback on scrolling to point (if exist) +-- @function scroll:on_point_move +-- @tparam function callback Callback on scroll to point of interest +function M.on_point_move(self, callback) + self.on_point_scroll:subscribe(callback) +end + + +--- Set the scroll possibly area +-- @function scroll:set_border +-- @tparam vector3 border Size of scrolling area +function M.set_border(self, content_size) + gui.set_size(self.node, content_size) + update_border(self) +end + + +--- Return current scroll progress +-- @function scroll:get_scroll_percent +-- @treturn vector3 Scroll progress +function M.get_scroll_percent(self) + local border = self.border + local size_x = math.abs(border.z - border.x) + if size_x == 0 then + size_x = 1 + end + + local size_y = math.abs(border.w - border.y) + if size_y == 0 then + size_y = 1 + end + local pos = self.pos + + return vmath.vector3( + (border.x - pos.x) / size_x, + (border.y - pos.y) / size_y, + 0 + ) +end + + +return M diff --git a/druid/const.lua b/druid/const.lua index ae6d4ce..8e5c4ac 100644 --- a/druid/const.lua +++ b/druid/const.lua @@ -63,11 +63,22 @@ M.UI_INPUT = { } +M.OS = { + ANDROID = "Android", + IOS = "iPhone OS", + MAC = "Darwin", + LINUX = "Linux", + WINDOWS = "Windows", + BROWSER = "HTML5", +} + + M.SIDE = { X = "x", Y = "y" } + M.SWIPE = { UP = "up", DOWN = "down", diff --git a/druid/helper.lua b/druid/helper.lua index ccd08a4..14d17ae 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -152,4 +152,32 @@ function M.get_pivot_offset(pivot) end +--- Check if device is mobile (Android or iOS) +-- @function helper..is_mobile +function M.is_mobile() + local system_name = sys.get_sys_info().system_name + return system_name == const.OS.IOS or system_name == const.OS.ANDROID +end + + +--- Check if device is HTML5 +-- @function helper.is_web +function M.is_web() + local system_name = sys.get_sys_info().system_name + return system_name == const.OS.BROWSER +end + + +function M.get_border(node) + local pivot = gui.get_pivot(node) + local pivot_offset = M.get_pivot_offset(pivot) + local size = vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node)) + return vmath.vector4( + -size.x*(0.5 - pivot_offset.x), + size.y*(0.5 + pivot_offset.y), + size.x*(0.5 + pivot_offset.x), + -size.y*(0.5 - pivot_offset.y) + ) +end + return M diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index 817a4d4..b05dd48 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -43,16 +43,24 @@ M["button"] = { } +M["drag"] = { + DRAG_DEADZONE = 10, +} + + M["scroll"] = { - FRICT_HOLD = 0.8, -- mult. for inert, while touching + ANIM_SPEED = 0.3, -- gui.animation speed to point + SCROLL_WHEEL_SPEED = 10, + FRICT = 0.93, -- mult for free inert + FRICT_HOLD = 0.8, -- mult. for inert, while touching INERT_THRESHOLD = 2, -- speed to stop inertion INERT_SPEED = 25, -- koef. of inert speed - DEADZONE = 6, -- in px - SOFT_ZONE_SIZE = 160, -- size of outside zone (back move) - SCROLL_WHEEL_SPEED = 10, + EXTRA_STRECH_SIZE = vmath.vector4(-100, 100, 100, -100), -- size of outside zone (back move) + BACK_SPEED = 0.2, -- lerp speed - ANIM_SPEED = 0.3, -- gui.animation speed to point + LERP_SPEED = 1, + BORDER_LERP_SPEED = 0.3, } diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 9c04b33..d1b3fa7 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -16,6 +16,7 @@ -- @see druid.checkbox_group -- @see druid.radio_group -- @see druid.swipe +-- @see druid.drag local const = require("druid.const") local druid_input = require("druid.helper.druid_input") @@ -38,6 +39,7 @@ local checkbox_group = require("druid.base.checkbox_group") local radio_group = require("druid.base.radio_group") local input = require("druid.base.input") local swipe = require("druid.base.swipe") +local drag = require("druid.base.drag") -- local infinity_scroll = require("druid.base.infinity_scroll") -- @classmod Druid @@ -447,4 +449,9 @@ function Druid.new_swipe(self, ...) end +function Druid.new_drag(self, ...) + return Druid.create(self, drag, ...) +end + + return Druid diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index f1883f8..bce3fa1 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -180,7 +180,7 @@ nodes { nodes { position { x: 0.0 - y: 450.0 + y: 1200.0 z: 0.0 w: 1.0 } @@ -198,7 +198,7 @@ nodes { } size { x: 600.0 - y: 1250.0 + y: 1500.0 z: 0.0 w: 1.0 } @@ -2882,7 +2882,7 @@ nodes { nodes { position { x: 0.0 - y: -890.0 + y: -1890.0 z: 0.0 w: 1.0 } @@ -3225,6 +3225,179 @@ nodes { text_leading: 1.0 text_tracking: 0.0 } +nodes { + position { + x: 0.0 + y: -1150.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 400.0 + y: 400.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.5019608 + y: 0.2 + z: 0.3019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "scroll2_view" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "scroll_content" + layer: "" + inherit_alpha: true + slice9 { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +nodes { + position { + x: 0.0 + y: 200.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 400.0 + y: 800.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.4 + y: 0.3019608 + z: 0.7019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "scroll2_content" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_N + adjust_mode: ADJUST_MODE_FIT + parent: "scroll2_view" + layer: "" + inherit_alpha: true + slice9 { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 + } + clipping_mode: CLIPPING_MODE_NONE + clipping_visible: true + clipping_inverted: false + alpha: 0.5 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +nodes { + position { + x: 0.0 + y: -200.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 200.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_TEXT + blend_mode: BLEND_MODE_ALPHA + text: "Content" + font: "game" + id: "text" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + outline { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + shadow { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + adjust_mode: ADJUST_MODE_FIT + line_break: false + parent: "scroll2_content" + layer: "" + inherit_alpha: true + alpha: 1.0 + outline_alpha: 0.0 + shadow_alpha: 0.0 + template_node_child: false + text_leading: 1.0 + text_tracking: 0.0 +} nodes { position { x: 600.0 @@ -5334,7 +5507,7 @@ nodes { z: 0.0 w: 0.0 } - clipping_mode: CLIPPING_MODE_STENCIL + clipping_mode: CLIPPING_MODE_NONE clipping_visible: true clipping_inverted: false alpha: 1.0 @@ -5389,7 +5562,7 @@ nodes { z: 0.0 w: 0.0 } - clipping_mode: CLIPPING_MODE_NONE + clipping_mode: CLIPPING_MODE_STENCIL clipping_visible: true clipping_inverted: false alpha: 1.0 diff --git a/example/page/main.lua b/example/page/main.lua index a56eab1..4828fbe 100644 --- a/example/page/main.lua +++ b/example/page/main.lua @@ -97,7 +97,8 @@ end local function setup_scroll(self) - self.scroll = self.druid:new_scroll("scroll_content", "main_page") + self.druid:new_scroll("main_page", "scroll_content") + self.scroll = self.druid:new_scroll("scroll2_view", "scroll2_content") end diff --git a/example/page/scroll.lua b/example/page/scroll.lua index 73bc819..284615a 100644 --- a/example/page/scroll.lua +++ b/example/page/scroll.lua @@ -4,7 +4,7 @@ local M = {} local function init_grid(self) local prefab = gui.get_node("grid_prefab") - local grid_scroll = self.druid:new_scroll("grid_content", "scroll_with_grid_size") + local grid_scroll = self.druid:new_scroll("scroll_with_grid_size", "grid_content") local grid = self.druid:new_grid("grid_content", "grid_prefab", 20) for i = 1, 40 do @@ -23,29 +23,29 @@ local function init_grid(self) gui.set_enabled(prefab, false) - grid_scroll:set_border(grid:get_size()) + grid_scroll:set_size(grid:get_size()) local scroll_slider = self.druid:new_slider("grid_scroll_pin", vmath.vector3(300, 0, 0), function(_, value) - grid_scroll:scroll_to_percent(vmath.vector3(value, 0, 0), true) + -- grid_scroll:scroll_to_percent(vmath.vector3(value, 0, 0), true) end) grid_scroll.on_scroll:subscribe(function(_, point) - scroll_slider:set(grid_scroll:get_scroll_percent().x, true) + scroll_slider:set(grid_scroll:get_percent().x, true) end) end function M.setup_page(self) - self.druid:new_scroll("scroll_page_content", "scroll_page") - self.druid:new_scroll("simple_scroll_content", "simple_scroll_input") + self.druid:new_scroll("scroll_page", "scroll_page_content") + self.druid:new_scroll("simple_scroll_input", "simple_scroll_content") -- scroll contain scrolls: -- parent first - self.druid:new_scroll("children_scroll_content", "children_scroll") + self.druid:new_scroll("children_scroll", "children_scroll_content") -- chilren next - self.druid:new_scroll("children_scroll_content_1", "children_scroll_1") - self.druid:new_scroll("children_scroll_content_2", "children_scroll_2") - self.druid:new_scroll("children_scroll_content_3", "children_scroll_3") + self.druid:new_scroll("children_scroll_1", "children_scroll_content_1") + self.druid:new_scroll("children_scroll_2", "children_scroll_content_2") + self.druid:new_scroll("children_scroll_3", "children_scroll_content_3") init_grid(self) end