mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
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.
This commit is contained in:
@@ -55,68 +55,54 @@ if Device:hasFrontlight() then
|
||||
local function calculateGestureDelta(ges, direction, min, max)
|
||||
local delta_int
|
||||
if type(ges) == "table" then
|
||||
-- here we are using just two scales
|
||||
-- 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
|
||||
local gesture_multiplier
|
||||
if ges.ges == "two_finger_swipe" or ges.ges == "swipe" then
|
||||
scale_multiplier = 0.8
|
||||
gesture_multiplier = 0.8
|
||||
else
|
||||
scale_multiplier = 1
|
||||
gesture_multiplier = 1
|
||||
end
|
||||
|
||||
local gestureScale
|
||||
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
|
||||
gestureScale = Screen:getWidth() * scale_multiplier
|
||||
gestureScale = Screen:getWidth() * gesture_multiplier
|
||||
else
|
||||
local width = Screen:getWidth()
|
||||
local height = Screen:getHeight()
|
||||
-- diagonal
|
||||
gestureScale = math.sqrt(width * width + height * height) * scale_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)
|
||||
gestureScale = math.sqrt(width^2 + height^2) * gesture_multiplier
|
||||
end
|
||||
|
||||
-- In case we're passed a gesture that doesn't imply movement (e.g., tap or hold)
|
||||
if ges.distance == nil then
|
||||
ges.distance = 1
|
||||
end
|
||||
|
||||
local step = math.ceil(#steps_tbl * ges.distance / gestureScale)
|
||||
delta_int = steps_tbl[step] or steps_tbl[#steps_tbl]
|
||||
-- delta_int is calculated by a function f(x) = coeff * x^2
|
||||
-- *) 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
|
||||
-- received amount to change
|
||||
-- The ges arg passed by our caller wasn't a gesture, but an absolute integer increment
|
||||
delta_int = ges
|
||||
end
|
||||
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
|
||||
end
|
||||
return direction, delta_int
|
||||
return direction * delta_int
|
||||
end
|
||||
|
||||
-- direction +1 - increase frontlight
|
||||
-- direction -1 - decrease frontlight
|
||||
function DeviceListener:onChangeFlIntensity(ges, direction)
|
||||
local powerd = Device:getPowerDevice()
|
||||
local delta_int
|
||||
direction, delta_int = calculateGestureDelta(ges, direction, powerd.fl_min, powerd.fl_max)
|
||||
local delta = 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
|
||||
self:onSetFlIntensity(new_intensity)
|
||||
self:onShowIntensity()
|
||||
@@ -149,17 +135,13 @@ if Device:hasFrontlight() then
|
||||
if not Device:hasNaturalLight() then return true end
|
||||
|
||||
local powerd = Device:getPowerDevice()
|
||||
local delta_int
|
||||
direction, delta_int = calculateGestureDelta(ges, direction, powerd.fl_warmth_min, powerd.fl_warmth_max)
|
||||
local delta = calculateGestureDelta(ges, direction, powerd.fl_warmth_min, powerd.fl_warmth_max)
|
||||
|
||||
local warmth
|
||||
if type(ges) == "table" then
|
||||
-- received a gesture, scale the gesture delta to the API range
|
||||
warmth = powerd:frontlightWarmth() + powerd:fromNativeWarmth(direction * delta_int)
|
||||
else
|
||||
-- received an absolute increment, use it as-is in the native scale
|
||||
warmth = powerd:fromNativeWarmth(powerd:toNativeWarmth(powerd:frontlightWarmth()) + ges)
|
||||
end
|
||||
-- Given that the native warmth ranges are usually pretty restrictive (e.g., [0, 10] or [0, 24]),
|
||||
-- do the computations in the native scale, to ensure we always actually *change* something,
|
||||
-- in case both the old and new value would round to the same native step,
|
||||
-- despite being different in the API scale, which is stupidly fixed at [0, 100]...
|
||||
local warmth = powerd:fromNativeWarmth(powerd:toNativeWarmth(powerd:frontlightWarmth()) + delta)
|
||||
|
||||
self:onSetFlWarmth(warmth)
|
||||
self:onShowWarmth()
|
||||
|
||||
Reference in New Issue
Block a user