myspace / CommonLua /X /XGesture.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
6.39 kB
if not Platform.switch then return end
DefineClass.XGestureWindow = {
__parents = { "XWindow" },
gesture_time = 300,
tap_dist = 20*20, -- square of the tap max tap offset
taps = false,
last_gesture = false,
swipe_dist = 50,
}
-- recognised gestures
-- tap - fast press and release without moving
-- swipe - fast move to left, right, top or bottom
-- drag - continuous move
-- parallel tap - tap simultaneously with two fingers
-- pinch/rotation/pan - pres two fingers to zoom, rotate and move
function XGestureWindow:Init()
self.taps = {}
end
function XGestureWindow:TapCount(pos)
local time = RealTime() - self.gesture_time
for i = #self.taps, 1, -1 do
local tap = self.taps[i]
if tap.time - time < 0 then
table.remove(self.taps[i])
else
if pos:Dist2D2(tap.pos) < self.tap_dist then
table.remove(self.taps, i)
return tap.count
end
end
end
return 0
end
function XGestureWindow:RegisterTap(pos, count)
self.taps[#self.taps + 1] = { pos = pos, time = RealTime(), count = count }
end
function XGestureWindow:OnTouchBegan(id, pos, touch)
touch.start_pos = pos
touch.start_time = RealTime()
local gesture = self.last_gesture
if not gesture or gesture.done or #gesture == 2 or RealTime() - gesture.start_time > self.gesture_time then
-- new gesture
gesture = { start_time = RealTime(), start_pos = pos, taps = self:TapCount(pos) + 1 }
self.last_gesture = gesture
CreateRealTimeThread(function()
Sleep(self.gesture_time)
if not gesture.done then
self:GestureTime(gesture)
end
end)
end
touch.gesture = gesture
gesture[#gesture + 1] = touch
self:GestureTouch(gesture, touch)
return "break"
end
function XGestureWindow:OnTouchMoved(id, pos, touch)
local gesture = touch.gesture
if gesture then
self:GestureMove(gesture, touch)
end
return "break"
end
function XGestureWindow:OnTouchEnded(id, pos, touch)
local gesture = touch.gesture
if gesture then
self:GestureRelease(gesture, touch)
end
return "break"
end
function XGestureWindow:OnTouchCancelled(id, pos, touch)
local gesture = touch.gesture
if gesture then
self:GestureRelease(gesture, touch)
end
return "break"
end
function XGestureWindow:GestureTouch(gesture, touch)
if #gesture == 2 then
if gesture.type == "drag" then
self:OnDragStop(gesture[1].start_pos, gesture)
gesture.type = "pinch"
self:OnPinchStart((gesture[1].start_pos + gesture[2].start_pos) / 2, gesture)
self:UpdatePinch(gesture)
end
end
end
function XGestureWindow:GestureTime(gesture)
if #gesture == 1 and not gesture.type then
gesture.type = "drag"
self:OnDragStart(gesture[1].start_pos, gesture)
end
end
function XGestureWindow:GestureMove(gesture, touch)
local tap = touch.start_pos:Dist2D2(touch.pos) < self.tap_dist
if #gesture == 1 then
if gesture.type == "drag" then
self:OnDragMove(touch.pos, gesture)
elseif not tap and not gesture.type then
gesture.type = "drag"
self:OnDragStart(gesture.start_pos, gesture)
end
elseif #gesture == 2 and not tap then
if gesture.type ~= "pinch" then
gesture.type = "pinch"
self:OnPinchStart((gesture[1].start_pos + gesture[2].start_pos) / 2, gesture)
end
self:UpdatePinch(gesture)
end
end
function XGestureWindow:GestureRelease(gesture, touch)
local tap = touch.start_pos:Dist2D2(touch.pos) < self.tap_dist
gesture.done = true
if #gesture == 1 then
if gesture.type == "drag" then
self:OnDragEnd(touch.pos, gesture)
return
end
assert(RealTime() - gesture.start_time < self.gesture_time and tap)
self:RegisterTap(touch.pos, gesture.taps)
self:OnTap(touch.pos, gesture)
elseif #gesture == 2 then
if gesture.type == "pinch" then
self:UpdatePinch(gesture)
self:OnPinchEnd(gesture)
end
if RealTime() - gesture.start_time < self.gesture_time and tap then
self:OnParallelTap(gesture)
end
end
end
function XGestureWindow:UpdatePinch(gesture)
-- offset
self:OnPinchMove((gesture[1].pos - gesture[1].start_pos + gesture[2].pos - gesture[2].start_pos) / 2, gesture)
-- zoom
gesture.start_dist = gesture.start_dist or (gesture[1].start_pos:Dist2D(gesture[2].start_pos))
self:OnPinchZoom(gesture[1].pos:Dist2D(gesture[2].pos) * 1000 / gesture.start_dist, gesture)
-- rotate
self:OnPinchRotate(CalcAngleBetween2D(
gesture[1].start_pos - gesture[2].start_pos,
gesture[1].pos - gesture[2].pos
), gesture)
end
function XGestureWindow:OnTap(pos, gesture)
print("tap", pos, gesture.taps)
end
function XGestureWindow:OnDragStart(pos, gesture)
end
function XGestureWindow:OnDragMove(pos, gesture)
local offset = pos - gesture[1].start_pos
if gesture.swipe then
if gesture.swipe == "h" then
self:OnHSwipeUpdate(offset:x(), gesture)
end
if gesture.swipe == "v" then
self:OnVSwipeUpdate(offset:y(), gesture)
end
else
if abs(offset:x()) > self.swipe_dist then
gesture.swipe = "h"
self:OnHSwipeStart(offset:x(), gesture)
elseif abs(offset:y()) > self.swipe_dist then
gesture.swipe = "v"
self:OnVSwipeStart(offset:y(), gesture)
end
end
end
function XGestureWindow:OnDragEnd(pos, gesture)
local offset = pos - gesture[1].start_pos
if gesture.swipe then
if gesture.swipe == "h" then
self:OnHSwipeEnd(offset:x(), gesture, offset:x() * 1000 / (RealTime() - gesture.start_time + 1))
end
if gesture.swipe == "v" then
self:OnVSwipeEnd(offset:y(), gesture, offset:y() * 1000 / (RealTime() - gesture.start_time + 1))
end
end
end
function XGestureWindow:OnHSwipeStart(offs, gesture)
end
function XGestureWindow:OnHSwipeUpdate(offs, gesture)
end
function XGestureWindow:OnHSwipeEnd(offs, gesture)
end
function XGestureWindow:OnVSwipeStart(offs, gesture)
end
function XGestureWindow:OnVSwipeUpdate(offs, gesture)
end
function XGestureWindow:OnVSwipeEnd(offs, gesture)
end
function XGestureWindow:OnParallelTap(gesture)
print("parallel tap", gesture[1].pos)
end
function XGestureWindow:OnPinchStart(gesture)
print("pinch start")
end
function XGestureWindow:OnPinchMove(offset, gesture)
print("move", offset)
end
function XGestureWindow:OnPinchZoom(zoom, gesture)
print("zoom", zoom)
end
function XGestureWindow:OnPinchRotate(angle, gesture)
print("rotate", angle)
end
function XGestureWindow:OnPinchEnd(gesture)
print("pinch end")
end
--[[
function OnMsg.DesktopCreated()
local win = XGestureWindow:new(terminal.desktop)
win:SetPos(point20)
win:SetSize(terminal.desktop:GetSize())
end
--]]