From 3339b000712bdf5bbe931b7e93937761a92b972f Mon Sep 17 00:00:00 2001 From: Insality Date: Fri, 17 Apr 2020 20:04:45 +0300 Subject: [PATCH] Add simple swipe component --- druid/base/hover.lua | 2 +- druid/base/swipe.lua | 129 +++++++++++++++++++++++++++++++ druid/const.lua | 9 ++- druid/styles/default/style.lua | 7 ++ druid/system/druid_instance.lua | 11 +++ example/gui/main/main.gui | 6 +- example/gui/main/main.gui_script | 13 ++++ example/page/main.lua | 1 - 8 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 druid/base/swipe.lua diff --git a/druid/base/hover.lua b/druid/base/hover.lua index 0fb916a..2a831a7 100644 --- a/druid/base/hover.lua +++ b/druid/base/hover.lua @@ -70,7 +70,7 @@ function M.set_hover(self, state) end ---- Strict button click area. Useful for +--- Strict hover click area. Useful for -- no click events outside stencil node -- @function hover:set_click_zone -- @tparam node zone Gui node diff --git a/druid/base/swipe.lua b/druid/base/swipe.lua new file mode 100644 index 0000000..e9fbf31 --- /dev/null +++ b/druid/base/swipe.lua @@ -0,0 +1,129 @@ +--- Component to handle swipe gestures on node. +-- Swipe will be triggered, if swipe was started and +-- ended on one node +-- @module druid.swipe + +--- Component events +-- @table Events +-- @tfield druid_event on_swipe Trigger on swipe event + +--- Component style params +-- @table Style +-- @tfield number SWIPE_TIME Maximum time for swipe trigger +-- @tfield number SWIPE_THRESHOLD Minimum distance for swipe trigger +-- @tfield bool SWIPE_TRIGGER_ON_MOVE If true, trigger on swipe moving, not only release action + +local Event = require("druid.event") +local const = require("druid.const") +local helper = require("druid.helper") +local component = require("druid.component") + +local M = component.create("swipe", { const.ON_INPUT }) + + +local function start_swipe(self, action) + self._swipe_start_time = socket.gettime() + self.start_pos.x = action.x + self.start_pos.y = action.y +end + + +local function reset_swipe(self, action) + self._swipe_start_time = false +end + + +local function check_swipe(self, action) + local dx = action.x - self.start_pos.x + local dy = action.y - self.start_pos.y + local dist = helper.distance(self.start_pos.x, self.start_pos.y, action.x, action.y) + local delta_time = socket.gettime() - self._swipe_start_time + local is_swipe = self.style.SWIPE_THRESHOLD <= dist and delta_time <= self.style.SWIPE_TIME + + if is_swipe then + local is_x_swipe = math.abs(dx) >= math.abs(dy) + local swipe_side = false + if is_x_swipe and dx > 0 then + swipe_side = const.SWIPE.RIGHT + end + if is_x_swipe and dx < 0 then + swipe_side = const.SWIPE.LEFT + end + if not is_x_swipe and dy > 0 then + swipe_side = const.SWIPE.UP + end + if not is_x_swipe and dy < 0 then + swipe_side = const.SWIPE.DOWN + end + + self.on_swipe:trigger(self:get_context(), swipe_side, dist, delta_time) + reset_swipe(self) + 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 +function M.init(self, node, on_swipe_callback) + self.style = self:get_style() + self._trigger_on_move = self.style.SWIPE_TRIGGER_ON_MOVE + self.node = self:get_node(node) + + self._swipe_start_time = false + self.start_pos = vmath.vector3(0) + + self.click_zone = nil + self.on_swipe = Event(on_swipe_callback) +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 then + reset_swipe(self, action) + return false + end + + if self._swipe_start_time and (self._trigger_on_move or action.released) then + check_swipe(self, action) + end + + if action.pressed then + start_swipe(self, action) + end + + if action.released then + reset_swipe(self, action) + end +end + + +function M.on_input_interrupt(self) + reset_swipe(self) +end + + +--- Strict swipe click area. Useful for +-- restrict events outside stencil node +-- @function swipe: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/const.lua b/druid/const.lua index fd2c121..7d1dcf0 100644 --- a/druid/const.lua +++ b/druid/const.lua @@ -58,10 +58,17 @@ M.SIDE = { Y = "y" } +M.SWIPE = { + UP = "up", + DOWN = "down", + LEFT = "left", + RIGHT = "right", +} + M.EMPTY_FUNCTION = function() end M.EMPTY_STRING = "" M.EMPTY_TABLE = {} -return M \ No newline at end of file +return M diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index eaddd9d..12164e3 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -75,4 +75,11 @@ M["checkbox"] = { } +M["swipe"] = { + SWIPE_THRESHOLD = 50, + SWIPE_TIME = 0.4, + SWIPE_TRIGGER_ON_MOVE = true +} + + return M diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 9739803..f071608 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -15,6 +15,7 @@ -- @see druid.checkbox -- @see druid.checkbox_group -- @see druid.radio_group +-- @see druid.swipe local const = require("druid.const") local druid_input = require("druid.helper.druid_input") @@ -36,6 +37,7 @@ local checkbox = require("druid.base.checkbox") 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 infinity_scroll = require("druid.base.infinity_scroll") -- @classmod Druid @@ -364,4 +366,13 @@ function Druid.new_radio_group(self, ...) end +--- Create swipe basic component +-- @function druid:new_swipe +-- @tparam args ... swipe init args +-- @treturn Component swipe component +function Druid.new_swipe(self, ...) + return Druid.create(self, swipe, ...) +end + + return Druid diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index 91ec206..5f58f85 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -33,8 +33,8 @@ nodes { w: 1.0 } size { - x: 1.0 - y: 1.0 + x: 600.0 + y: 900.0 z: 0.0 w: 1.0 } @@ -65,7 +65,7 @@ nodes { clipping_inverted: false alpha: 1.0 template_node_child: false - size_mode: SIZE_MODE_AUTO + size_mode: SIZE_MODE_MANUAL } nodes { position { diff --git a/example/gui/main/main.gui_script b/example/gui/main/main.gui_script index e9a0106..c08c365 100644 --- a/example/gui/main/main.gui_script +++ b/example/gui/main/main.gui_script @@ -39,11 +39,24 @@ local function init_top_panel(self) end +local function init_swipe_control(self) + self.druid:new_swipe("root", function(_, side) + if side == "left" then + on_control_button(self, 1) + end + if side == "right" then + on_control_button(self, -1) + end + end) +end + + function init(self) druid.set_default_style(default_style) self.druid = druid.new(self) init_top_panel(self) + init_swipe_control(self) self.page = 1 main_page.setup_page(self) text_page.setup_page(self) diff --git a/example/page/main.lua b/example/page/main.lua index 3252792..2da7d7f 100644 --- a/example/page/main.lua +++ b/example/page/main.lua @@ -106,7 +106,6 @@ local function setup_back_handler(self) end - function M.setup_page(self) setup_texts(self)