Files
koreader-mirror/frontend/ui/widget/bboxwidget.lua
HW 2154e7e852 Further refactoring
This should finish the work to make all globals to local variables.
That allows LuaJIT to properly compile things by interning the
references to the relevant parts (rather than looking up globals
all the time which stops a trace).
2013-10-22 17:11:31 +02:00

221 lines
6.3 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("ui/device")
local GestureRange = require("ui/gesturerange")
--[[
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)
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