160 lines
3.9 KiB
Lua
160 lines
3.9 KiB
Lua
|
|
local currentPath = (...):match('(.-)[^%./]+$')
|
||
|
|
local parentPath = currentPath:match('(.-)[^%./]+%.$')
|
||
|
|
|
||
|
|
--- @class IUILib
|
||
|
|
local iui = require(parentPath .. "iui")
|
||
|
|
|
||
|
|
--- @class (exact) IUIMouseVelocityEntry
|
||
|
|
--- @field dx number
|
||
|
|
--- @field dy number
|
||
|
|
--- @field timestamp number
|
||
|
|
--- @field dt number
|
||
|
|
|
||
|
|
--- @class (exact) IUIMouseState
|
||
|
|
--- @field x number
|
||
|
|
--- @field y number
|
||
|
|
--- @field dx number
|
||
|
|
--- @field dy number
|
||
|
|
--- @field scrollX number
|
||
|
|
--- @field scrollY number
|
||
|
|
--- @field down IUISet<number>
|
||
|
|
--- @field pressed IUISet<number>
|
||
|
|
--- @field released IUISet<number>
|
||
|
|
|
||
|
|
--- @class (exact) IUIMouseRootContext
|
||
|
|
--- @field velocityBuffer IUIMouseVelocityEntry[]
|
||
|
|
--- @field storage IUIMouseState
|
||
|
|
--- @field disabledStorage IUIMouseState
|
||
|
|
|
||
|
|
local ctx --- @type IUIMouseRootContext
|
||
|
|
|
||
|
|
local function limitMouseVelocityEvents()
|
||
|
|
local limit = iui.backend.system.getTimestamp() - 0.1
|
||
|
|
|
||
|
|
while #ctx.velocityBuffer > 0 and ctx.velocityBuffer[1].timestamp < limit do
|
||
|
|
table.remove(ctx.velocityBuffer, 1)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local function addMouseVelocityEvent(dx, dy)
|
||
|
|
local timestamp = iui.backend.system.getTimestamp()
|
||
|
|
|
||
|
|
--- @type IUIMouseVelocityEntry
|
||
|
|
local entry = { dx = dx, dy = dy, timestamp = timestamp, dt = iui.dt }
|
||
|
|
|
||
|
|
table.insert(ctx.velocityBuffer, entry)
|
||
|
|
|
||
|
|
limitMouseVelocityEvents()
|
||
|
|
end
|
||
|
|
|
||
|
|
--- @return IUIMouseState
|
||
|
|
local function makeMouseState()
|
||
|
|
--- @type IUIMouseState
|
||
|
|
return {
|
||
|
|
x = -100,
|
||
|
|
y = -100,
|
||
|
|
dx = 0,
|
||
|
|
dy = 0,
|
||
|
|
scrollX = 0,
|
||
|
|
scrollY = 0,
|
||
|
|
down = iui.set.new(),
|
||
|
|
pressed = iui.set.new(),
|
||
|
|
released = iui.set.new()
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
local mouse = {
|
||
|
|
--- @param event IUIMouseEvent
|
||
|
|
--- @param button number
|
||
|
|
--- @param x number
|
||
|
|
--- @param y number
|
||
|
|
--- @param dx number
|
||
|
|
--- @param dy number
|
||
|
|
__call = function(_, event, button, x, y, dx, dy)
|
||
|
|
if ctx == nil then return end
|
||
|
|
local storage = ctx.storage
|
||
|
|
|
||
|
|
if event == "move" then
|
||
|
|
storage.x = x
|
||
|
|
storage.y = y
|
||
|
|
storage.dx = storage.dx + dx
|
||
|
|
storage.dy = storage.dy + dy
|
||
|
|
addMouseVelocityEvent(dx, dy)
|
||
|
|
elseif event == "down" then
|
||
|
|
storage.x = x
|
||
|
|
storage.y = y
|
||
|
|
storage.down:put(button)
|
||
|
|
storage.pressed:put(button)
|
||
|
|
elseif event == "up" then
|
||
|
|
storage.x = x
|
||
|
|
storage.y = y
|
||
|
|
storage.down:remove(button)
|
||
|
|
storage.released:put(button)
|
||
|
|
elseif event == "scroll" then
|
||
|
|
storage.scrollX = storage.scrollX + dx
|
||
|
|
storage.scrollY = storage.scrollY + dy
|
||
|
|
end
|
||
|
|
end,
|
||
|
|
}
|
||
|
|
setmetatable(mouse, mouse)
|
||
|
|
|
||
|
|
--- @return IUIMouseRootContext
|
||
|
|
function mouse.newRootContext()
|
||
|
|
--- @type IUIMouseRootContext
|
||
|
|
return {
|
||
|
|
velocityBuffer = {},
|
||
|
|
storage = makeMouseState(),
|
||
|
|
disabledStorage = makeMouseState()
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
--- @param rootContext IUIMouseRootContext
|
||
|
|
function mouse.setRootContext(rootContext)
|
||
|
|
ctx = rootContext
|
||
|
|
|
||
|
|
mouse.__index = ctx.storage
|
||
|
|
end
|
||
|
|
|
||
|
|
function mouse.endFrame()
|
||
|
|
local storage = ctx.storage
|
||
|
|
|
||
|
|
storage.dx = 0
|
||
|
|
storage.dy = 0
|
||
|
|
storage.scrollX = 0
|
||
|
|
storage.scrollY = 0
|
||
|
|
storage.pressed:removeAll()
|
||
|
|
storage.released:removeAll()
|
||
|
|
end
|
||
|
|
|
||
|
|
function mouse.resetVelocity()
|
||
|
|
ctx.velocityBuffer = {}
|
||
|
|
end
|
||
|
|
|
||
|
|
--- @return number vx, number vy
|
||
|
|
function mouse.getVelocity()
|
||
|
|
local vx, vy = 0, 0
|
||
|
|
|
||
|
|
local weightSum = 0
|
||
|
|
local now = iui.backend.system.getTimestamp()
|
||
|
|
|
||
|
|
for _, entry in ipairs(ctx.velocityBuffer) do
|
||
|
|
local weight = math.exp((entry.timestamp - now) * 20)
|
||
|
|
weightSum = weightSum + weight
|
||
|
|
vx = vx + (entry.dx / entry.dt) * weight
|
||
|
|
vy = vy + (entry.dy / entry.dt) * weight
|
||
|
|
end
|
||
|
|
|
||
|
|
if weightSum ~= 0 then
|
||
|
|
vx, vy = vx / weightSum, vy / weightSum
|
||
|
|
end
|
||
|
|
|
||
|
|
return -vx, -vy
|
||
|
|
end
|
||
|
|
|
||
|
|
--- @param active boolean
|
||
|
|
function mouse.setActive(active)
|
||
|
|
mouse.__index = active and ctx.storage or ctx.disabledStorage
|
||
|
|
end
|
||
|
|
|
||
|
|
return mouse --[[@as IUIMouse]]
|