Files
koreader/frontend/ui/reader/readerzooming.lua
chrox 8e4516b824 add regional zoom mode in pdf/djvu page
In regional zoom mode double tap will zoom to the tapped
region(paragraph or column, etc., detected optically via libk2pdfopt).
As the first demo, this feature is only turned on in flipping mode by
tapping the top-left corner of the screen. Eventually we may incorporate
this feature in "free" zoom mode.
2014-01-02 11:14:26 +08:00

324 lines
8.6 KiB
Lua

local InputContainer = require("ui/widget/container/inputcontainer")
local Device = require("ui/device")
local Input = require("ui/input")
local Screen = require("ui/screen")
local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
local Event = require("ui/event")
local DEBUG = require("dbg")
local _ = require("gettext")
local ReaderZooming = InputContainer:new{
zoom = 1.0,
-- default to nil so we can trigger ZoomModeUpdate events on start up
zoom_mode = nil,
DEFAULT_ZOOM_MODE = "page",
current_page = 1,
rotation = 0
}
function ReaderZooming:init()
if Device:hasKeyboard() then
self.key_events = {
ZoomIn = {
{ "Shift", Input.group.PgFwd },
doc = _("zoom in"),
event = "Zoom", args = "in"
},
ZoomOut = {
{ "Shift", Input.group.PgBack },
doc = _("zoom out"),
event = "Zoom", args = "out"
},
ZoomToFitPage = {
{ "A" },
doc = _("zoom to fit page"),
event = "SetZoomMode", args = "page"
},
ZoomToFitContent = {
{ "Shift", "A" },
doc = _("zoom to fit content"),
event = "SetZoomMode", args = "content"
},
ZoomToFitPageWidth = {
{ "S" },
doc = _("zoom to fit page width"),
event = "SetZoomMode", args = "pagewidth"
},
ZoomToFitContentWidth = {
{ "Shift", "S" },
doc = _("zoom to fit content width"),
event = "SetZoomMode", args = "contentwidth"
},
ZoomToFitPageHeight = {
{ "D" },
doc = _("zoom to fit page height"),
event = "SetZoomMode", args = "pageheight"
},
ZoomToFitContentHeight = {
{ "Shift", "D" },
doc = _("zoom to fit content height"),
event = "SetZoomMode", args = "contentheight"
},
}
end
if Device:isTouchDevice() then
self.ges_events = {
Spread = {
GestureRange:new{
ges = "spread",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
}
},
Pinch = {
GestureRange:new{
ges = "pinch",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
}
},
ToggleFreeZoom = {
GestureRange:new{
ges = "double_tap",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
}
},
}
end
self.ui.menu:registerToMainMenu(self)
end
function ReaderZooming:onReadSettings(config)
-- @TODO config file from old code base uses globalzoom_mode
-- instead of zoom_mode, we need to handle this imcompatibility
-- 04.12 2012 (houqp)
local zoom_mode = config:readSetting("zoom_mode")
if not zoom_mode then
zoom_mode = self.DEFAULT_ZOOM_MODE
end
self.ui:handleEvent(Event:new("SetZoomMode", zoom_mode))
end
function ReaderZooming:onSaveSettings()
self.ui.doc_settings:saveSetting("zoom_mode", self.zoom_mode)
end
function ReaderZooming:onSpread(arg, ges)
if ges.direction == "horizontal" then
self:genSetZoomModeCallBack("contentwidth")()
elseif ges.direction == "vertical" then
self:genSetZoomModeCallBack("contentheight")()
elseif ges.direction == "diagonal" then
self:genSetZoomModeCallBack("content")()
end
return true
end
function ReaderZooming:onPinch(arg, ges)
if ges.direction == "diagonal" then
self:genSetZoomModeCallBack("page")()
elseif ges.direction == "horizontal" then
self:genSetZoomModeCallBack("pagewidth")()
elseif ges.direction == "vertical" then
self:genSetZoomModeCallBack("pageheight")()
end
return true
end
function ReaderZooming:onToggleFreeZoom(arg, ges)
if self.zoom_mode ~= "free" then
self.orig_zoom = self.zoom
self.orig_zoom_mode = self.zoom_mode
local xpos, ypos
self.zoom, xpos, ypos = self:getRegionalZoomCenter(self.current_page, ges.pos)
DEBUG("zoom center", self.zoom, xpos, ypos)
self.ui:handleEvent(Event:new("SetZoomMode", "free"))
if xpos == nil or ypos == nil then
xpos = ges.pos.x * self.zoom / self.orig_zoom
ypos = ges.pos.y * self.zoom / self.orig_zoom
end
self.view:SetZoomCenter(xpos, ypos)
else
self.ui:handleEvent(Event:new("SetZoomMode", self.orig_zoom_mode or "page"))
end
end
function ReaderZooming:onSetDimensions(dimensions)
-- we were resized
self.dimen = dimensions
self:setZoom()
end
function ReaderZooming:onRestoreDimensions(dimensions)
-- we were resized
self.dimen = dimensions
self:setZoom()
end
function ReaderZooming:onRotationUpdate(rotation)
self.rotation = rotation
self:setZoom()
end
function ReaderZooming:onZoom(direction)
DEBUG("zoom", direction)
if direction == "in" then
self.zoom = self.zoom * 1.333333
elseif direction == "out" then
self.zoom = self.zoom * 0.75
end
DEBUG("zoom is now at", self.zoom)
self:onSetZoomMode("free")
self.view:onZoomUpdate(self.zoom)
return true
end
function ReaderZooming:onSetZoomMode(new_mode)
self.view.zoom_mode = new_mode
if self.zoom_mode ~= new_mode then
DEBUG("setting zoom mode to", new_mode)
self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode))
self.zoom_mode = new_mode
self:setZoom()
end
end
function ReaderZooming:onPageUpdate(new_page_no)
self.current_page = new_page_no
self:setZoom()
end
function ReaderZooming:onReZoom()
self:setZoom()
self.ui:handleEvent(Event:new("InitScrollPageStates"))
return true
end
function ReaderZooming:getZoom(pageno)
-- check if we're in bbox mode and work on bbox if that's the case
local zoom = nil
local page_size = {}
if self.zoom_mode == "content"
or self.zoom_mode == "contentwidth"
or self.zoom_mode == "contentheight" then
local ubbox_dimen = self.ui.document:getUsedBBoxDimensions(pageno, 1)
--self.view:handleEvent(Event:new("BBoxUpdate", page_size))
self.view:onBBoxUpdate(ubbox_dimen)
page_size = ubbox_dimen
else
-- otherwise, operate on full page
self.view:onBBoxUpdate(nil)
page_size = self.ui.document:getNativePageDimensions(pageno)
--page_size = self.ui.document:getPageDimensions(pageno, 1, 0)
end
-- calculate zoom value:
local zoom_w = self.dimen.w / page_size.w
local zoom_h = self.dimen.h / page_size.h
if self.rotation % 180 ~= 0 then
-- rotated by 90 or 270 degrees
zoom_w = self.dimen.w / page_size.h
zoom_h = self.dimen.h / page_size.w
end
if self.zoom_mode == "content" or self.zoom_mode == "page" then
if zoom_w < zoom_h then
zoom = zoom_w
else
zoom = zoom_h
end
elseif self.zoom_mode == "contentwidth" or self.zoom_mode == "pagewidth" then
zoom = zoom_w
elseif self.zoom_mode == "contentheight" or self.zoom_mode == "pageheight" then
zoom = zoom_h
elseif self.zoom_mode == "free" then
zoom = self.zoom
end
return zoom
end
function ReaderZooming:getRegionalZoomCenter(pageno, pos)
local p_pos = self.view:getSinglePagePosition(pos)
local page_size = self.ui.document:getNativePageDimensions(pageno)
local pos_x = p_pos.x / page_size.w / p_pos.zoom
local pos_y = p_pos.y / page_size.h / p_pos.zoom
local regions = self.ui.document:getPageRegions(pageno)
DEBUG("get page regions", regions)
local margin = self.ui.document.configurable.page_margin * Screen:getDPI()
for i = 1, #regions do
if regions[i].x0 <= pos_x and pos_x <= regions[i].x1
and regions[i].y0 <= pos_y and pos_y <= regions[i].y1 then
local zoom = 1/(regions[i].x1 - regions[i].x0)
zoom = zoom/(1 + 3*margin/zoom/page_size.w)
local xpos = (regions[i].x0 + regions[i].x1)/2 * zoom * page_size.w
local ypos = p_pos.y / p_pos.zoom * zoom
return zoom, xpos, ypos
end
end
return 2
end
function ReaderZooming:setZoom()
if not self.dimen then
self.dimen = self.ui.dimen
end
self.zoom = self:getZoom(self.current_page)
self.ui:handleEvent(Event:new("ZoomUpdate", self.zoom))
end
function ReaderZooming:genSetZoomModeCallBack(mode)
return function()
self:setZoomMode(mode)
end
end
function ReaderZooming:setZoomMode(mode)
self.ui:handleEvent(Event:new("SetZoomMode", mode))
self.ui:handleEvent(Event:new("InitScrollPageStates"))
end
function ReaderZooming:addToMainMenu(tab_item_table)
if self.ui.document.info.has_pages then
table.insert(tab_item_table.typeset, {
text = _("Switch zoom mode"),
sub_item_table = {
{
text = _("Zoom to fit content width"),
callback = self:genSetZoomModeCallBack("contentwidth")
},
{
text = _("Zoom to fit content height"),
callback = self:genSetZoomModeCallBack("contentheight")
},
{
text = _("Zoom to fit page width"),
callback = self:genSetZoomModeCallBack("pagewidth")
},
{
text = _("Zoom to fit page height"),
callback = self:genSetZoomModeCallBack("pageheight")
},
{
text = _("Zoom to fit content"),
callback = self:genSetZoomModeCallBack("content")
},
{
text = _("Zoom to fit page"),
callback = self:genSetZoomModeCallBack("page")
},
}
})
end
end
return ReaderZooming