DeviceListener: Rejig calculateGestureDelta algorithm

Get rid of the silly precomputed tables, and do More Maths(TM) instead!
Thanks to @zwim for the magic sauce ;).

Minor simplification of the API while I'm in there, and unify the warmth
computations, do everything in the native scale (much like what
effectively happens for intensity) to workaround the silly public API
being an unhelpful PITA, ensuring consistent & effective changes.
reviewable/pr11238/r1
zwim 6 months ago committed by NiLuJe
parent a2e0642998
commit c30c1ff11f

@ -55,68 +55,54 @@ if Device:hasFrontlight() then
local function calculateGestureDelta(ges, direction, min, max) local function calculateGestureDelta(ges, direction, min, max)
local delta_int local delta_int
if type(ges) == "table" then if type(ges) == "table" then
-- here we are using just two scales local gesture_multiplier
-- big scale is for high dynamic ranges (e.g. brightness from 1..100)
-- original scale maybe tuned by hand
-- small scale is for lower dynamic ranges (e.g. warmth from 1..10)
-- scale entries are calculated by math.round(1*sqrt(2)^n)
--- @fixme: An intermediary scale is probably necessary for Kindle, which goes from 0 to 24...
local steps_fl_big_scale = { 0.1, 0.1, 0.2, 0.4, 0.7, 1.1, 1.6, 2.2, 2.9, 3.7, 4.6, 5.6, 6.7, 7.9, 9.2, 10.6, }
local steps_fl_small_scale = { 1.0, 1.0, 2.0, 3.0, 4.0, 6.0, 8.1, 11.3 }
local steps_fl = steps_fl_big_scale
if (max - min) < 50 then
steps_fl = steps_fl_small_scale
end
local gestureScale
local scale_multiplier
if ges.ges == "two_finger_swipe" or ges.ges == "swipe" then if ges.ges == "two_finger_swipe" or ges.ges == "swipe" then
scale_multiplier = 0.8 gesture_multiplier = 0.8
else else
scale_multiplier = 1 gesture_multiplier = 1
end end
local gestureScale
if ges.direction == "south" or ges.direction == "north" then if ges.direction == "south" or ges.direction == "north" then
gestureScale = Screen:getHeight() * scale_multiplier gestureScale = Screen:getHeight() * gesture_multiplier
elseif ges.direction == "west" or ges.direction == "east" then elseif ges.direction == "west" or ges.direction == "east" then
gestureScale = Screen:getWidth() * scale_multiplier gestureScale = Screen:getWidth() * gesture_multiplier
else else
local width = Screen:getWidth() local width = Screen:getWidth()
local height = Screen:getHeight() local height = Screen:getHeight()
-- diagonal -- diagonal
gestureScale = math.sqrt(width * width + height * height) * scale_multiplier gestureScale = math.sqrt(width^2 + height^2) * gesture_multiplier
end
local steps_tbl = {}
local scale = (max - min) / steps_fl[#steps_fl] / 2 -- full swipe gives half scale
for i = 1, #steps_fl, 1 do
steps_tbl[i] = math.ceil(steps_fl[i] * scale)
end end
-- In case we're passed a gesture that doesn't imply movement (e.g., tap or hold)
if ges.distance == nil then if ges.distance == nil then
ges.distance = 1 ges.distance = 1
end end
local step = math.ceil(#steps_tbl * ges.distance / gestureScale) -- delta_int is calculated by a function f(x) = coeff * x^2
delta_int = steps_tbl[step] or steps_tbl[#steps_tbl] -- *) f(x) has the boundary condition: f(1) = max/2;
-- *) x is roughly the swipe distance as a fraction of the screen geometry,
-- clamped between 0 and 1
local x = math.min(1, ges.distance / gestureScale)
delta_int = math.ceil(1/2 * max * x^2)
else else
-- received amount to change -- The ges arg passed by our caller wasn't a gesture, but an absolute integer increment
delta_int = ges delta_int = ges
end end
if direction ~= -1 and direction ~= 1 then if direction ~= -1 and direction ~= 1 then
-- set default value (increase frontlight) -- If the caller didn't specify, opt to *increase* by default
direction = 1 direction = 1
end end
return direction, delta_int return direction * delta_int
end end
-- direction +1 - increase frontlight -- direction +1 - increase frontlight
-- direction -1 - decrease frontlight -- direction -1 - decrease frontlight
function DeviceListener:onChangeFlIntensity(ges, direction) function DeviceListener:onChangeFlIntensity(ges, direction)
local powerd = Device:getPowerDevice() local powerd = Device:getPowerDevice()
local delta_int local delta = calculateGestureDelta(ges, direction, powerd.fl_min, powerd.fl_max)
direction, delta_int = calculateGestureDelta(ges, direction, powerd.fl_min, powerd.fl_max)
local new_intensity = powerd:frontlightIntensity() + direction * delta_int local new_intensity = powerd:frontlightIntensity() + delta
-- when new_intensity <= 0, toggle light off -- when new_intensity <= 0, toggle light off
self:onSetFlIntensity(new_intensity) self:onSetFlIntensity(new_intensity)
self:onShowIntensity() self:onShowIntensity()
@ -149,17 +135,13 @@ if Device:hasFrontlight() then
if not Device:hasNaturalLight() then return true end if not Device:hasNaturalLight() then return true end
local powerd = Device:getPowerDevice() local powerd = Device:getPowerDevice()
local delta_int local delta = calculateGestureDelta(ges, direction, powerd.fl_warmth_min, powerd.fl_warmth_max)
direction, delta_int = calculateGestureDelta(ges, direction, powerd.fl_warmth_min, powerd.fl_warmth_max)
local warmth -- Given that the native warmth ranges are usually pretty restrictive (e.g., [0, 10] or [0, 24]),
if type(ges) == "table" then -- do the computations in the native scale, to ensure we always actually *change* something,
-- received a gesture, scale the gesture delta to the API range -- in case both the old and new value would round to the same native step,
warmth = powerd:frontlightWarmth() + powerd:fromNativeWarmth(direction * delta_int) -- despite being different in the API scale, which is stupidly fixed at [0, 100]...
else local warmth = powerd:fromNativeWarmth(powerd:toNativeWarmth(powerd:frontlightWarmth()) + delta)
-- received an absolute increment, use it as-is in the native scale
warmth = powerd:fromNativeWarmth(powerd:toNativeWarmth(powerd:frontlightWarmth()) + ges)
end
self:onSetFlWarmth(warmth) self:onSetFlWarmth(warmth)
self:onShowWarmth() self:onShowWarmth()

Loading…
Cancel
Save