2
0
mirror of https://github.com/koreader/koreader synced 2024-11-11 19:11:14 +00:00
koreader/frontend/ui/widget/bboxwidget.lua

226 lines
7.5 KiB
Lua
Raw Normal View History

2017-04-29 14:30:16 +00:00
--[[--
BBoxWidget shows a bbox for page cropping.
]]
2013-10-18 20:38:07 +00:00
local InputContainer = require("ui/widget/container/inputcontainer")
local Device = require("device")
2017-04-29 14:30:16 +00:00
local Event = require("ui/event")
local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
2013-10-23 14:37:55 +00:00
local Math = require("optmath")
2017-09-13 14:56:20 +00:00
local Size = require("ui/size")
2017-04-29 14:30:16 +00:00
local UIManager = require("ui/uimanager")
2013-10-18 20:38:07 +00:00
local BBoxWidget = InputContainer:new{
2014-03-13 13:52:43 +00:00
page_bbox = nil,
screen_bbox = nil,
2017-09-13 14:56:20 +00:00
linesize = Size.line.thick,
2014-03-13 13:52:43 +00:00
fine_factor = 10,
dimen = Geom:new(),
}
function BBoxWidget:init()
2014-03-13 13:52:43 +00:00
self.page_bbox = self.document:getPageBBox(self.view.state.page)
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()
2014-03-13 13:52:43 +00:00
return self.view.dimen
end
function BBoxWidget:paintTo(bb, x, y)
self.dimen = self.view.dimen:copy()
self.dimen.x, self.dimen.y = x, y
2014-03-13 13:52:43 +00:00
-- 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
2013-02-21 10:08:36 +00:00
function BBoxWidget:getScreenBBox(page_bbox)
2014-03-13 13:52:43 +00:00
local bbox = {}
local scale = self.view.state.zoom
local screen_offset = self.view.state.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
2013-02-21 10:08:36 +00:00
function BBoxWidget:getPageBBox(screen_bbox)
2014-03-13 13:52:43 +00:00
local bbox = {}
local scale = self.view.state.zoom
local screen_offset = self.view.state.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
2013-02-21 10:08:36 +00:00
function BBoxWidget:inPageArea(ges)
2014-03-13 13:52:43 +00:00
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)
2013-02-21 10:08:36 +00:00
end
function BBoxWidget:adjustScreenBBox(ges, relative)
2014-03-13 13:52:43 +00:00
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)
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)
}
2013-04-08 07:29:23 +00:00
UIManager:setDirty("all")
2013-02-20 14:50:57 +00:00
end
2013-02-21 10:08:36 +00:00
function BBoxWidget:getModifiedPageBBox()
2014-03-13 13:52:43 +00:00
return self:getPageBBox(self.screen_bbox)
2013-02-21 10:08:36 +00:00
end
2013-02-20 14:50:57 +00:00
function BBoxWidget:onTapAdjust(arg, ges)
2014-03-13 13:52:43 +00:00
self:adjustScreenBBox(ges)
return true
2013-02-20 14:50:57 +00:00
end
function BBoxWidget:onSwipeAdjust(arg, ges)
2014-03-13 13:52:43 +00:00
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
2014-10-15 10:17:16 +00:00
-- since Kobo devices may append hold gestures to each swipe gesture rendering
-- relative replacement impossible. See koreader/koreader#987 at Github.
--self:adjustScreenBBox(ges)
2014-03-13 13:52:43 +00:00
return true
end
function BBoxWidget:onConfirmAdjust(arg, ges)
2014-03-13 13:52:43 +00:00
if self:inPageArea(ges) then
self.ui:handleEvent(Event:new("ConfirmPageCrop"))
end
return true
end
2013-10-18 20:38:07 +00:00
return BBoxWidget