mirror of
https://github.com/koreader/koreader
synced 2024-10-31 21:20:20 +00:00
3066c86e38
This is a major overhaul of the hardware abstraction layer. A few notes: General platform distinction happens in frontend/device.lua which will delegate everything else to frontend/device/<platform_name>/device.lua which should extend frontend/device/generic/device.lua Screen handling is implemented in frontend/device/screen.lua which includes the *functionality* to support device specifics. Actually setting up the device specific functionality, however, is done in the device specific setup code in the relevant device.lua file. The same goes for input handling.
226 lines
7.6 KiB
Lua
226 lines
7.6 KiB
Lua
local InputContainer = require("ui/widget/container/inputcontainer")
|
|
local Geom = require("ui/geometry")
|
|
local Event = require("ui/event")
|
|
local UIManager = require("ui/uimanager")
|
|
local Device = require("device")
|
|
local GestureRange = require("ui/gesturerange")
|
|
local Math = require("optmath")
|
|
local DEBUG = require("dbg")
|
|
|
|
--[[
|
|
BBoxWidget shows a bbox for page cropping
|
|
]]
|
|
local BBoxWidget = InputContainer:new{
|
|
page_bbox = nil,
|
|
screen_bbox = nil,
|
|
linesize = 2,
|
|
fine_factor = 10,
|
|
}
|
|
|
|
function BBoxWidget:init()
|
|
self.page_bbox = self.document:getPageBBox(self.view.state.page)
|
|
--DEBUG("used page bbox on page", self.view.state.page, self.page_bbox)
|
|
if Device:isTouchDevice() then
|
|
self.ges_events = {
|
|
TapAdjust = {
|
|
GestureRange:new{
|
|
ges = "tap",
|
|
range = self.view.dimen,
|
|
}
|
|
},
|
|
SwipeAdjust = {
|
|
GestureRange:new{
|
|
ges = "swipe",
|
|
range = self.view.dimen,
|
|
}
|
|
},
|
|
HoldAdjust = {
|
|
GestureRange:new{
|
|
ges = "hold",
|
|
range = self.view.dimen,
|
|
}
|
|
},
|
|
ConfirmAdjust = {
|
|
GestureRange:new{
|
|
ges = "double_tap",
|
|
range = self.view.dimen,
|
|
}
|
|
}
|
|
}
|
|
end
|
|
end
|
|
|
|
function BBoxWidget:getSize()
|
|
return self.view.dimen
|
|
end
|
|
|
|
function BBoxWidget:paintTo(bb, x, y)
|
|
-- As getScreenBBox uses view states, screen_bbox initialization is postponed.
|
|
self.screen_bbox = self.screen_bbox or self:getScreenBBox(self.page_bbox)
|
|
local bbox = self.screen_bbox
|
|
-- top edge
|
|
bb:invertRect(bbox.x0 + self.linesize, bbox.y0, bbox.x1 - bbox.x0, self.linesize)
|
|
-- bottom edge
|
|
bb:invertRect(bbox.x0 + self.linesize, bbox.y1, bbox.x1 - bbox.x0 - self.linesize, self.linesize)
|
|
-- left edge
|
|
bb:invertRect(bbox.x0, bbox.y0, self.linesize, bbox.y1 - bbox.y0 + self.linesize)
|
|
-- right edge
|
|
bb:invertRect(bbox.x1, bbox.y0 + self.linesize, self.linesize, bbox.y1 - bbox.y0)
|
|
end
|
|
|
|
-- transform page bbox to screen bbox
|
|
function BBoxWidget:getScreenBBox(page_bbox)
|
|
local bbox = {}
|
|
local scale = self.view.state.zoom
|
|
local screen_offset = self.view.state.offset
|
|
--DEBUG("screen offset in page_to_screen", screen_offset)
|
|
bbox.x0 = Math.round(page_bbox.x0 * scale + screen_offset.x)
|
|
bbox.y0 = Math.round(page_bbox.y0 * scale + screen_offset.y)
|
|
bbox.x1 = Math.round(page_bbox.x1 * scale + screen_offset.x)
|
|
bbox.y1 = Math.round(page_bbox.y1 * scale + screen_offset.y)
|
|
return bbox
|
|
end
|
|
|
|
-- transform screen bbox to page bbox
|
|
function BBoxWidget:getPageBBox(screen_bbox)
|
|
local bbox = {}
|
|
local scale = self.view.state.zoom
|
|
local screen_offset = self.view.state.offset
|
|
--DEBUG("screen offset in screen_to_page", screen_offset)
|
|
bbox.x0 = Math.round((screen_bbox.x0 - screen_offset.x) / scale)
|
|
bbox.y0 = Math.round((screen_bbox.y0 - screen_offset.y) / scale)
|
|
bbox.x1 = Math.round((screen_bbox.x1 - screen_offset.x) / scale)
|
|
bbox.y1 = Math.round((screen_bbox.y1 - screen_offset.y) / scale)
|
|
return bbox
|
|
end
|
|
|
|
function BBoxWidget:inPageArea(ges)
|
|
local offset = self.view.state.offset
|
|
local page_area = self.view.page_area
|
|
local page_dimen = Geom:new{ x = offset.x, y = offset.y, h = page_area.h, w = page_area.w}
|
|
return not ges.pos:notIntersectWith(page_dimen)
|
|
end
|
|
|
|
function BBoxWidget:adjustScreenBBox(ges, relative)
|
|
--DEBUG("adjusting crop bbox with pos", ges.pos)
|
|
if not self:inPageArea(ges) then return end
|
|
local bbox = self.screen_bbox
|
|
local upper_left = Geom:new{ x = bbox.x0, y = bbox.y0}
|
|
local upper_right = Geom:new{ x = bbox.x1, y = bbox.y0}
|
|
local bottom_left = Geom:new{ x = bbox.x0, y = bbox.y1}
|
|
local bottom_right = Geom:new{ x = bbox.x1, y = bbox.y1}
|
|
local upper_center = Geom:new{ x = (bbox.x0 + bbox.x1) / 2, y = bbox.y0}
|
|
local bottom_center = Geom:new{ x = (bbox.x0 + bbox.x1) / 2, y = bbox.y1}
|
|
local right_center = Geom:new{ x = bbox.x1, y = (bbox.y0 + bbox.y1) / 2}
|
|
local left_center = Geom:new{ x = bbox.x0, y = (bbox.y0 + bbox.y1) / 2}
|
|
local anchors = {
|
|
upper_left, upper_center, upper_right,
|
|
left_center, right_center,
|
|
bottom_left, bottom_center, bottom_right,
|
|
}
|
|
local _, nearest = Math.tmin(anchors, function(a,b)
|
|
return a:distance(ges.pos) > b:distance(ges.pos)
|
|
end)
|
|
--DEBUG("nearest anchor", nearest)
|
|
if nearest == upper_left then
|
|
upper_left.x = ges.pos.x
|
|
upper_left.y = ges.pos.y
|
|
elseif nearest == bottom_right then
|
|
bottom_right.x = ges.pos.x
|
|
bottom_right.y = ges.pos.y
|
|
elseif nearest == upper_right then
|
|
bottom_right.x = ges.pos.x
|
|
upper_left.y = ges.pos.y
|
|
elseif nearest == bottom_left then
|
|
upper_left.x = ges.pos.x
|
|
bottom_right.y = ges.pos.y
|
|
elseif nearest == upper_center then
|
|
if relative then
|
|
local delta = 0
|
|
if ges.direction == "north" then
|
|
delta = -ges.distance / self.fine_factor
|
|
elseif ges.direction == "south" then
|
|
delta = ges.distance / self.fine_factor
|
|
end
|
|
upper_left.y = upper_left.y + delta
|
|
else
|
|
upper_left.y = ges.pos.y
|
|
end
|
|
elseif nearest == right_center then
|
|
if relative then
|
|
local delta = 0
|
|
if ges.direction == "west" then
|
|
delta = -ges.distance / self.fine_factor
|
|
elseif ges.direction == "east" then
|
|
delta = ges.distance / self.fine_factor
|
|
end
|
|
bottom_right.x = bottom_right.x + delta
|
|
else
|
|
bottom_right.x = ges.pos.x
|
|
end
|
|
elseif nearest == bottom_center then
|
|
if relative then
|
|
local delta = 0
|
|
if ges.direction == "north" then
|
|
delta = -ges.distance / self.fine_factor
|
|
elseif ges.direction == "south" then
|
|
delta = ges.distance / self.fine_factor
|
|
end
|
|
bottom_right.y = bottom_right.y + delta
|
|
else
|
|
bottom_right.y = ges.pos.y
|
|
end
|
|
elseif nearest == left_center then
|
|
if relative then
|
|
local delta = 0
|
|
if ges.direction == "west" then
|
|
delta = -ges.distance / self.fine_factor
|
|
elseif ges.direction == "east" then
|
|
delta = ges.distance / self.fine_factor
|
|
end
|
|
upper_left.x = upper_left.x + delta
|
|
else
|
|
upper_left.x = ges.pos.x
|
|
end
|
|
end
|
|
self.screen_bbox = {
|
|
x0 = Math.round(upper_left.x),
|
|
y0 = Math.round(upper_left.y),
|
|
x1 = Math.round(bottom_right.x),
|
|
y1 = Math.round(bottom_right.y)
|
|
}
|
|
|
|
UIManager.repaint_all = true
|
|
end
|
|
|
|
function BBoxWidget:getModifiedPageBBox()
|
|
return self:getPageBBox(self.screen_bbox)
|
|
end
|
|
|
|
function BBoxWidget:onTapAdjust(arg, ges)
|
|
self:adjustScreenBBox(ges)
|
|
return true
|
|
end
|
|
|
|
function BBoxWidget:onSwipeAdjust(arg, ges)
|
|
self:adjustScreenBBox(ges, true)
|
|
return true
|
|
end
|
|
|
|
function BBoxWidget:onHoldAdjust(arg, ges)
|
|
-- FIXME: this is a dirty hack to disable hold gesture in page cropping
|
|
-- since Kobo devices may append hold gestures to each swipe gesture rendering
|
|
-- relative replacement impossible. See koreader/koreader#987 at Github.
|
|
--self:adjustScreenBBox(ges)
|
|
return true
|
|
end
|
|
|
|
function BBoxWidget:onConfirmAdjust(arg, ges)
|
|
if self:inPageArea(ges) then
|
|
self.ui:handleEvent(Event:new("ConfirmPageCrop"))
|
|
end
|
|
return true
|
|
end
|
|
|
|
return BBoxWidget
|