mirror of
https://github.com/Insality/druid.git
synced 2025-06-27 18:37:44 +02:00
170 lines
4.3 KiB
Lua
170 lines
4.3 KiB
Lua
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
|
|
|
|
--- Component to handle swipe gestures on node.
|
|
-- Swipe will be triggered, if swipe was started and
|
|
-- ended on one node
|
|
--
|
|
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_swipe" target="_blank"><b>Example Link</b></a>
|
|
-- @module Swipe
|
|
-- @within BaseComponent
|
|
-- @alias druid.swipe
|
|
|
|
--- Swipe node
|
|
---@param node node
|
|
|
|
--- Restriction zone
|
|
---@param click_zone node|nil
|
|
|
|
--- Trigger on swipe event(self, swipe_side, dist, delta_time)
|
|
-- @tfield druid.event on_swipe) druid.event
|
|
|
|
---
|
|
|
|
local Event = require("druid.event")
|
|
local const = require("druid.const")
|
|
local helper = require("druid.helper")
|
|
local component = require("druid.component")
|
|
|
|
---@class druid.swipe: druid.base_component
|
|
---@field node node
|
|
---@field on_swipe druid.event
|
|
---@field style table
|
|
---@field click_zone node
|
|
---@field private _trigger_on_move boolean
|
|
---@field private _swipe_start_time number
|
|
---@field private _start_pos vector3
|
|
---@field private _is_enabled boolean
|
|
---@field private _is_mobile boolean
|
|
local M = component.create("swipe")
|
|
|
|
|
|
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 = 0
|
|
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 style params.
|
|
-- You can override this component styles params in druid styles table
|
|
-- or create your own style
|
|
-- @table style
|
|
-- @tfield number|nil SWIPE_TIME Maximum time for swipe trigger. Default: 0.4
|
|
-- @tfield number|nil SWIPE_THRESHOLD Minimum distance for swipe trigger. Default: 50
|
|
-- @tfield boolean|nil SWIPE_TRIGGER_ON_MOVE If true, trigger on swipe moving, not only release action. Default: false
|
|
function M:on_style_change(style)
|
|
self.style = {}
|
|
self.style.SWIPE_TIME = style.SWIPE_TIME or 0.4
|
|
self.style.SWIPE_THRESHOLD = style.SWIPE_THRESHOLD or 50
|
|
self.style.SWIPE_TRIGGER_ON_MOVE = style.SWIPE_TRIGGER_ON_MOVE or false
|
|
end
|
|
|
|
|
|
---Swipe constructor
|
|
---@param node_or_node_id node|string
|
|
---@param on_swipe_callback function
|
|
function M:init(node_or_node_id, on_swipe_callback)
|
|
self._trigger_on_move = self.style.SWIPE_TRIGGER_ON_MOVE
|
|
self.node = self:get_node(node_or_node_id)
|
|
|
|
self._swipe_start_time = 0
|
|
self._start_pos = vmath.vector3(0)
|
|
|
|
self.click_zone = nil
|
|
self.on_swipe = Event(on_swipe_callback)
|
|
end
|
|
|
|
|
|
function M:on_late_init()
|
|
if not self.click_zone and const.IS_STENCIL_CHECK then
|
|
local stencil_node = helper.get_closest_stencil_node(self.node)
|
|
if stencil_node then
|
|
self:set_click_zone(stencil_node)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
---@param action_id hash
|
|
---@param action action
|
|
function M:on_input(action_id, action)
|
|
if action_id ~= const.ACTION_TOUCH then
|
|
return false
|
|
end
|
|
|
|
if not gui.is_enabled(self.node, true) then
|
|
return false
|
|
end
|
|
|
|
local is_pick = helper.pick_node(self.node, action.x, action.y, self.click_zone)
|
|
if not is_pick then
|
|
reset_swipe(self, action)
|
|
return false
|
|
end
|
|
|
|
if self._swipe_start_time ~= 0 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
|
|
|
|
return true
|
|
end
|
|
|
|
|
|
function M:on_input_interrupt()
|
|
reset_swipe(self)
|
|
end
|
|
|
|
|
|
--- Strict swipe click area. Useful for
|
|
-- restrict events outside stencil node
|
|
---@param zone node|string|nil Gui node
|
|
function M:set_click_zone(zone)
|
|
self.click_zone = self:get_node(zone)
|
|
end
|
|
|
|
|
|
return M
|