From 05425fb76c78cc3a3682729de5481f7ee3db0010 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 28 Apr 2020 18:13:43 +0300 Subject: [PATCH 01/11] 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 From f77fa8e8a819cc19a08ae31dd15bd4f7a79c78e5 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 28 Apr 2020 19:06:29 +0300 Subject: [PATCH 02/11] Add multitouch for scroll correct scrolling with several fingers --- druid/base/drag.lua | 12 ++++++------ druid/base/scroll.lua | 1 - druid/const.lua | 1 + druid/styles/default/style.lua | 1 - input/game.input_binding | 12 ++++++++---- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/druid/base/drag.lua b/druid/base/drag.lua index 8c31b7f..f4439d8 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -61,7 +61,7 @@ end local function find_touch(action_id, action, touch_id) - local act = const.ACTION_TOUCH + local act = helper.is_mobile() and const.ACTION_MULTITOUCH or const.ACTION_TOUCH if action_id ~= act then return @@ -135,7 +135,7 @@ end function M.on_input(self, action_id, action) - if action_id ~= const.ACTION_TOUCH then + if action_id ~= const.ACTION_TOUCH and action_id ~= const.ACTION_MULTITOUCH then return end @@ -172,7 +172,7 @@ function M.on_input(self, action_id, action) if touch.released and self.is_touch then if action.touch then -- Mobile - on_touch_release(action_id, action, self) + on_touch_release(self, action_id, action) else -- PC end_touch(self) @@ -189,9 +189,9 @@ function M.on_input(self, action_id, action) 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 + if touch_modified then + self.screen_x = touch_modified.screen_x + self.screen_y = touch_modified.screen_y end if self.is_drag then diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 694fb13..6255c30 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -235,7 +235,6 @@ end function M.set_size(self, size) - pprint(size) gui.set_size(self.content_node, size) update_size(self) end diff --git a/druid/const.lua b/druid/const.lua index 8e5c4ac..1db17e2 100644 --- a/druid/const.lua +++ b/druid/const.lua @@ -14,6 +14,7 @@ M.ACTION_ESC = hash("key_esc") M.ACTION_TOUCH = hash("touch") M.ACTION_SCROLL_UP = hash("scroll_up") +M.ACTION_MULTITOUCH = hash("multitouch") M.ACTION_SCROLL_DOWN = hash("scroll_down") diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index b05dd48..8bd8c60 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -60,7 +60,6 @@ M["scroll"] = { BACK_SPEED = 0.2, -- lerp speed LERP_SPEED = 1, - BORDER_LERP_SPEED = 0.3, } diff --git a/input/game.input_binding b/input/game.input_binding index b873ebd..0b6d8ca 100644 --- a/input/game.input_binding +++ b/input/game.input_binding @@ -18,10 +18,6 @@ key_trigger { input: KEY_ESC action: "key_esc" } -mouse_trigger { - input: MOUSE_BUTTON_1 - action: "touch" -} mouse_trigger { input: MOUSE_WHEEL_UP action: "scroll_up" @@ -30,6 +26,14 @@ mouse_trigger { input: MOUSE_WHEEL_DOWN action: "scroll_down" } +mouse_trigger { + input: MOUSE_BUTTON_1 + action: "touch" +} +touch_trigger { + input: TOUCH_MULTI + action: "multitouch" +} text_trigger { input: TEXT action: "text" From 7d3429f252626a55791b385b7ec24fc1ba0780bd Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 28 Apr 2020 23:22:00 +0300 Subject: [PATCH 03/11] Scroll refactoring progress --- druid/base/drag.lua | 32 +-- druid/base/scroll.lua | 41 +--- druid/styles/default/style.lua | 12 +- example/gui/main/main.gui | 350 +++++++++++++++---------------- example/gui/main/main.gui_script | 8 +- example/page/main.lua | 1 - example/page/scroll.lua | 2 + 7 files changed, 213 insertions(+), 233 deletions(-) diff --git a/druid/base/drag.lua b/druid/base/drag.lua index f4439d8..8eed307 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -22,11 +22,11 @@ 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.touch_start_pos.x = touch.x + self.touch_start_pos.y = touch.y - self.screen_x = touch.screen_x - self.screen_y = touch.screen_y + self.x = touch.x + self.y = touch.y self.on_touch_start:trigger(self:get_context()) end @@ -40,22 +40,24 @@ local function end_touch(self) self.is_drag = false self.is_touch = false self.on_touch_end:trigger(self:get_context()) + self:reset_input_priority() 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 + self.touch_start_pos.x = touch.x end if not self.can_y then - self.touch_start_pos.y = touch.screen_y + self.touch_start_pos.y = touch.y end - local distance = helper.distance(touch.screen_x, touch.screen_y, self.touch_start_pos.x, self.touch_start_pos.y) + local distance = helper.distance(touch.x, touch.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()) + self:increase_input_priority() end end @@ -93,8 +95,8 @@ local function on_touch_release(self, action_id, action) end if next_touch then - self.screen_x = next_touch.screen_x - self.screen_y = next_touch.screen_y + self.x = next_touch.x + self.y = next_touch.y self.touch_id = next_touch.id else end_touch(self) @@ -116,8 +118,8 @@ function M.init(self, node, on_drag_callback) self.dx = 0 self.dy = 0 self.touch_id = 0 - self.screen_x = 0 - self.screen_y = 0 + self.x = 0 + self.y = 0 self.is_touch = false self.is_drag = false self.touch_start_pos = vmath.vector3(0) @@ -185,13 +187,13 @@ function M.on_input(self, action_id, action) 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 + self.dx = touch_modified.x - self.x + self.dy = touch_modified.y - self.y end if touch_modified then - self.screen_x = touch_modified.screen_x - self.screen_y = touch_modified.screen_y + self.x = touch_modified.x + self.y = touch_modified.y end if self.is_drag then diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 6255c30..d1537ae 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -22,7 +22,7 @@ local function on_scroll_drag(self, dx, dy) dy = -dy local t = self.target_pos local b = self.available_soft_pos - local soft = 100 + local extra_size = self.style.EXTRA_STRECH_SIZE -- Handle soft zones -- Percent - multiplier for delta. Less if outside of scroll zone @@ -30,10 +30,10 @@ local function on_scroll_drag(self, dx, dy) local y_perc = 1 if t.x < b.x and dx < 0 then - x_perc = (soft - (b.x - t.x)) / soft + x_perc = (-extra_size.x - (b.x - t.x)) / -extra_size.x end if t.x > b.z and dx > 0 then - x_perc = (soft - (t.x - b.z)) / soft + x_perc = (extra_size.z - (t.x - b.z)) / extra_size.z end -- If disabled scroll by x if not self.can_x then @@ -41,24 +41,16 @@ local function on_scroll_drag(self, dx, dy) end if t.y > b.y and dy < 0 then - y_perc = (soft - (t.y - b.y)) / soft + y_perc = (extra_size.y - (t.y - b.y)) / extra_size.y end if t.y < b.w and dy > 0 then - y_perc = (soft - (b.w - t.y)) / soft + y_perc = (-extra_size.w - (b.w - t.y)) / -extra_size.w 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.inertion.x = 0 - end - if y_perc ~= 1 then - self.inertion.y = 0 - end - t.x = t.x + dx * x_perc t.y = t.y - dy * y_perc end @@ -79,21 +71,8 @@ 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 + self.inertion.x = (self.inertion.x + dx) * self.style.FRICT_HOLD + self.inertion.y = (self.inertion.y + dy) * self.style.FRICT_HOLD set_pos(self, self.target_pos) end @@ -119,8 +98,10 @@ end local function check_threshold(self) - if vmath.length(self.inertion) < self.style.INERT_THRESHOLD then + if math.abs(self.inertion.x) < self.style.INERT_THRESHOLD then self.inertion.x = 0 + end + if math.abs(self.inertion.y) < self.style.INERT_THRESHOLD then self.inertion.y = 0 end end @@ -221,7 +202,7 @@ function M.init(self, view_zone, content_zone) self.current_pos = gui.get_position(self.content_node) self.target_pos = vmath.vector3(self.current_pos) - self.inertion = vmath.vector3() + self.inertion = vmath.vector3(0) self.drag = self.druid:new_drag(view_zone, on_scroll_drag) self.drag.on_touch_start:subscribe(on_touch_start) diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index 8bd8c60..10d0953 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -52,14 +52,14 @@ M["scroll"] = { 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 + FRICT = 0.94, -- mult for free inert + FRICT_HOLD = 0.75, -- mult. for inert, while touching INERT_THRESHOLD = 2, -- speed to stop inertion - INERT_SPEED = 25, -- koef. of inert speed - EXTRA_STRECH_SIZE = vmath.vector4(-100, 100, 100, -100), -- size of outside zone (back move) + INERT_SPEED = 27, -- koef. of inert speed - BACK_SPEED = 0.2, -- lerp speed - LERP_SPEED = 1, + BACK_SPEED = 0.35, -- Lerp speed of return to soft position + + EXTRA_STRECH_SIZE = vmath.vector4(-100, 100, 100, -100), -- size of outside zone (back move) } diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index bce3fa1..3675838 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -180,7 +180,7 @@ nodes { nodes { position { x: 0.0 - y: 1200.0 + y: 450.0 z: 0.0 w: 1.0 } @@ -2882,7 +2882,7 @@ nodes { nodes { position { x: 0.0 - y: -1890.0 + y: -890.0 z: 0.0 w: 1.0 } @@ -3225,179 +3225,6 @@ 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 @@ -6962,6 +6789,179 @@ nodes { text_leading: 1.0 text_tracking: 0.0 } +nodes { + position { + x: 0.0 + y: -1400.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: 550.0 + y: 500.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: "scroll_smaller_view" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "scroll_page_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: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 200.0 + y: 200.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: "scroll_smaller_content" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "scroll_smaller_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: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 200.0 + y: 100.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_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: "scroll_smaller_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: 2400.0 diff --git a/example/gui/main/main.gui_script b/example/gui/main/main.gui_script index f38a0ae..ba4ef8d 100644 --- a/example/gui/main/main.gui_script +++ b/example/gui/main/main.gui_script @@ -21,12 +21,8 @@ local pages = { local function on_control_button(self, delta) self.page = self.page + delta - if self.page < 1 then - self.page = #pages - end - if self.page > #pages then - self.page = 1 - end + self.page = math.max(1, self.page) + self.page = math.min(self.page, #pages) self.header:translate(pages[self.page]) local node = gui.get_node("C_Anchor") diff --git a/example/page/main.lua b/example/page/main.lua index 4828fbe..5563c0d 100644 --- a/example/page/main.lua +++ b/example/page/main.lua @@ -98,7 +98,6 @@ end local function setup_scroll(self) 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 284615a..205b4e8 100644 --- a/example/page/scroll.lua +++ b/example/page/scroll.lua @@ -47,6 +47,8 @@ function M.setup_page(self) self.druid:new_scroll("children_scroll_2", "children_scroll_content_2") self.druid:new_scroll("children_scroll_3", "children_scroll_content_3") + self.druid:new_scroll("scroll_smaller_view", "scroll_smaller_content") + init_grid(self) end From baf731958f4787d0accfe3d1ac6b80660ccb7717 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 3 May 2020 17:16:58 +0300 Subject: [PATCH 04/11] Renamed example page files --- example/gui/main/main.gui_script | 14 +++--- example/page/button_page.lua | 53 ++++++++++++++++++++ example/page/{input.lua => input_page.lua} | 0 example/page/{main.lua => main_page.lua} | 0 example/page/{scroll.lua => scroll_page.lua} | 8 +++ example/page/{slider.lua => slider_page.lua} | 0 example/page/{texts.lua => texts_page.lua} | 0 7 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 example/page/button_page.lua rename example/page/{input.lua => input_page.lua} (100%) rename example/page/{main.lua => main_page.lua} (100%) rename example/page/{scroll.lua => scroll_page.lua} (88%) rename example/page/{slider.lua => slider_page.lua} (100%) rename example/page/{texts.lua => texts_page.lua} (100%) diff --git a/example/gui/main/main.gui_script b/example/gui/main/main.gui_script index ba4ef8d..7c39141 100644 --- a/example/gui/main/main.gui_script +++ b/example/gui/main/main.gui_script @@ -3,12 +3,12 @@ local druid = require("druid.druid") local empty_style = require("druid.styles.empty.style") local default_style = require("druid.styles.default.style") -local main_page = require("example.page.main") -local text_page = require("example.page.texts") -local button_page = require("example.page.button") -local scroll_page = require("example.page.scroll") -local slider_page = require("example.page.slider") -local input_page = require("example.page.input") +local main_page = require("example.page.main_page") +local text_page = require("example.page.texts_page") +local button_page = require("example.page.button_page") +local scroll_page = require("example.page.scroll_page") +local slider_page = require("example.page.slider_page") +local input_page = require("example.page.input_page") local pages = { "main_page", @@ -62,7 +62,7 @@ function init(self) init_top_panel(self) init_swipe_control(self) - self.page = 1 + self.page = 4 main_page.setup_page(self) text_page.setup_page(self) button_page.setup_page(self) diff --git a/example/page/button_page.lua b/example/page/button_page.lua new file mode 100644 index 0000000..e736935 --- /dev/null +++ b/example/page/button_page.lua @@ -0,0 +1,53 @@ +local sprite_style = require("druid.styles.sprites.style") + +local M = {} + + +local function usual_callback() + print("Usual callback") +end + +local function long_tap_callback(self, params, button, hold_time) + print("Long tap callback", hold_time) +end + +local function hold_callback(self, params, button, hold_time) + print("On hold callback", hold_time) +end + +local function repeated_callback(self, params, button, click_in_row) + print("Repeated callback", click_in_row) +end + +local function double_tap_callback(self, params, button, click_in_row) + print("Double tap callback", click_in_row) +end + + +local function setup_buttons(self) + self.druid:new_button("button_usual/button", usual_callback) + + local custom_style = self.druid:new_button("button_custom_style/button", usual_callback) + custom_style:set_style(sprite_style) + + local long_button = self.druid:new_button("button_long_tap/button", usual_callback) + long_button.on_hold_callback:subscribe(hold_callback) + long_button.on_long_click:subscribe(long_tap_callback) + self.druid:new_button("button_repeated_tap/button", usual_callback) + .on_repeated_click:subscribe(repeated_callback) + self.druid:new_button("button_double_tap/button", usual_callback) + .on_double_click:subscribe(double_tap_callback) + + local button_space = self.druid:new_button("button_key_trigger/button", usual_callback) + button_space:set_key_trigger("key_space") + button_space.on_long_click:subscribe(long_tap_callback) + button_space.on_double_click:subscribe(double_tap_callback) +end + + +function M.setup_page(self) + setup_buttons(self) +end + + +return M diff --git a/example/page/input.lua b/example/page/input_page.lua similarity index 100% rename from example/page/input.lua rename to example/page/input_page.lua diff --git a/example/page/main.lua b/example/page/main_page.lua similarity index 100% rename from example/page/main.lua rename to example/page/main_page.lua diff --git a/example/page/scroll.lua b/example/page/scroll_page.lua similarity index 88% rename from example/page/scroll.lua rename to example/page/scroll_page.lua index 205b4e8..c24f944 100644 --- a/example/page/scroll.lua +++ b/example/page/scroll_page.lua @@ -49,6 +49,14 @@ function M.setup_page(self) self.druid:new_scroll("scroll_smaller_view", "scroll_smaller_content") + self.druid:new_scroll("scroll_with_points", "scroll_with_points_content") + :set_points({ + vmath.vector3(-300, 0, 0), + vmath.vector3(-900, 0, 0), + vmath.vector3(-1500, 0, 0), + vmath.vector3(-2100, 0, 0), + }) + init_grid(self) end diff --git a/example/page/slider.lua b/example/page/slider_page.lua similarity index 100% rename from example/page/slider.lua rename to example/page/slider_page.lua diff --git a/example/page/texts.lua b/example/page/texts_page.lua similarity index 100% rename from example/page/texts.lua rename to example/page/texts_page.lua From 99781f333d3d30004be2dbc6039e2b47013d5ba6 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 3 May 2020 19:36:28 +0300 Subject: [PATCH 05/11] Scroll progress. Previous API returing in process --- druid/base/drag.lua | 7 + druid/base/scroll.lua | 310 ++++++++++++++++++++++++------ druid/helper.lua | 11 +- druid/styles/default/style.lua | 3 +- example/gui/main/main.gui | 334 ++++++++++++++++++++++++++++++++- example/page/scroll_page.lua | 8 +- 6 files changed, 600 insertions(+), 73 deletions(-) diff --git a/druid/base/drag.lua b/druid/base/drag.lua index 8eed307..e8205c3 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -136,6 +136,13 @@ function M.init(self, node, on_drag_callback) end +function M.on_input_interrupt(self) + if self.is_drag or self.is_touch then + end_touch(self) + end +end + + function M.on_input(self, action_id, action) if action_id ~= const.ACTION_TOUCH and action_id ~= const.ACTION_MULTITOUCH then return diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index d1537ae..1632bc5 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -18,10 +18,15 @@ local component = require("druid.component") local M = component.create("scroll", { const.ON_UPDATE }) +local function inverse_lerp(min, max, current) + return helper.clamp((current - min) / (max - min), 0, 1) +end + + local function on_scroll_drag(self, dx, dy) - dy = -dy local t = self.target_pos - local b = self.available_soft_pos + local b = self.available_pos + local eb = self.available_pos_extra local extra_size = self.style.EXTRA_STRECH_SIZE -- Handle soft zones @@ -29,34 +34,40 @@ local function on_scroll_drag(self, dx, dy) local x_perc = 1 local y_perc = 1 + -- Right border (minimum x) if t.x < b.x and dx < 0 then - x_perc = (-extra_size.x - (b.x - t.x)) / -extra_size.x + x_perc = inverse_lerp(eb.x, b.x, t.x) end + -- Left border (maximum x) if t.x > b.z and dx > 0 then - x_perc = (extra_size.z - (t.x - b.z)) / extra_size.z + x_perc = inverse_lerp(eb.z, b.z, t.x) end - -- If disabled scroll by x + -- Disable x scroll if not self.can_x then x_perc = 0 end - if t.y > b.y and dy < 0 then - y_perc = (extra_size.y - (t.y - b.y)) / extra_size.y + -- Top border (minimum y) + if t.y < b.y and dy < 0 then + y_perc = inverse_lerp(eb.y, b.y, t.y) end - if t.y < b.w and dy > 0 then - y_perc = (-extra_size.w - (b.w - t.y)) / -extra_size.w + -- Bot border (maximum y) + if t.y > b.w and dy > 0 and extra_size > 0 then + y_perc = inverse_lerp(eb.w, b.w, t.y) end - -- If disabled scroll by y if not self.can_y then y_perc = 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) + position.x = helper.clamp(position.x, self.available_pos_extra.x, self.available_pos_extra.z) + position.y = helper.clamp(position.y, self.available_pos_extra.w, self.available_pos_extra.y) + 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 @@ -80,44 +91,117 @@ end local function check_soft_zone(self) local t = self.target_pos - local b = self.available_soft_pos + local b = self.available_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 + -- Right border (minimum x) 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 + -- Left border (maximum x) 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 + -- Top border (maximum y) + 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 + -- Bot border (minimum y) + 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 +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.inertion + 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 = self.current_pos + 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) - if math.abs(self.inertion.x) < self.style.INERT_THRESHOLD then + local is_stopped = false + + if self.inertion.x ~= 0 and math.abs(self.inertion.x) < self.style.INERT_THRESHOLD then + is_stopped = true self.inertion.x = 0 end - if math.abs(self.inertion.y) < self.style.INERT_THRESHOLD then + if self.inertion.y ~= 0 and math.abs(self.inertion.y) < self.style.INERT_THRESHOLD then + is_stopped = true self.inertion.y = 0 end + + if is_stopped or not self.inert then + if self.points then + print("check points free inert?") + end + check_points(self) + 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 + if self.is_inert and (self.inertion.x ~= 0 or self.inertion.y ~= 0) then + -- 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 + + check_threshold(self) + end -- Inertion friction self.inertion = self.inertion * self.style.FRICT - check_threshold(self) check_soft_zone(self) set_pos(self, target) end @@ -131,48 +215,92 @@ local function on_touch_start(self) 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) +local function on_touch_end(self) + check_threshold(self) +end - 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 + +local function update_size(self) + self.view_border = helper.get_border(self.view_node) + self.view_size = vmath.mul_per_elem(gui.get_size(self.view_node), + gui.get_scale(self.view_node)) + + self.content_border = helper.get_border(self.content_node) + self.content_size = vmath.mul_per_elem(gui.get_size(self.content_node), + gui.get_scale(self.content_node)) + + --== AVAILABLE POSITION + -- (min_x, min_y, max_x, max_y) + self.available_pos = vmath.vector4( + self.view_border.x - self.content_border.x, + self.view_border.y - self.content_border.y, + self.view_border.z - self.content_border.z, + self.view_border.w - self.content_border.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 + if self.available_pos.x > self.available_pos.z then + self.available_pos.x, self.available_pos.z = self.available_pos.z, self.available_pos.x + end + if self.available_pos.y > self.available_pos.w then + self.available_pos.y, self.available_pos.w = self.available_pos.w, self.available_pos.y + end + + self.available_size = vmath.vector3( + self.available_pos.z - self.available_pos.x, + self.available_pos.w - self.available_pos.y, + 0) + + self.can_x = math.abs(self.available_pos.x - self.available_pos.z) > 0 + self.can_y = math.abs(self.available_pos.y - self.available_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) + --== EXTRA CONTENT SIZE + self.content_size_extra = 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 + local sign = self.content_size.x > self.view_size.x and 1 or -1 + self.content_size_extra.x = self.content_size_extra.x - self.style.EXTRA_STRECH_SIZE * sign + self.content_size_extra.z = self.content_size_extra.z + self.style.EXTRA_STRECH_SIZE * sign 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 + local sign = self.content_size.y > self.view_size.y and 1 or -1 + self.content_size_extra.y = self.content_size_extra.y + self.style.EXTRA_STRECH_SIZE * sign + self.content_size_extra.w = self.content_size_extra.w - self.style.EXTRA_STRECH_SIZE * sign 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 + self.available_pos_extra = vmath.vector4( + self.view_border.x - self.content_size_extra.x, + self.view_border.y - self.content_size_extra.y, + self.view_border.z - self.content_size_extra.z, + self.view_border.w - self.content_size_extra.w ) + if self.available_pos_extra.x > self.available_pos_extra.z then + self.available_pos_extra.x, self.available_pos_extra.z = self.available_pos_extra.z, self.available_pos_extra.x + end + if self.available_pos_extra.y > self.available_pos_extra.w then + self.available_pos_extra.y, self.available_pos_extra.w = self.available_pos_extra.w, self.available_pos_extra.y + end - 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) + self.available_size_extra = vmath.vector3( + self.available_pos_extra.z - self.available_pos_extra.x, + self.available_pos_extra.w - self.available_pos_extra.y, + 0) + --== END CONTENT EXTRA + + -- print("VIEW BORDER", self.view_border) + -- print("CONTENT BORDER", self.content_border) + -- print("AVAILABLE POS", self.available_pos) + -- print("CURRENT POS", self.current_pos) + -- print("VIEW_SIZE", self.view_size) + -- print("CONTENT_SIZE", self.content_size) + -- print("AVAILABLE_SIZE", self.available_size) + + -- print("CONTENT SIZE EXTRA", self.content_size_extra) + -- print("AVAILABLE POS EXTRA", self.available_pos_extra) + -- print("") end @@ -199,18 +327,20 @@ function M.init(self, view_zone, content_zone) self.view_node = self:get_node(view_zone) self.content_node = self:get_node(content_zone) - self.current_pos = gui.get_position(self.content_node) self.target_pos = vmath.vector3(self.current_pos) self.inertion = vmath.vector3(0) self.drag = self.druid:new_drag(view_zone, on_scroll_drag) self.drag.on_touch_start:subscribe(on_touch_start) + self.drag.on_touch_end:subscribe(on_touch_end) self.on_scroll = Event() self.on_scroll_to = Event() self.on_point_scroll = Event() + self.is_inert = true + update_size(self) end @@ -237,22 +367,22 @@ end -- @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 b = self.available_pos 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) + target.x = helper.clamp(point.x, b.x, b.z) + target.y = helper.clamp(point.y, b.y, b.w) cancel_animate(self) self.animate = not is_instant if is_instant then - self.target = target + self.target_pos = target set_pos(self, target) else - gui.animate(self.node, gui.PROP_POSITION, target, gui.EASING_OUTSINE, self.style.ANIM_SPEED, 0, function() + gui.animate(self.content_node, gui.PROP_POSITION, target, gui.EASING_OUTSINE, self.style.ANIM_SPEED, 0, function() self.animate = false - self.target = target + self.target_pos = target set_pos(self, target) end) end @@ -261,8 +391,28 @@ function M.scroll_to(self, point, is_instant) end +--- Scroll to item in scroll by point index +-- @function scroll:scroll_to_index +-- @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 + + + function M.scroll_to_percent(self, percent, is_instant) - local border = self.border + local border = self.available_pos local size_x = math.abs(border.z - border.x) if size_x == 0 then @@ -282,14 +432,50 @@ end 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 + local y_dist = self.available_size.y + local y_perc = y_dist ~= 0 and (self.current_pos.y - self.available_pos.w) / y_dist or 1 - 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 + local x_dist = self.available_size.x + local x_perc = x_dist ~= 0 and (self.current_pos.x - self.available_pos.z) / x_dist or 1 return vmath.vector3(x_perc, y_perc, 0) 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 + + return self +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].x = -self.points[i].x + 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) + + pprint(self.points) + + return self +end + + return M diff --git a/druid/helper.lua b/druid/helper.lua index 14d17ae..0243de8 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -168,15 +168,18 @@ function M.is_web() end +--- Distance from node to size border +-- @function helper.get_border +-- @return vector4 (left, top, right, down) 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) + -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 diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index 10d0953..7c4b63e 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -51,6 +51,7 @@ M["drag"] = { M["scroll"] = { ANIM_SPEED = 0.3, -- gui.animation speed to point SCROLL_WHEEL_SPEED = 10, + DEADZONE = 20, FRICT = 0.94, -- mult for free inert FRICT_HOLD = 0.75, -- mult. for inert, while touching @@ -59,7 +60,7 @@ M["scroll"] = { BACK_SPEED = 0.35, -- Lerp speed of return to soft position - EXTRA_STRECH_SIZE = vmath.vector4(-100, 100, 100, -100), -- size of outside zone (back move) + EXTRA_STRECH_SIZE = 100, -- size of outside zone (back move) } diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index 3675838..9cf5062 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -5362,7 +5362,7 @@ nodes { } size { x: 600.0 - y: 1900.0 + y: 2100.0 z: 0.0 w: 1.0 } @@ -6792,7 +6792,337 @@ nodes { nodes { position { x: 0.0 - y: -1400.0 + y: -1300.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 600.0 + y: 300.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "kenney/empty" + id: "scroll_with_points" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "scroll_page_content" + layer: "image" + inherit_alpha: true + slice9 { + x: 0.0 + y: 0.0 + z: 0.0 + w: 0.0 + } + clipping_mode: CLIPPING_MODE_STENCIL + clipping_visible: true + clipping_inverted: false + alpha: 1.0 + template_node_child: false + size_mode: SIZE_MODE_MANUAL +} +nodes { + position { + x: -300.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 2400.0 + y: 300.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.9019608 + y: 0.5019608 + z: 0.3019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "scroll_with_points_content" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_W + adjust_mode: ADJUST_MODE_FIT + parent: "scroll_with_points" + layer: "image" + 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: 300.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 500.0 + y: 250.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.9019608 + y: 0.7019608 + z: 0.9019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "intereset_point_1" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "scroll_with_points_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: 900.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 500.0 + y: 250.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 0.7019608 + z: 0.7019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "intereset_point_2" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "scroll_with_points_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: 1500.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 500.0 + y: 250.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 0.9019608 + z: 0.7019608 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "intereset_point_3" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "scroll_with_points_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: 2100.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + rotation { + x: 0.0 + y: 0.0 + z: 0.0 + w: 1.0 + } + scale { + x: 1.0 + y: 1.0 + z: 1.0 + w: 1.0 + } + size { + x: 500.0 + y: 250.0 + z: 0.0 + w: 1.0 + } + color { + x: 1.0 + y: 1.0 + z: 0.6 + w: 1.0 + } + type: TYPE_BOX + blend_mode: BLEND_MODE_ALPHA + texture: "" + id: "intereset_point_4" + xanchor: XANCHOR_NONE + yanchor: YANCHOR_NONE + pivot: PIVOT_CENTER + adjust_mode: ADJUST_MODE_FIT + parent: "scroll_with_points_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: -1750.0 z: 0.0 w: 1.0 } diff --git a/example/page/scroll_page.lua b/example/page/scroll_page.lua index c24f944..4d9e036 100644 --- a/example/page/scroll_page.lua +++ b/example/page/scroll_page.lua @@ -51,10 +51,10 @@ function M.setup_page(self) self.druid:new_scroll("scroll_with_points", "scroll_with_points_content") :set_points({ - vmath.vector3(-300, 0, 0), - vmath.vector3(-900, 0, 0), - vmath.vector3(-1500, 0, 0), - vmath.vector3(-2100, 0, 0), + vmath.vector3(300, 0, 0), + vmath.vector3(900, 0, 0), + vmath.vector3(1500, 0, 0), + vmath.vector3(2100, 0, 0), }) init_grid(self) From facfe39269c8a22c54691ae1d570c29db95cc1b0 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 3 May 2020 20:46:01 +0300 Subject: [PATCH 06/11] Scroll polishing --- druid/base/scroll.lua | 90 ++++++++++++---------------------- druid/helper.lua | 5 ++ druid/styles/default/style.lua | 4 +- example/page/scroll_page.lua | 22 ++++++--- 4 files changed, 51 insertions(+), 70 deletions(-) diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 1632bc5..3c65a40 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -27,7 +27,6 @@ local function on_scroll_drag(self, dx, dy) local t = self.target_pos local b = self.available_pos local eb = self.available_pos_extra - local extra_size = self.style.EXTRA_STRECH_SIZE -- Handle soft zones -- Percent - multiplier for delta. Less if outside of scroll zone @@ -52,7 +51,7 @@ local function on_scroll_drag(self, dx, dy) y_perc = inverse_lerp(eb.y, b.y, t.y) end -- Bot border (maximum y) - if t.y > b.w and dy > 0 and extra_size > 0 then + if t.y > b.w and dy > 0 then y_perc = inverse_lerp(eb.w, b.w, t.y) end if not self.can_y then @@ -141,15 +140,16 @@ local function check_points(self) local index = false local index_on_inert = false local pos = self.current_pos + for i = 1, #self.points do local p = self.points[i] - local dist = helper.distance(pos.x, pos.y, p.x, p.y) + 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 + 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 + if inert.y ~= 0 and helper.sign(inert.y) ~= helper.sign(-p.y - pos.y) then on_inert = false end @@ -179,10 +179,7 @@ local function check_threshold(self) self.inertion.y = 0 end - if is_stopped or not self.inert then - if self.points then - print("check points free inert?") - end + if is_stopped or not self.is_inert then check_points(self) end end @@ -231,12 +228,7 @@ local function update_size(self) --== AVAILABLE POSITION -- (min_x, min_y, max_x, max_y) - self.available_pos = vmath.vector4( - self.view_border.x - self.content_border.x, - self.view_border.y - self.content_border.y, - self.view_border.z - self.content_border.z, - self.view_border.w - self.content_border.w - ) + self.available_pos = self.view_border - self.content_border if self.available_pos.x > self.available_pos.z then self.available_pos.x, self.available_pos.z = self.available_pos.z, self.available_pos.x @@ -261,14 +253,14 @@ local function update_size(self) self.content_size_extra = helper.get_border(self.content_node) if self.can_x then local sign = self.content_size.x > self.view_size.x and 1 or -1 - self.content_size_extra.x = self.content_size_extra.x - self.style.EXTRA_STRECH_SIZE * sign - self.content_size_extra.z = self.content_size_extra.z + self.style.EXTRA_STRECH_SIZE * sign + self.content_size_extra.x = self.content_size_extra.x - self.extra_stretch_size * sign + self.content_size_extra.z = self.content_size_extra.z + self.extra_stretch_size * sign end if self.can_y then local sign = self.content_size.y > self.view_size.y and 1 or -1 - self.content_size_extra.y = self.content_size_extra.y + self.style.EXTRA_STRECH_SIZE * sign - self.content_size_extra.w = self.content_size_extra.w - self.style.EXTRA_STRECH_SIZE * sign + self.content_size_extra.y = self.content_size_extra.y + self.extra_stretch_size * sign + self.content_size_extra.w = self.content_size_extra.w - self.extra_stretch_size * sign end self.available_pos_extra = vmath.vector4( @@ -288,19 +280,6 @@ local function update_size(self) self.available_pos_extra.z - self.available_pos_extra.x, self.available_pos_extra.w - self.available_pos_extra.y, 0) - --== END CONTENT EXTRA - - -- print("VIEW BORDER", self.view_border) - -- print("CONTENT BORDER", self.content_border) - -- print("AVAILABLE POS", self.available_pos) - -- print("CURRENT POS", self.current_pos) - -- print("VIEW_SIZE", self.view_size) - -- print("CONTENT_SIZE", self.content_size) - -- print("AVAILABLE_SIZE", self.available_size) - - -- print("CONTENT SIZE EXTRA", self.content_size_extra) - -- print("AVAILABLE POS EXTRA", self.available_pos_extra) - -- print("") end @@ -330,6 +309,7 @@ function M.init(self, view_zone, content_zone) self.current_pos = gui.get_position(self.content_node) self.target_pos = vmath.vector3(self.current_pos) self.inertion = vmath.vector3(0) + self.extra_stretch_size = self.style.EXTRA_STRECH_SIZE self.drag = self.druid:new_drag(view_zone, on_scroll_drag) self.drag.on_touch_start:subscribe(on_touch_start) @@ -368,9 +348,9 @@ end -- @usage scroll:scroll_to(vmath.vector3(0), true) function M.scroll_to(self, point, is_instant) local b = self.available_pos - local target = vmath.vector3(point) - target.x = helper.clamp(point.x, b.x, b.z) - target.y = helper.clamp(point.y, b.y, b.w) + local target = vmath.vector3(-point.x, -point.y, 0) + target.x = helper.clamp(target.x, b.x, b.z) + target.y = helper.clamp(target.y, b.y, b.w) cancel_animate(self) @@ -414,30 +394,19 @@ end function M.scroll_to_percent(self, percent, is_instant) local border = self.available_pos - 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) + -helper.lerp(border.x, border.z, 1 - percent.x), + -helper.lerp(border.w, border.y, 1 - percent.y), + 0 + ) + M.scroll_to(self, pos, is_instant) end function M.get_percent(self) - local y_dist = self.available_size.y - local y_perc = y_dist ~= 0 and (self.current_pos.y - self.available_pos.w) / y_dist or 1 - - local x_dist = self.available_size.x - local x_perc = x_dist ~= 0 and (self.current_pos.x - self.available_pos.z) / x_dist or 1 - + local x_perc = 1 - inverse_lerp(self.available_pos.x, self.available_pos.z, self.current_pos.x) + local y_perc = inverse_lerp(self.available_pos.w, self.available_pos.y, self.current_pos.y) return vmath.vector3(x_perc, y_perc, 0) end @@ -454,17 +423,20 @@ function M.set_inert(self, state) end +function M.set_extra_strech_size(self, stretch_size) + self.extra_stretch_size = stretch_size or self.style.EXTRA_STRECH_SIZE + update_size(self) + + return self +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].x = -self.points[i].x - 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 @@ -472,8 +444,6 @@ function M.set_points(self, points) check_threshold(self) - pprint(self.points) - return self end diff --git a/druid/helper.lua b/druid/helper.lua index 0243de8..1e1076f 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -126,6 +126,11 @@ function M.round(num, numDecimalPlaces) end +function M.lerp(a, b, t) + return a + (b - a) * t +end + + --- Check if node is enabled in gui hierarchy. -- Return false, if node or any his parent is disabled -- @function helper.is_enabled diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index 7c4b63e..8c5b049 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -49,13 +49,13 @@ M["drag"] = { M["scroll"] = { - ANIM_SPEED = 0.3, -- gui.animation speed to point + ANIM_SPEED = 0.2, -- gui.animation speed to point SCROLL_WHEEL_SPEED = 10, DEADZONE = 20, FRICT = 0.94, -- mult for free inert FRICT_HOLD = 0.75, -- mult. for inert, while touching - INERT_THRESHOLD = 2, -- speed to stop inertion + INERT_THRESHOLD = 2.5, -- speed to stop inertion INERT_SPEED = 27, -- koef. of inert speed BACK_SPEED = 0.35, -- Lerp speed of return to soft position diff --git a/example/page/scroll_page.lua b/example/page/scroll_page.lua index 4d9e036..e49d018 100644 --- a/example/page/scroll_page.lua +++ b/example/page/scroll_page.lua @@ -1,7 +1,7 @@ local M = {} -local function init_grid(self) +local function init_scroll_with_grid(self) local prefab = gui.get_node("grid_prefab") local grid_scroll = self.druid:new_scroll("scroll_with_grid_size", "grid_content") @@ -15,7 +15,6 @@ local function init_grid(self) local button = self.druid:new_button(clone_prefab["grid_button"], function() local position = gui.get_position(clone_prefab["grid_prefab"]) - position.x = -position.x grid_scroll:scroll_to(position) end) button:set_click_zone(gui.get_node("scroll_with_grid_size")) @@ -26,7 +25,7 @@ local function init_grid(self) 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) @@ -36,19 +35,28 @@ end function M.setup_page(self) + -- Usual scroll for whole page self.druid:new_scroll("scroll_page", "scroll_page_content") + + -- Simple scroll with no adjust self.druid:new_scroll("simple_scroll_input", "simple_scroll_content") - -- scroll contain scrolls: - -- parent first + -- Scroll with grid example + init_scroll_with_grid(self) + + -- Scroll contain children scrolls: + -- Parent scroll self.druid:new_scroll("children_scroll", "children_scroll_content") - -- chilren next + -- Childre scrolls 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") + -- Content with less size than view self.druid:new_scroll("scroll_smaller_view", "scroll_smaller_content") + :set_extra_strech_size(0) + -- Scroll with points of interests self.druid:new_scroll("scroll_with_points", "scroll_with_points_content") :set_points({ vmath.vector3(300, 0, 0), @@ -56,8 +64,6 @@ function M.setup_page(self) vmath.vector3(1500, 0, 0), vmath.vector3(2100, 0, 0), }) - - init_grid(self) end From 0c1bf63e139262d163a4dc2c0b6944082a992406 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 3 May 2020 20:56:37 +0300 Subject: [PATCH 07/11] Scroll module refactoring --- druid/base/scroll.lua | 103 +++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 57 deletions(-) diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 3c65a40..f48a009 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -42,7 +42,7 @@ local function on_scroll_drag(self, dx, dy) x_perc = inverse_lerp(eb.z, b.z, t.x) end -- Disable x scroll - if not self.can_x then + if not self.drag.can_x then x_perc = 0 end @@ -54,7 +54,8 @@ local function on_scroll_drag(self, dx, dy) if t.y > b.w and dy > 0 then y_perc = inverse_lerp(eb.w, b.w, t.y) end - if not self.can_y then + -- Disable y scroll + if not self.drag.can_y then y_perc = 0 end @@ -212,74 +213,61 @@ local function on_touch_start(self) end +--- Verify vector +-- Field x have to <= field z +-- Field y have to <= field w +local function verify_scroll_vector4(vector) + if vector.x > vector.z then + vector.x, vector.z = vector.z, vector.x + end + if vector.y > vector.w then + vector.y, vector.w = vector.w, vector.y + end + + return vector +end + + +--- Return size from scroll border vector4 +local function get_size_vector(vector) + return vmath.vector3(vector.z - vector.x, vector.w - vector.y, 0) +end + + local function on_touch_end(self) check_threshold(self) end local function update_size(self) - self.view_border = helper.get_border(self.view_node) - self.view_size = vmath.mul_per_elem(gui.get_size(self.view_node), - gui.get_scale(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)) - self.content_border = helper.get_border(self.content_node) - self.content_size = vmath.mul_per_elem(gui.get_size(self.content_node), - gui.get_scale(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)) - --== AVAILABLE POSITION - -- (min_x, min_y, max_x, max_y) - self.available_pos = self.view_border - self.content_border + self.available_pos = verify_scroll_vector4(view_border - content_border) + self.available_size = get_size_vector(self.available_pos) - if self.available_pos.x > self.available_pos.z then - self.available_pos.x, self.available_pos.z = self.available_pos.z, self.available_pos.x - end - if self.available_pos.y > self.available_pos.w then - self.available_pos.y, self.available_pos.w = self.available_pos.w, self.available_pos.y + self.drag.can_x = self.available_size.x > 0 + self.drag.can_y = self.available_size.y > 0 + + --== Extra content size calculation + local content_border_extra = helper.get_border(self.content_node) + if self.drag.can_x then + local sign = content_size.x > view_size.x and 1 or -1 + content_border_extra.x = content_border_extra.x - self.extra_stretch_size * sign + content_border_extra.z = content_border_extra.z + self.extra_stretch_size * sign end - self.available_size = vmath.vector3( - self.available_pos.z - self.available_pos.x, - self.available_pos.w - self.available_pos.y, - 0) - - self.can_x = math.abs(self.available_pos.x - self.available_pos.z) > 0 - self.can_y = math.abs(self.available_pos.y - self.available_pos.w) > 0 - - self.drag.can_x = self.can_x - self.drag.can_y = self.can_y - - - --== EXTRA CONTENT SIZE - self.content_size_extra = helper.get_border(self.content_node) - if self.can_x then - local sign = self.content_size.x > self.view_size.x and 1 or -1 - self.content_size_extra.x = self.content_size_extra.x - self.extra_stretch_size * sign - self.content_size_extra.z = self.content_size_extra.z + self.extra_stretch_size * sign + if self.drag.can_y then + local sign = content_size.y > view_size.y and 1 or -1 + content_border_extra.y = content_border_extra.y + self.extra_stretch_size * sign + content_border_extra.w = content_border_extra.w - self.extra_stretch_size * sign end - if self.can_y then - local sign = self.content_size.y > self.view_size.y and 1 or -1 - self.content_size_extra.y = self.content_size_extra.y + self.extra_stretch_size * sign - self.content_size_extra.w = self.content_size_extra.w - self.extra_stretch_size * sign - end - - self.available_pos_extra = vmath.vector4( - self.view_border.x - self.content_size_extra.x, - self.view_border.y - self.content_size_extra.y, - self.view_border.z - self.content_size_extra.z, - self.view_border.w - self.content_size_extra.w - ) - if self.available_pos_extra.x > self.available_pos_extra.z then - self.available_pos_extra.x, self.available_pos_extra.z = self.available_pos_extra.z, self.available_pos_extra.x - end - if self.available_pos_extra.y > self.available_pos_extra.w then - self.available_pos_extra.y, self.available_pos_extra.w = self.available_pos_extra.w, self.available_pos_extra.y - end - - self.available_size_extra = vmath.vector3( - self.available_pos_extra.z - self.available_pos_extra.x, - self.available_pos_extra.w - self.available_pos_extra.y, - 0) + self.available_pos_extra = verify_scroll_vector4(view_border - content_border_extra) + self.available_size_extra = get_size_vector(self.available_pos_extra) end @@ -407,6 +395,7 @@ end function M.get_percent(self) local x_perc = 1 - inverse_lerp(self.available_pos.x, self.available_pos.z, self.current_pos.x) local y_perc = inverse_lerp(self.available_pos.w, self.available_pos.y, self.current_pos.y) + return vmath.vector3(x_perc, y_perc, 0) end From 1e568c2fa6707945e91eb5668a61221bd5617de8 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 4 May 2020 00:16:08 +0300 Subject: [PATCH 08/11] Update documentation, refactoring --- docs/modules/druid.drag.html | 286 ++++++++++++++++ docs_md/changelog.md | 35 +- druid/base/blocker.lua | 4 +- druid/base/drag.lua | 42 ++- druid/base/scroll.lua | 314 +++++++++++------- druid/base/scroll_legacy.lua | 538 ------------------------------- druid/base/text.lua | 2 +- druid/druid.lua | 4 +- druid/styles/default/style.lua | 7 +- example/gui/main/main.gui | 67 +++- example/gui/main/main.gui_script | 7 +- example/page/scroll_page.lua | 3 +- 12 files changed, 631 insertions(+), 678 deletions(-) create mode 100644 docs/modules/druid.drag.html delete mode 100644 druid/base/scroll_legacy.lua diff --git a/docs/modules/druid.drag.html b/docs/modules/druid.drag.html new file mode 100644 index 0000000..ae4e709 --- /dev/null +++ b/docs/modules/druid.drag.html @@ -0,0 +1,286 @@ + + + + + Defold Druid UI Library + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module druid.drag

+

Component to handle drag action on node.

+

Drag have correct handling for multitouch and swap + touched while dragging. Drag will be processed even + the cursor is outside of node, if drag is already started

+ + +

Functions

+ + + + + + + + + +
init(node, on_drag_callback)Drag component constructor
set_click_zone(zone)Strict drag click area.
+

Tables

+ + + + + + + + + + + + + +
EventsComponent events
FieldsComponents fields
StyleComponent style params
+ +
+
+ + +

Functions

+ +
+
+ + init(node, on_drag_callback) +
+
+ Drag component constructor + + +

Parameters:

+
    +
  • node + node + GUI node to detect dragging +
  • +
  • on_drag_callback + function + Callback for ondragevent(self, dx, dy) +
  • +
+ + + + + +
+
+ + set_click_zone(zone) +
+
+ Strict drag click area. Useful for + restrict events outside stencil node + + +

Parameters:

+
    +
  • zone + node + Gui node +
  • +
+ + + + + +
+
+

Tables

+ +
+
+ + Events +
+
+ Component events + + +

Fields:

+
    +
  • on_touch_start + druid_event + (self) Event on touch start +
  • +
  • on_touch_end + druid_event + (self) Event on touch end +
  • +
  • on_drag_start + druid_event + (self) Event on drag start +
  • +
  • on_drag + druid_event + (self, dx, dy) Event on drag progress +
  • +
  • on_drag_end + druid_event + (self) Event on drag end +
  • +
+ + + + + +
+
+ + Fields +
+
+ Components fields + + +

Fields:

+
    +
  • is_touch + bool + Is component now touching +
  • +
  • is_drag + bool + Is component now dragging +
  • +
  • can_x + bool + Is drag component process vertical dragging. Default - true +
  • +
  • can_y + bool + Is drag component process horizontal. Default - true +
  • +
  • x + number + Current touch x position +
  • +
  • y + number + Current touch y position +
  • +
  • touch_start_pos + vector3 + Touch start position +
  • +
+ + + + + +
+
+ + Style +
+
+ Component style params + + +

Fields:

+
    +
  • DRAG_DEADZONE + number + Distance in pixels to start dragging +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.6 +Last updated 2020-05-04 00:06:50 +
+
+ + diff --git a/docs_md/changelog.md b/docs_md/changelog.md index 0959b59..bf0018e 100644 --- a/docs_md/changelog.md +++ b/docs_md/changelog.md @@ -39,4 +39,37 @@ Druid 0.3.0: - Known issues: - Adjusting text size by height works wrong. Adjusting single line texting works fine - Space is not working in HTML5 - \ No newline at end of file + + + +Druid 0.4.0: + +- Add _Drag_ basic component + - Drag component allow you detect dragging on GUI node + - Drag will be processed even the cursor is outside of node, if drag is already started + - Drag provides correct handle of several touches. Drag can switch between them (no more scroll gliches with position) + - Drag have next events: + - on_touch_start (self) + - on_touch_end (self) + - on_drag_start (self) + - on_drag (self, dx, dy) + - on_drag_end (self) + - You can restriction side of draggin by changing _drag.can_x_ and _drag.can_y_ fields + - You can setup drag deadzone to detect, when dragging is started (by default 10 pixels) + +- Druid _Scroll_ component fully reworked. Input logic moved to _Drag_ component + - Updated scroll documentation + - Changed constructor order params + - Scroll now contains from view and content node + - _View node_ - static node, which size determine the "camera" zone + - _Content node_ - dynamic node, moving by _Scroll_ component + - Scroll will be disabled only if content size equals to view size (by width or height separatly) + - You can adjust scroll size via _.gui_ scene. Just setup correct node size + - Different anchoring is supported (for easier layout) + - Function _scroll_to_ now accept position relative to _content node_. It's more easier for handling. _Example:_ if you have children node of _content_node_, you can pass this node position to scroll to this. + - **Resolve #52**: _Content node size_ now can be less than _view node size_. In this case, content will be scrolled only inside _view size_ + - **Fix #50**: If style:SOFT_ZONE_SIZE equals to [0..1], scroll can be disappeared + +- _Grid_ anchor by default equals to node pivot (so, more gui settings in _.gui_ settings) + +- **Fix:** Blocker component bug (blocker had very high priority, so it's block even button components, created after bloker) \ No newline at end of file diff --git a/druid/base/blocker.lua b/druid/base/blocker.lua index 0b336bd..e5c3931 100644 --- a/druid/base/blocker.lua +++ b/druid/base/blocker.lua @@ -14,7 +14,7 @@ local Event = require("druid.event") local const = require("druid.const") local component = require("druid.component") -local M = component.create("blocker", { const.ON_INPUT_HIGH }) +local M = component.create("blocker", { const.ON_INPUT }) --- Component init function @@ -29,7 +29,7 @@ end function M.on_input(self, action_id, action) - if action_id ~= const.ACTION_TOUCH then + if action_id ~= const.ACTION_TOUCH and action_id ~= const.ACTION_MULTITOUCH then return false end diff --git a/druid/base/drag.lua b/druid/base/drag.lua index e8205c3..8e1199a 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -1,14 +1,30 @@ ---- Component to handle drag action on node +--- Component to handle drag action on node. +-- Drag have correct handling for multitouch and swap +-- touched while dragging. Drag will be processed even +-- the cursor is outside of node, if drag is already started -- @module druid.drag ---- Components fields --- @table Fields - --- Component events -- @table Events +-- @tfield druid_event on_touch_start (self) Event on touch start +-- @tfield druid_event on_touch_end (self) Event on touch end +-- @tfield druid_event on_drag_start (self) Event on drag start +-- @tfield druid_event on_drag (self, dx, dy) Event on drag progress +-- @tfield druid_event on_drag_end (self) Event on drag end + +--- Components fields +-- @table Fields +-- @tfield bool is_touch Is component now touching +-- @tfield bool is_drag Is component now dragging +-- @tfield bool can_x Is drag component process vertical dragging. Default - true +-- @tfield bool can_y Is drag component process horizontal. Default - true +-- @tfield number x Current touch x position +-- @tfield number y Current touch y position +-- @tfield vector3 touch_start_pos Touch start position --- Component style params -- @table Style +-- @tfield number DRAG_DEADZONE Distance in pixels to start dragging local Event = require("druid.event") local const = require("druid.const") @@ -49,12 +65,13 @@ local function process_touch(self, touch) if not self.can_x then self.touch_start_pos.x = touch.x end + if not self.can_y then self.touch_start_pos.y = touch.y end local distance = helper.distance(touch.x, touch.y, self.touch_start_pos.x, self.touch_start_pos.y) - if not self.is_drag and distance >= self.drag_deadzone then + if not self.is_drag and distance >= self.style.DRAG_DEADZONE then self.is_drag = true self.on_drag_start:trigger(self:get_context()) self:increase_input_priority() @@ -62,6 +79,8 @@ local function process_touch(self, touch) end +--- Return current touch action from action input data +-- If touch_id stored - return exact this touch action local function find_touch(action_id, action, touch_id) local act = helper.is_mobile() and const.ACTION_MULTITOUCH or const.ACTION_TOUCH @@ -83,6 +102,8 @@ local function find_touch(action_id, action, touch_id) end +--- Process on touch release. We should to find, if any other +-- touches exists to switch to another touch. local function on_touch_release(self, action_id, action) if #action.touch >= 2 then -- Find next unpressed touch @@ -107,14 +128,14 @@ local function on_touch_release(self, action_id, action) end ---- Component init function +--- Drag component constructor +-- @tparam node node GUI node to detect dragging +-- @tparam function on_drag_callback Callback for on_drag_event(self, dx, dy) -- @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 @@ -162,8 +183,6 @@ function M.on_input(self, action_id, action) return false end - self.dx = 0 - self.dy = 0 local touch = find_touch(action_id, action, self.touch_id) if not touch then @@ -174,6 +193,9 @@ function M.on_input(self, action_id, action) self.touch_id = touch.id end + self.dx = 0 + self.dy = 0 + if touch.pressed and not self.is_touch then start_touch(self, touch) end diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index f48a009..dd2a534 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -1,14 +1,40 @@ ---- +--- 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 const = require("druid.const") @@ -23,8 +49,29 @@ local function inverse_lerp(min, max, current) end +--- Update vector with next conditions: +-- Field x have to <= field z +-- Field y have to <= field w +local function get_border_vector(vector) + if vector.x > vector.z then + vector.x, vector.z = vector.z, vector.x + end + if vector.y > vector.w then + vector.y, vector.w = vector.w, vector.y + end + + return vector +end + + +--- Return size from scroll border vector4 +local function get_size_vector(vector) + return vmath.vector3(vector.z - vector.x, vector.w - vector.y, 0) +end + + local function on_scroll_drag(self, dx, dy) - local t = self.target_pos + local t = self.target_position local b = self.available_pos local eb = self.available_pos_extra @@ -64,50 +111,54 @@ local function on_scroll_drag(self, dx, dy) end -local function set_pos(self, position) - position.x = helper.clamp(position.x, self.available_pos_extra.x, self.available_pos_extra.z) - position.y = helper.clamp(position.y, self.available_pos_extra.w, self.available_pos_extra.y) - - 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 - - self.inertion.x = (self.inertion.x + dx) * self.style.FRICT_HOLD - self.inertion.y = (self.inertion.y + dy) * 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_pos + local target = self.target_position + local border = self.available_pos + local speed = self.style.BACK_SPEED -- Right border (minimum x) - if t.x < b.x then - t.x = helper.step(t.x, b.x, math.abs(t.x - b.x) * self.style.BACK_SPEED) + if target.x < border.x then + target.x = helper.step(target.x, border.x, math.abs(target.x - border.x) * speed) end -- Left border (maximum x) - if t.x > b.z then - t.x = helper.step(t.x, b.z, math.abs(t.x - b.z) * self.style.BACK_SPEED) + if target.x > border.z then + target.x = helper.step(target.x, border.z, math.abs(target.x - border.z) * speed) end -- Top border (maximum y) - if t.y < b.y then - t.y = helper.step(t.y, b.y, math.abs(t.y - b.y) * self.style.BACK_SPEED) + if target.y < border.y then + target.y = helper.step(target.y, border.y, math.abs(target.y - border.y) * speed) end -- Bot border (minimum y) - if t.y > b.w then - t.y = helper.step(t.y, b.w, math.abs(t.y - b.w) * self.style.BACK_SPEED) + if target.y > border.w then + target.y = helper.step(target.y, border.w, math.abs(target.y - border.w) * speed) + end +end + + +--- Cancel animation on other animation or input touch +local function cancel_animate(self) + if self.is_animate then + self.target_position = gui.get_position(self.content_node) + self.position.x = self.target_position.x + self.position.y = self.target_position.y + gui.cancel_animation(self.content_node, gui.PROP_POSITION) + self.is_animate = false + end +end + + + +local function set_scroll_position(self, position) + local available_extra = self.available_pos_extra + position.x = helper.clamp(position.x, available_extra.x, available_extra.z) + position.y = helper.clamp(position.y, available_extra.w, available_extra.y) + + if self.position.x ~= position.x or self.position.y ~= position.y then + self.position.x = position.x + self.position.y = position.y + gui.set_position(self.content_node, position) + + self.on_scroll:trigger(self:get_context(), self.position) end end @@ -122,7 +173,7 @@ local function check_points(self) end local inert = self.inertion - if not self.is_inert then + 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 @@ -140,7 +191,7 @@ local function check_points(self) local temp_dist_on_inert = math.huge local index = false local index_on_inert = false - local pos = self.current_pos + local pos = self.position for i = 1, #self.points do local p = self.points[i] @@ -180,19 +231,19 @@ local function check_threshold(self) self.inertion.y = 0 end - if is_stopped or not self.is_inert then + if is_stopped or not self._is_inert then check_points(self) end end local function update_free_scroll(self, dt) - local target = self.target_pos + local target = self.target_position - if self.is_inert and (self.inertion.x ~= 0 or self.inertion.y ~= 0) then + if self._is_inert and (self.inertion.x ~= 0 or self.inertion.y ~= 0) then -- 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 + target.x = self.position.x + self.inertion.x * self.style.INERT_SPEED * dt + target.y = self.position.y + self.inertion.y * self.style.INERT_SPEED * dt check_threshold(self) end @@ -200,37 +251,29 @@ local function update_free_scroll(self, dt) -- Inertion friction self.inertion = self.inertion * self.style.FRICT - check_soft_zone(self) - set_pos(self, target) + if self.position.x ~= target.x or self.position.y ~= target.y then + check_soft_zone(self) + set_scroll_position(self, target) + end +end + + +local function update_hand_scroll(self, dt) + local dx = self.target_position.x - self.position.x + local dy = self.target_position.y - self.position.y + + self.inertion.x = (self.inertion.x + dx) * self.style.FRICT_HOLD + self.inertion.y = (self.inertion.y + dy) * self.style.FRICT_HOLD + + set_scroll_position(self, self.target_position) 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 - - ---- Verify vector --- Field x have to <= field z --- Field y have to <= field w -local function verify_scroll_vector4(vector) - if vector.x > vector.z then - vector.x, vector.z = vector.z, vector.x - end - if vector.y > vector.w then - vector.y, vector.w = vector.w, vector.y - end - - return vector -end - - ---- Return size from scroll border vector4 -local function get_size_vector(vector) - return vmath.vector3(vector.z - vector.x, vector.w - vector.y, 0) + self.target_position.x = self.position.x + self.target_position.y = self.position.y end @@ -246,14 +289,17 @@ local function update_size(self) 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)) - self.available_pos = verify_scroll_vector4(view_border - content_border) + self.available_pos = get_border_vector(view_border - content_border) self.available_size = get_size_vector(self.available_pos) self.drag.can_x = self.available_size.x > 0 self.drag.can_y = self.available_size.y > 0 - --== Extra content size calculation + -- Extra content size calculation + -- We add extra size only if scroll is available + -- Even the content zone size less than view zone size local content_border_extra = helper.get_border(self.content_node) + if self.drag.can_x then local sign = content_size.x > view_size.x and 1 or -1 content_border_extra.x = content_border_extra.x - self.extra_stretch_size * sign @@ -266,27 +312,20 @@ local function update_size(self) content_border_extra.w = content_border_extra.w - self.extra_stretch_size * sign end - self.available_pos_extra = verify_scroll_vector4(view_border - content_border_extra) + if not self.style.SMALL_CONTENT_SCROLL then + self.drag.can_x = content_size.x > view_size.x + self.drag.can_y = content_size.y > view_size.y + end + + self.available_pos_extra = get_border_vector(view_border - content_border_extra) self.available_size_extra = get_size_vector(self.available_pos_extra) 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 swipe:init --- @tparam node node Gui node --- @tparam function on_swipe_callback Swipe callback for on_swipe_end event +--- Scroll constructor. +-- @function scroll:init +-- @tparam node view_node GUI view scroll node +-- @tparam node content_node GUI content scroll node function M.init(self, view_zone, content_zone) self.druid = self:get_druid() self.style = self:get_style() @@ -294,10 +333,9 @@ function M.init(self, view_zone, content_zone) self.view_node = self:get_node(view_zone) self.content_node = self:get_node(content_zone) - self.current_pos = gui.get_position(self.content_node) - self.target_pos = vmath.vector3(self.current_pos) + self.position = gui.get_position(self.content_node) + self.target_position = vmath.vector3(self.position) self.inertion = vmath.vector3(0) - self.extra_stretch_size = self.style.EXTRA_STRECH_SIZE self.drag = self.druid:new_drag(view_zone, on_scroll_drag) self.drag.on_touch_start:subscribe(on_touch_start) @@ -307,18 +345,15 @@ function M.init(self, view_zone, content_zone) self.on_scroll_to = Event() self.on_point_scroll = Event() - self.is_inert = true + self.selected = nil + self._is_inert = true + self.is_animate = false + self.extra_stretch_size = self.style.EXTRA_STRECH_SIZE update_size(self) end -function M.set_size(self, size) - gui.set_size(self.content_node, size) - update_size(self) -end - - function M.update(self, dt) if self.drag.is_drag then update_hand_scroll(self, dt) @@ -328,10 +363,10 @@ function M.update(self, dt) end ---- Start scroll to target point +--- Start scroll to target point. -- @function scroll:scroll_to --- @tparam point vector3 target point --- @tparam[opt] bool is_instant instant scroll flag +-- @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) @@ -342,16 +377,16 @@ function M.scroll_to(self, point, is_instant) cancel_animate(self) - self.animate = not is_instant + self.is_animate = not is_instant if is_instant then - self.target_pos = target - set_pos(self, target) + self.target_position = target + set_scroll_position(self, target) else gui.animate(self.content_node, gui.PROP_POSITION, target, gui.EASING_OUTSINE, self.style.ANIM_SPEED, 0, function() - self.animate = false - self.target_pos = target - set_pos(self, target) + self.is_animate = false + self.target_position = target + set_scroll_position(self, target) end) end @@ -359,11 +394,15 @@ function M.scroll_to(self, point, is_instant) end ---- Scroll to item in scroll by point index +--- Scroll to item in scroll by point index. -- @function scroll:scroll_to_index -- @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) + if not self.points then + return + end + index = helper.clamp(index, 1, #self.points) if self.selected ~= index then @@ -378,7 +417,11 @@ function M.scroll_to_index(self, index, skip_cb) 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.available_pos @@ -392,26 +435,56 @@ function M.scroll_to_percent(self, percent, is_instant) end +--- Return current scroll progress status. +-- Values will be in [0..1] interval +-- @function scroll:get_percent +-- @treturn vector3 New vector with scroll progress values function M.get_percent(self) - local x_perc = 1 - inverse_lerp(self.available_pos.x, self.available_pos.z, self.current_pos.x) - local y_perc = inverse_lerp(self.available_pos.w, self.available_pos.y, self.current_pos.y) + local x_perc = 1 - inverse_lerp(self.available_pos.x, self.available_pos.z, self.position.x) + local y_perc = inverse_lerp(self.available_pos.w, self.available_pos.y, self.position.y) return vmath.vector3(x_perc, y_perc, 0) end +--- Set scroll content size. +-- It will change content gui node size +-- @function scroll:set_size +-- @tparam vector3 size The new size for content node +-- @treturn druid.scroll Self instance +function M.set_size(self, size) + gui.set_size(self.content_node, size) + update_size(self) + + return 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 +-- @treturn druid.scroll Self instance function M.set_inert(self, state) - self.is_inert = state - + self._is_inert = state return self end +--- Return if scroll have inertion. +-- @function scroll:is_inert +-- @treturn bool If scroll have inertion +function M.is_inert(self) + return self._is_inert +end + + +--- Set extra size for scroll stretching. +-- Set 0 to disable stretching effect +-- @function scroll:set_extra_strech_size +-- @tparam number stretch_size Size in pixels of additional scroll area +-- @treturn druid.scroll Self instance function M.set_extra_strech_size(self, stretch_size) self.extra_stretch_size = stretch_size or self.style.EXTRA_STRECH_SIZE update_size(self) @@ -420,10 +493,19 @@ function M.set_extra_strech_size(self, stretch_size) end +--- Return vector of scroll size with width and height. +-- @function scroll:get_scroll_size +-- @treturn vector3 Available scroll size +function M.get_scroll_size(self) + return self.available_size +end + + --- Set points of interest. -- Scroll will always centered on closer points -- @function scroll:set_points -- @tparam table points Array of vector3 points +-- @treturn druid.scroll Self instance function M.set_points(self, points) self.points = points diff --git a/druid/base/scroll_legacy.lua b/druid/base/scroll_legacy.lua deleted file mode 100644 index 56a50aa..0000000 --- a/druid/base/scroll_legacy.lua +++ /dev/null @@ -1,538 +0,0 @@ ---- 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/base/text.lua b/druid/base/text.lua index 5a668ee..a6c7f2e 100644 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -196,7 +196,7 @@ end --- Return true, if text with line break -- @function text:is_multiline --- @treturn boolean Is text node with line break +-- @treturn bool Is text node with line break function M.is_multiline(self) return gui.get_line_break(self.node) end diff --git a/druid/druid.lua b/druid/druid.lua index eb10f44..c3b4533 100644 --- a/druid/druid.lua +++ b/druid/druid.lua @@ -73,11 +73,11 @@ function M.set_default_style(style) end ---- Set text function. +--- Set text function -- Druid locale component will call this function -- to get translated text. After set_text_funtion -- all existing locale component will be updated --- @function druid.set_text_function(callback) +-- @function druid.set_text_function -- @tparam function callback Get localized text function function M.set_text_function(callback) settings.get_text = callback or const.EMPTY_FUNCTION diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index 8c5b049..782fc48 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -53,14 +53,15 @@ M["scroll"] = { SCROLL_WHEEL_SPEED = 10, DEADZONE = 20, - FRICT = 0.94, -- mult for free inert - FRICT_HOLD = 0.75, -- mult. for inert, while touching + FRICT = 0.93, -- mult for free inert + FRICT_HOLD = 0.79, -- mult. for inert, while touching INERT_THRESHOLD = 2.5, -- speed to stop inertion - INERT_SPEED = 27, -- koef. of inert speed + INERT_SPEED = 30, -- koef. of inert speed BACK_SPEED = 0.35, -- Lerp speed of return to soft position EXTRA_STRECH_SIZE = 100, -- size of outside zone (back move) + SMALL_CONTENT_SCROLL = true, } diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index 9cf5062..de6f1e6 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -5925,7 +5925,7 @@ nodes { } nodes { position { - x: -300.0 + x: -287.0 y: 0.0 z: 0.0 w: 1.0 @@ -7174,6 +7174,69 @@ nodes { template_node_child: false size_mode: SIZE_MODE_MANUAL } +nodes { + position { + x: -197.0 + y: 223.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: "View" + font: "game" + id: "scroll_smaller_view_hint" + 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: "scroll_smaller_view" + 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: 0.0 @@ -7264,7 +7327,7 @@ nodes { blend_mode: BLEND_MODE_ALPHA text: "Content" font: "game" - id: "text" + id: "scroll_smaller_content_hint" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE pivot: PIVOT_CENTER diff --git a/example/gui/main/main.gui_script b/example/gui/main/main.gui_script index 7c39141..3cf9b6a 100644 --- a/example/gui/main/main.gui_script +++ b/example/gui/main/main.gui_script @@ -31,6 +31,7 @@ end local function init_top_panel(self) + self.druid:new_blocker("panel_top") self.druid:new_button("button_left/button", on_control_button, -1) self.druid:new_button("button_right/button", on_control_button, 1) self.header = self.druid:new_lang_text("text_header", "main_page") @@ -60,9 +61,9 @@ function init(self) window.set_listener(on_window_callback) - init_top_panel(self) init_swipe_control(self) - self.page = 4 + + self.page = 1 main_page.setup_page(self) text_page.setup_page(self) button_page.setup_page(self) @@ -70,6 +71,8 @@ function init(self) slider_page.setup_page(self) input_page.setup_page(self) + init_top_panel(self) + -- Refresh state on_control_button(self, 0) end diff --git a/example/page/scroll_page.lua b/example/page/scroll_page.lua index e49d018..f48ec74 100644 --- a/example/page/scroll_page.lua +++ b/example/page/scroll_page.lua @@ -24,7 +24,7 @@ local function init_scroll_with_grid(self) grid_scroll:set_size(grid:get_size()) - local scroll_slider = self.druid:new_slider("grid_scroll_pin", vmath.vector3(300, 0, 0), function(_, value) + local scroll_slider = self.druid:new_slider("grid_scroll_pin", vmath.vector3(287, 0, 0), function(_, value) grid_scroll:scroll_to_percent(vmath.vector3(value, 0, 0), true) end) @@ -55,6 +55,7 @@ function M.setup_page(self) -- Content with less size than view self.druid:new_scroll("scroll_smaller_view", "scroll_smaller_content") :set_extra_strech_size(0) + :set_inert(false) -- Scroll with points of interests self.druid:new_scroll("scroll_with_points", "scroll_with_points_content") From 10c4ee215127ae2359a5fcd3f10f566df5c487ef Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 4 May 2020 00:51:44 +0300 Subject: [PATCH 09/11] Update documentation --- druid/base/scroll.lua | 37 ++++++++++++++++++---------------- druid/styles/default/style.lua | 18 ++++++----------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index dd2a534..d3215da 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -15,15 +15,17 @@ --- 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 node view_node Scroll view node +-- @tfield node content_node Scroll content node -- @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 +-- @tfield vector3 inertion Current inert speed +-- @tfield vector3 position Current scroll posisition +-- @tfield vector3 target_position Current scroll target position +-- @tfield vector4 available_pos Available position for content node: (min_x, max_y, max_x, min_y) +-- @tfield vector3 available_size Size of available positions: (width, height, 0) +-- @tfield druid.drag drag Drag component +-- @tfield[opt] selected Current index of points of interests +-- @tfield bool is_animate Flag, if scroll now animating by gui.animate --- Component style params -- @table Style @@ -31,10 +33,11 @@ -- @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 POINTS_DEADZONE Speed to check points of interests in no_inertion mode -- @tfield number BACK_SPEED Scroll back returning lerp speed -- @tfield number ANIM_SPEED Scroll gui.animation speed for scroll_to function +-- @tfield number EXTRA_STRECH_SIZE extra size in pixels outside of scroll (stretch effect) +-- @tfield bool SMALL_CONTENT_SCROLL If true, content node with size less than view node size can be scrolled local Event = require("druid.event") local const = require("druid.const") @@ -174,11 +177,11 @@ local function check_points(self) local inert = self.inertion if not self._is_inert then - if math.abs(inert.x) > self.style.DEADZONE then + if math.abs(inert.x) > self.style.POINTS_DEADZONE then self:scroll_to_index(self.selected - helper.sign(inert.x)) return end - if math.abs(inert.y) > self.style.DEADZONE then + if math.abs(inert.y) > self.style.POINTS_DEADZONE then self:scroll_to_index(self.selected + helper.sign(inert.y)) return end @@ -251,8 +254,8 @@ local function update_free_scroll(self, dt) -- Inertion friction self.inertion = self.inertion * self.style.FRICT + check_soft_zone(self) if self.position.x ~= target.x or self.position.y ~= target.y then - check_soft_zone(self) set_scroll_position(self, target) end end @@ -326,18 +329,18 @@ end -- @function scroll:init -- @tparam node view_node GUI view scroll node -- @tparam node content_node GUI content scroll node -function M.init(self, view_zone, content_zone) +function M.init(self, view_node, content_node) self.druid = self:get_druid() self.style = self:get_style() - self.view_node = self:get_node(view_zone) - self.content_node = self:get_node(content_zone) + self.view_node = self:get_node(view_node) + self.content_node = self:get_node(content_node) self.position = gui.get_position(self.content_node) self.target_position = vmath.vector3(self.position) self.inertion = vmath.vector3(0) - self.drag = self.druid:new_drag(view_zone, on_scroll_drag) + self.drag = self.druid:new_drag(view_node, on_scroll_drag) self.drag.on_touch_start:subscribe(on_touch_start) self.drag.on_touch_end:subscribe(on_touch_end) diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index 782fc48..cd21fe7 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -44,24 +44,23 @@ M["button"] = { M["drag"] = { - DRAG_DEADZONE = 10, + DRAG_DEADZONE = 10, -- Size in pixels of drag deadzone } M["scroll"] = { ANIM_SPEED = 0.2, -- gui.animation speed to point - SCROLL_WHEEL_SPEED = 10, - DEADZONE = 20, - + BACK_SPEED = 0.35, -- Lerp speed of return to soft position FRICT = 0.93, -- mult for free inert FRICT_HOLD = 0.79, -- mult. for inert, while touching INERT_THRESHOLD = 2.5, -- speed to stop inertion INERT_SPEED = 30, -- koef. of inert speed + EXTRA_STRECH_SIZE = 100, -- extra size in pixels outside of scroll (stretch effect) + POINTS_DEADZONE = 20, -- Speed to check points of interests in no_inertion mode - BACK_SPEED = 0.35, -- Lerp speed of return to soft position + SCROLL_WHEEL_SPEED = 20, - EXTRA_STRECH_SIZE = 100, -- size of outside zone (back move) - SMALL_CONTENT_SCROLL = true, + SMALL_CONTENT_SCROLL = true, -- If true, content node with size less than view node size can be scrolled } @@ -71,11 +70,6 @@ M["progress"] = { } -M["progress_rich"] = { - DELAY = 1, -- delay in seconds before main fill -} - - M["checkbox"] = { on_change_state = function(self, node, state) local target = state and 1 or 0 From 9195201b9cd4f21b8b98c086bfc97932aeebe95e Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 4 May 2020 00:52:06 +0300 Subject: [PATCH 10/11] Update ldoc --- docs/index.html | 7 +- docs/modules/component.html | 3 +- docs/modules/druid.back_handler.html | 3 +- docs/modules/druid.blocker.html | 3 +- docs/modules/druid.button.html | 3 +- docs/modules/druid.checkbox.html | 3 +- docs/modules/druid.checkbox_group.html | 3 +- docs/modules/druid.drag.html | 2 +- docs/modules/druid.grid.html | 3 +- docs/modules/druid.helper.html | 62 +++- docs/modules/druid.hover.html | 3 +- docs/modules/druid.html | 11 +- docs/modules/druid.input.html | 31 +- docs/modules/druid.lang_text.html | 3 +- docs/modules/druid.progress.html | 3 +- docs/modules/druid.radio_group.html | 3 +- docs/modules/druid.scroll.html | 291 ++++++++++++------ docs/modules/druid.slider.html | 3 +- docs/modules/druid.swipe.html | 3 +- docs/modules/druid.text.html | 5 +- docs/modules/druid.timer.html | 3 +- docs/modules/druid_event.html | 3 +- docs/modules/druid_instance.html | 4 +- docs/topics/01-components.md.html | 3 +- .../02-creating_custom_components.md.html | 3 +- docs/topics/03-styles.md.html | 3 +- docs/topics/04-druid_assets.md.html | 3 +- docs/topics/05-examples.md.html | 3 +- docs/topics/README.md.html | 3 +- docs/topics/changelog.md.html | 55 +++- 30 files changed, 377 insertions(+), 154 deletions(-) diff --git a/docs/index.html b/docs/index.html index 3ffa283..c7116f4 100644 --- a/docs/index.html +++ b/docs/index.html @@ -36,6 +36,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -93,6 +94,10 @@ druid.checkbox_group Checkbox group module + + druid.drag + Component to handle drag action on node. + druid.grid Component to handle placing components by row and columns. @@ -195,7 +200,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/component.html b/docs/modules/component.html index 37fd89c..aae8da2 100644 --- a/docs/modules/component.html +++ b/docs/modules/component.html @@ -43,6 +43,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -478,7 +479,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.back_handler.html b/docs/modules/druid.back_handler.html index 0bc2cc0..7e95a33 100644 --- a/docs/modules/druid.back_handler.html +++ b/docs/modules/druid.back_handler.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -217,7 +218,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.blocker.html b/docs/modules/druid.blocker.html index 02feafd..721f904 100644 --- a/docs/modules/druid.blocker.html +++ b/docs/modules/druid.blocker.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -236,7 +237,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.button.html b/docs/modules/druid.button.html index b59dd1c..883e585 100644 --- a/docs/modules/druid.button.html +++ b/docs/modules/druid.button.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -416,7 +417,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.checkbox.html b/docs/modules/druid.checkbox.html index 1411d1c..ea9bf32 100644 --- a/docs/modules/druid.checkbox.html +++ b/docs/modules/druid.checkbox.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -279,7 +280,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.checkbox_group.html b/docs/modules/druid.checkbox_group.html index 0a7c625..ee56ba9 100644 --- a/docs/modules/druid.checkbox_group.html +++ b/docs/modules/druid.checkbox_group.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -241,7 +242,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.drag.html b/docs/modules/druid.drag.html index ae4e709..a25b190 100644 --- a/docs/modules/druid.drag.html +++ b/docs/modules/druid.drag.html @@ -279,7 +279,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-05-04 00:06:50 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.grid.html b/docs/modules/druid.grid.html index 0a0ae13..a487fda 100644 --- a/docs/modules/druid.grid.html +++ b/docs/modules/druid.grid.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -372,7 +373,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.helper.html b/docs/modules/druid.helper.html index 822ba15..e05799f 100644 --- a/docs/modules/druid.helper.html +++ b/docs/modules/druid.helper.html @@ -43,6 +43,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -100,6 +101,18 @@ get_pivot_offset(pivot) Get node offset for given gui pivot + + helper..is_mobile() + Check if device is mobile (Android or iOS) + + + is_web() + Check if device is HTML5 + + + get_border() + Distance from node to size border +
    @@ -230,6 +243,53 @@ + +
    + + helper..is_mobile() +
    +
    + Check if device is mobile (Android or iOS) + + + + + + + +
    +
    + + is_web() +
    +
    + Check if device is HTML5 + + + + + + + +
    +
    + + get_border() +
    +
    + Distance from node to size border + + + +

    Returns:

    +
      + + vector4 (left, top, right, down) +
    + + + +
    @@ -238,7 +298,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.hover.html b/docs/modules/druid.hover.html index 5313e41..7d36b64 100644 --- a/docs/modules/druid.hover.html +++ b/docs/modules/druid.hover.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -213,7 +214,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.html b/docs/modules/druid.html index 021f3db..ea8c216 100644 --- a/docs/modules/druid.html +++ b/docs/modules/druid.html @@ -43,6 +43,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -114,7 +115,9 @@ set_text_function(callback) - Set text function. + Set text function + Druid locale component will call this function + to get translated text. set_sound_function(callback) @@ -226,9 +229,9 @@ set_text_function(callback)
    - Set text function. + Set text function Druid locale component will call this function - to get translated text. After settextfuntion + to get translated text. After settextfuntion all existing locale component will be updated @@ -326,7 +329,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.input.html b/docs/modules/druid.input.html index 8f6b84b..737bc3d 100644 --- a/docs/modules/druid.input.html +++ b/docs/modules/druid.input.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -96,11 +97,11 @@ Return current input field text - set_max_length(max_length, Self) + set_max_length(max_length) Set maximum length for input field. - set_allowerd_characters(characters, Self) + set_allowerd_characters(characters) Set allowed charaters for input field. @@ -174,7 +175,7 @@
    - set_max_length(max_length, Self) + set_max_length(max_length)
    Set maximum length for input field. @@ -187,12 +188,14 @@ number Maximum length for input text field -
  • Self - druid.input - instance to make chain calls -
  • +

    Returns:

    +
      + + druid.input + Self instance to make chain calls +
    @@ -200,7 +203,7 @@
    - set_allowerd_characters(characters, Self) + set_allowerd_characters(characters)
    Set allowed charaters for input field. @@ -214,12 +217,14 @@ string Regulax exp. for validate user input -
  • Self - druid.input - instance to make chain calls -
  • +

    Returns:

    +
      + + druid.input + Self instance to make chain calls +
    @@ -383,7 +388,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.lang_text.html b/docs/modules/druid.lang_text.html index 3ffaa4c..8345b88 100644 --- a/docs/modules/druid.lang_text.html +++ b/docs/modules/druid.lang_text.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -242,7 +243,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.progress.html b/docs/modules/druid.progress.html index 2181941..60b3a72 100644 --- a/docs/modules/druid.progress.html +++ b/docs/modules/druid.progress.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -381,7 +382,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.radio_group.html b/docs/modules/druid.radio_group.html index e2de393..65b2d6f 100644 --- a/docs/modules/druid.radio_group.html +++ b/docs/modules/druid.radio_group.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -241,7 +242,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.scroll.html b/docs/modules/druid.scroll.html index a4b9263..e9aae94 100644 --- a/docs/modules/druid.scroll.html +++ b/docs/modules/druid.scroll.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -89,40 +90,48 @@

    Functions

    - - + + - + + + + + - - + + - - + + - - + + - - + + - - + + + + + +
    init(scroll_parent, input_zone)Component init functioninit(view_node, content_node)Scroll constructor.
    scroll_to(vector3[, is_instant])Start scroll to target pointStart scroll to target point.
    scroll_to_index(index[, skip_cb])Scroll to item in scroll by point index.
    scroll_to_percent(vector3[, is_instant]) Start scroll to target scroll percent
    init(index[, skip_cb])Scroll to item in scroll by point indexget_percent()Return current scroll progress status.
    set_points(points)Set points of interest.set_size(size)Set scroll content size.
    set_inert(state) Enable or disable scroll inert.
    on_point_move(callback)Set the callback on scrolling to point (if exist)is_inert()Return if scroll have inertion.
    set_border(border)Set the scroll possibly areaset_extra_strech_size(stretch_size)Set extra size for scroll stretching.
    get_scroll_percent()Return current scroll progressget_scroll_size()Return vector of scroll size with width and height.
    set_points(points)Set points of interest.

    Tables

    @@ -150,21 +159,21 @@
    - init(scroll_parent, input_zone) + init(view_node, content_node)
    - Component init function + Scroll constructor.

    Parameters:

      -
    • scroll_parent +
    • view_node node - Gui node where placed scroll content. This node will change position + GUI view scroll node
    • -
    • input_zone +
    • content_node node - Gui node where input is catched + GUI content scroll node
    @@ -178,18 +187,18 @@ scroll_to(vector3[, is_instant])
    - Start scroll to target point + Start scroll to target point.

    Parameters:

    • vector3 point - target point + Target point
    • is_instant bool - instant scroll flag + Instant scroll flag (optional)
    @@ -203,6 +212,32 @@
  • scroll:scroll_to(vmath.vector3(0), true)
  • +
    +
    + + scroll_to_index(index[, skip_cb]) +
    +
    + Scroll to item in scroll by point index. + + +

    Parameters:

    +
      +
    • index + number + Point index +
    • +
    • skip_cb + bool + If true, skip the point callback + (optional) +
    • +
    + + + + +
    @@ -235,48 +270,49 @@
    - - init(index[, skip_cb]) + + get_percent()
    - Scroll to item in scroll by point index + Return current scroll progress status. + Values will be in [0..1] interval -

    Parameters:

    -
      -
    • index - number - Point index -
    • -
    • skip_cb - bool - If true, skip the point callback - (optional) -
    • -
    +

    Returns:

    +
      + + vector3 + New vector with scroll progress values +
    - - set_points(points) + + set_size(size)
    - Set points of interest. - Scroll will always centered on closer points + Set scroll content size. + It will change content gui node size

    Parameters:

      -
    • points - table - Array of vector3 points +
    • size + vector3 + The new size for content node
    +

    Returns:

    +
      + + druid.scroll + Self instance +
    @@ -300,59 +336,71 @@ +

    Returns:

    +
      + + druid.scroll + Self instance +
    - - on_point_move(callback) + + is_inert()
    - Set the callback on scrolling to point (if exist) + Return if scroll have inertion. + + + +

    Returns:

    +
      + + bool + If scroll have inertion +
    + + + + +
    +
    + + set_extra_strech_size(stretch_size) +
    +
    + Set extra size for scroll stretching. + Set 0 to disable stretching effect

    Parameters:

      -
    • callback - function - Callback on scroll to point of interest +
    • stretch_size + number + Size in pixels of additional scroll area
    +

    Returns:

    +
      + + druid.scroll + Self instance +
    - - set_border(border) + + get_scroll_size()
    - Set the scroll possibly area - - -

    Parameters:

    -
      -
    • border - vector3 - Size of scrolling area -
    • -
    - - - - - -
    -
    - - get_scroll_percent() -
    -
    - Return current scroll progress + Return vector of scroll size with width and height. @@ -360,7 +408,35 @@
      vector3 - Scroll progress + Available scroll size +
    + + + + +
    +
    + + set_points(points) +
    +
    + Set points of interest. + Scroll will always centered on closer points + + +

    Parameters:

    +
      +
    • points + table + Array of vector3 points +
    • +
    + +

    Returns:

    +
      + + druid.scroll + Self instance
    @@ -410,42 +486,51 @@

    Fields:

      -
    • node +
    • view_node node - Scroll parent node + Scroll view node
    • -
    • input_zone +
    • content_node node - Scroll input node -
    • -
    • zone_size - vector3 - Current scroll content size -
    • -
    • soft_size - number - Soft zone size from style table -
    • -
    • center_offset - vector3 - Distance from node to node's center + Scroll content node
    • is_inert bool Flag, if scroll now moving by inertion
    • -
    • inert +
    • inertion vector3 Current inert speed
    • -
    • pos +
    • position vector3 Current scroll posisition
    • -
    • target +
    • target_position vector3 Current scroll target position
    • +
    • available_pos + vector4 + Available position for content node: (minx, maxy, maxx, miny) +
    • +
    • available_size + vector3 + Size of available positions: (width, height, 0) +
    • +
    • drag + druid.drag + Drag component +
    • +
    • Current + selected + index of points of interests + (optional) +
    • +
    • is_animate + bool + Flag, if scroll now animating by gui.animate +
    @@ -479,13 +564,9 @@ number Multiplier for inertion speed -
  • DEADZONE +
  • POINTS_DEADZONE number - Deadzone for start scrol in pixels -
  • -
  • SOFT_ZONE_SIZE - number - Size of outside zone in pixels (for scroll back moving) + Speed to check points of interests in no_inertion mode
  • BACK_SPEED number @@ -495,6 +576,14 @@ number Scroll gui.animation speed for scroll_to function
  • +
  • EXTRA_STRECH_SIZE + number + extra size in pixels outside of scroll (stretch effect) +
  • +
  • SMALL_CONTENT_SCROLL + bool + If true, content node with size less than view node size can be scrolled +
  • @@ -509,7 +598,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.slider.html b/docs/modules/druid.slider.html index 2c42e44..c81ac6e 100644 --- a/docs/modules/druid.slider.html +++ b/docs/modules/druid.slider.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -280,7 +281,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.swipe.html b/docs/modules/druid.swipe.html index 15505fb..6589bc4 100644 --- a/docs/modules/druid.swipe.html +++ b/docs/modules/druid.swipe.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -250,7 +251,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.text.html b/docs/modules/druid.text.html index 15e8ccc..a081325 100644 --- a/docs/modules/druid.text.html +++ b/docs/modules/druid.text.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -309,7 +310,7 @@

    Returns:

      - boolean + bool Is text node with line break
    @@ -406,7 +407,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid.timer.html b/docs/modules/druid.timer.html index 3bf0f9d..c1ad7b9 100644 --- a/docs/modules/druid.timer.html +++ b/docs/modules/druid.timer.html @@ -44,6 +44,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -295,7 +296,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid_event.html b/docs/modules/druid_event.html index df96371..877e8bc 100644 --- a/docs/modules/druid_event.html +++ b/docs/modules/druid_event.html @@ -43,6 +43,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -241,7 +242,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/modules/druid_instance.html b/docs/modules/druid_instance.html index 0a4c8b4..ad27765 100644 --- a/docs/modules/druid_instance.html +++ b/docs/modules/druid_instance.html @@ -43,6 +43,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -96,6 +97,7 @@
  • druid.checkbox_group
  • druid.radio_group
  • druid.swipe
  • +
  • druid.drag
  • @@ -880,7 +882,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/topics/01-components.md.html b/docs/topics/01-components.md.html index 9b1000c..7f48b5e 100644 --- a/docs/topics/01-components.md.html +++ b/docs/topics/01-components.md.html @@ -68,6 +68,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -412,7 +413,7 @@ Key is value from druid const: const.SIDE.X (or just "x") or const.SIDE.Y (or ju
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/topics/02-creating_custom_components.md.html b/docs/topics/02-creating_custom_components.md.html index 0251ceb..67a5e37 100644 --- a/docs/topics/02-creating_custom_components.md.html +++ b/docs/topics/02-creating_custom_components.md.html @@ -56,6 +56,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -244,7 +245,7 @@ There is next interests in druid:
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/topics/03-styles.md.html b/docs/topics/03-styles.md.html index 8d2a391..8bdb3b1 100644 --- a/docs/topics/03-styles.md.html +++ b/docs/topics/03-styles.md.html @@ -54,6 +54,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -134,7 +135,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/topics/04-druid_assets.md.html b/docs/topics/04-druid_assets.md.html index 227822d..738e4fb 100644 --- a/docs/topics/04-druid_assets.md.html +++ b/docs/topics/04-druid_assets.md.html @@ -53,6 +53,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -91,7 +92,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/topics/05-examples.md.html b/docs/topics/05-examples.md.html index 28a3d17..187c016 100644 --- a/docs/topics/05-examples.md.html +++ b/docs/topics/05-examples.md.html @@ -53,6 +53,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -89,7 +90,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/topics/README.md.html b/docs/topics/README.md.html index f57e3ae..2205ddb 100644 --- a/docs/topics/README.md.html +++ b/docs/topics/README.md.html @@ -63,6 +63,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -336,7 +337,7 @@ https://insality.github.io/druid/

    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    diff --git a/docs/topics/changelog.md.html b/docs/topics/changelog.md.html index 9eba3e8..2cfc3d9 100644 --- a/docs/topics/changelog.md.html +++ b/docs/topics/changelog.md.html @@ -49,6 +49,7 @@
  • druid.button
  • druid.checkbox
  • druid.checkbox_group
  • +
  • druid.drag
  • druid.grid
  • druid.hover
  • druid.input
  • @@ -75,7 +76,7 @@

    Druid 0.3.0:

      -
    • Druid:final now is important function for correct working

    • +
    • Druid:final() now is important function for correct working

    • Add swipe basic component

      @@ -94,14 +95,10 @@
       - You can setup max length of the text
       - You can setup allowed characters. On add not allowed characters on_input_wrong will be called. By default it cause simple shake animation
       - The keyboard for input will not show on mobile HTML5. So input field in mobile HTML5 is not working now
      -- To make work different keyboard type, make sure value in game.project Android:InputMethod set to HidderInputField (https://defold.com/manuals/project-settings/#input-method)
      +- To make work different keyboard type, make sure value in game.project Android:InputMethod set to HiddenInputField (https://defold.com/manuals/project-settings/#input-method)
       
    • -
    • Add button onclickoutside event. You can subscribe on this event in button. Was needed for Input component (click outside to deselect input field).

    • -
    • Add start_pos to button component

    • -
    • Changed input binding settings. Add backspace, enter, text and marked_text. Backspace now is different from android back button.

    • -
    • Renamed onchangelanguage -> onlanguagechange component interest

    • -
    • Add basic component two functions: increase_input_priority and reset_input_priority. It used to process component input first in current input stack (there is two input stacks: INPUT and INPUT_HIGH). Example: on selecting input field, it increase input self priority until it be unselected

    • +
    • Add two functions to basic component: increase_input_priority and reset_input_priority. It used to process component input first in current input stack (there is two input stacks now: INPUT and INPUT_HIGH). Example: on selecting input field, it increase input self priority until it be unselected

    • Add two new component interests: on_focus_gain and on_focus_lost

    • Add global druid events:

      @@ -111,13 +108,53 @@ - on_layout_change: call druid.on_layout_change() (#37) for update all gui layouts (unimplemented now)
    • -
    • Add several examples to druid-assets respository

    • +
    • Add button on_click_outside event. You can subscribe on this event in button. Was needed for Input component (click outside to deselect input field)

    • +
    • Add startpos_ field to button component

    • +
    • Changed input binding settings. Add esc, enter, text and marked_text. Backspace now is different from android back button event. Check the README setup section

    • +
    • Renamed onchangelanguage -> onlanguagechange component interest

    • +
    • Add several examples to druid-assets respository (see live example here): https://insality.github.io/druid-assets/)

    • Known issues:

       - Adjusting text size by height works wrong. Adjusting single line texting works fine
      +- Space is not working in HTML5
      +
      + +

      Druid 0.4.0:

    • +
    • Add Drag basic component

      + +
      +- Drag component allow you detect dragging on GUI node
      +- Drag will be processed even the cursor is outside of node, if drag is already started
      +- Drag provides correct handle of several touches. Drag can switch between them (no more scroll gliches with position)
      +- Drag have next events:
      +    - on_touch_start (self)
      +    - on_touch_end (self)
      +    - on_drag_start (self)
      +    - on_drag (self, dx, dy)
      +    - on_drag_end (self)
      +- You can restriction side of draggin by changing _drag.can_x_ and _drag.can_y_ fields
      +- You can setup drag deadzone to detect, when dragging is started (by default 10 pixels)
       
    • +
    • Druid Scroll component fully reworked. Input logic moved to Drag component

      + +
      +- Updated scroll documentation
      +- Changed constructor order params
      +- Scroll now contains from view and content node
      +    - _View node_ - static node, which size determine the "camera" zone
      +    - _Content node_ - dynamic node, moving by _Scroll_ component
      +- Scroll will be disabled only if content size equals to view size (by width or height separatly)
      +- You can adjust scroll size via _.gui_ scene. Just setup correct node size
      +- Different anchoring is supported (for easier layout)
      +- Function _scroll_to_ now accept position relative to _content node_. It's more easier for handling. _Example:_ if you have children node of _content_node_, you can pass this node position to scroll to this.
      +- **Resolve #52**: _Content node size_ now can be less than _view node size_. In this case, content will be scrolled only inside _view size_
      +- **Fix #50**: If style:SOFT_ZONE_SIZE equals to [0..1], scroll can be disappeared
      +
      +
    • +
    • Grid anchor by default equals to node pivot (so, more gui settings in .gui settings)

    • +
    • Fix: Blocker component bug (blocker had very high priority, so it's block even button components, created after bloker)

    @@ -125,7 +162,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-04-18 14:39:17 +Last updated 2020-05-04 00:51:46
    From dad7cd91b606026cdbbc02e0a4be1cbbd0334594 Mon Sep 17 00:00:00 2001 From: Insality Date: Mon, 4 May 2020 00:58:38 +0300 Subject: [PATCH 11/11] Add annotation to new_drag function --- druid/system/druid_instance.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index d1b3fa7..bd02e44 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -449,6 +449,10 @@ function Druid.new_swipe(self, ...) end +--- Create drag basic component +-- @function druid:new_drag +-- @tparam args ... drag init args +-- @treturn Componetn drag component function Druid.new_drag(self, ...) return Druid.create(self, drag, ...) end