mirror of
https://github.com/Insality/druid
synced 2025-09-28 02:22:19 +02:00
Scroll refactoring process
This commit is contained in:
214
druid/base/drag.lua
Normal file
214
druid/base/drag.lua
Normal file
@@ -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
|
Reference in New Issue
Block a user