2
0
mirror of https://github.com/koreader/koreader synced 2024-10-31 21:20:20 +00:00
koreader/frontend/ui/widget/bboxwidget.lua
Hans-Werner Hilse 3066c86e38 Refactoring hardware abstraction
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.
2014-11-02 21:19:04 +01:00

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