2
0
mirror of https://github.com/koreader/koreader synced 2024-11-10 01:10:34 +00:00
koreader/frontend/apps/reader/modules/readerzooming.lua

369 lines
12 KiB
Lua
Raw Normal View History

2013-10-18 20:38:07 +00:00
local InputContainer = require("ui/widget/container/inputcontainer")
local ConfirmBox = require("ui/widget/confirmbox")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local Device = require("device")
local Input = require("device").input
local Screen = require("device").screen
2013-10-18 20:38:07 +00:00
local Geom = require("ui/geometry")
local Event = require("ui/event")
local logger = require("logger")
local T = require("ffi/util").template
2013-10-18 20:38:07 +00:00
local _ = require("gettext")
local ReaderZooming = InputContainer:new{
2014-03-13 13:52:43 +00:00
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()
2014-03-13 13:52:43 +00:00
if Device:hasKeyboard() then
self.key_events = {
ZoomIn = {
{ "Shift", Input.group.PgFwd },
doc = "zoom in",
2014-03-13 13:52:43 +00:00
event = "Zoom", args = "in"
},
ZoomOut = {
{ "Shift", Input.group.PgBack },
doc = "zoom out",
2014-03-13 13:52:43 +00:00
event = "Zoom", args = "out"
},
ZoomToFitPage = {
{ "A" },
doc = "zoom to fit page",
2014-03-13 13:52:43 +00:00
event = "SetZoomMode", args = "page"
},
ZoomToFitContent = {
{ "Shift", "A" },
doc = "zoom to fit content",
2014-03-13 13:52:43 +00:00
event = "SetZoomMode", args = "content"
},
ZoomToFitPageWidth = {
{ "S" },
doc = "zoom to fit page width",
2014-03-13 13:52:43 +00:00
event = "SetZoomMode", args = "pagewidth"
},
ZoomToFitContentWidth = {
{ "Shift", "S" },
doc = "zoom to fit content width",
2014-03-13 13:52:43 +00:00
event = "SetZoomMode", args = "contentwidth"
},
ZoomToFitPageHeight = {
{ "D" },
doc = "zoom to fit page height",
2014-03-13 13:52:43 +00:00
event = "SetZoomMode", args = "pageheight"
},
ZoomToFitContentHeight = {
{ "Shift", "D" },
doc = "zoom to fit content height",
2014-03-13 13:52:43 +00:00
event = "SetZoomMode", args = "contentheight"
},
ZoomToFitColumn = {
{ "Shift", "C" },
doc = "zoom to fit column",
event = "SetZoomMode", args = "colu"
},
2014-03-13 13:52:43 +00:00
}
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)
2014-03-13 13:52:43 +00:00
-- @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") or
G_reader_settings:readSetting("zoom_mode") or
self.DEFAULT_ZOOM_MODE
2014-03-13 13:52:43 +00:00
self:setZoomMode(zoom_mode)
end
2013-12-27 15:18:16 +00:00
function ReaderZooming:onSaveSettings()
self.ui.doc_settings:saveSetting("zoom_mode", self.orig_zoom_mode or self.zoom_mode)
end
function ReaderZooming:onSpread(arg, ges)
2014-03-13 13:52:43 +00:00
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)
2014-03-13 13:52:43 +00:00
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)
2014-03-13 13:52:43 +00:00
if self.zoom_mode ~= "free" then
self.orig_zoom = self.zoom
local xpos, ypos
self.zoom, xpos, ypos = self:getRegionalZoomCenter(self.current_page, ges.pos)
logger.info("zoom center", self.zoom, xpos, ypos)
2014-03-13 13:52:43 +00:00
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", "page"))
2014-03-13 13:52:43 +00:00
end
end
function ReaderZooming:onSetDimensions(dimensions)
2014-03-13 13:52:43 +00:00
-- we were resized
self.dimen = dimensions
self:setZoom()
end
function ReaderZooming:onRestoreDimensions(dimensions)
2014-03-13 13:52:43 +00:00
-- we were resized
self.dimen = dimensions
self:setZoom()
end
function ReaderZooming:onRotationUpdate(rotation)
2014-03-13 13:52:43 +00:00
self.rotation = rotation
self:setZoom()
end
function ReaderZooming:onZoom(direction)
logger.info("zoom", direction)
2014-03-13 13:52:43 +00:00
if direction == "in" then
self.zoom = self.zoom * 1.333333
elseif direction == "out" then
self.zoom = self.zoom * 0.75
end
logger.info("zoom is now at", self.zoom)
2014-03-13 13:52:43 +00:00
self:onSetZoomMode("free")
self.view:onZoomUpdate(self.zoom)
return true
end
function ReaderZooming:onSetZoomMode(new_mode)
2014-03-13 13:52:43 +00:00
self.view.zoom_mode = new_mode
if self.zoom_mode ~= new_mode then
logger.info("setting zoom mode to", new_mode)
2014-03-13 13:52:43 +00:00
self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode))
self.zoom_mode = new_mode
self:setZoom()
end
end
function ReaderZooming:onPageUpdate(new_page_no)
2014-03-13 13:52:43 +00:00
self.current_page = new_page_no
self:setZoom()
end
2013-04-14 07:16:42 +00:00
function ReaderZooming:onReZoom()
2014-03-13 13:52:43 +00:00
self:setZoom()
self.ui:handleEvent(Event:new("InitScrollPageStates"))
return true
2013-04-14 07:16:42 +00:00
end
function ReaderZooming:onEnterFlippingMode(zoom_mode)
self.orig_zoom_mode = self.zoom_mode
if zoom_mode == "free" then
self.ui:handleEvent(Event:new("SetZoomMode", "page"))
else
self.ui:handleEvent(Event:new("SetZoomMode", zoom_mode))
end
end
function ReaderZooming:onExitFlippingMode(zoom_mode)
self.orig_zoom_mode = nil
self.ui:handleEvent(Event:new("SetZoomMode", zoom_mode))
end
function ReaderZooming:getZoom(pageno)
2014-03-13 13:52:43 +00:00
-- check if we're in bbox mode and work on bbox if that's the case
local zoom = nil
local page_size = self.ui.document:getNativePageDimensions(pageno)
2014-03-13 13:52:43 +00:00
if self.zoom_mode == "content"
or self.zoom_mode == "contentwidth"
or self.zoom_mode == "contentheight"
or self.zoom_mode == "column" then
2014-03-13 13:52:43 +00:00
local ubbox_dimen = self.ui.document:getUsedBBoxDimensions(pageno, 1)
-- if bbox is larger than the native page dimension render the full page
-- See discussion in koreader/koreader#970.
if ubbox_dimen.w <= page_size.w and ubbox_dimen.h <= page_size.h then
page_size = ubbox_dimen
self.view:onBBoxUpdate(ubbox_dimen)
else
self.view:onBBoxUpdate(nil)
end
2014-03-13 13:52:43 +00:00
else
-- otherwise, operate on full page
self.view:onBBoxUpdate(nil)
end
-- calculate zoom value:
local zoom_w = self.dimen.w
local zoom_h = self.dimen.h
if self.ui.view.footer_visible then
zoom_h = zoom_h - self.ui.view.footer:getHeight()
end
if self.rotation % 180 == 0 then
-- No rotation or rotated by 180 degrees
zoom_w = zoom_w / page_size.w
zoom_h = zoom_h / page_size.h
else
2014-03-13 13:52:43 +00:00
-- rotated by 90 or 270 degrees
zoom_w = zoom_w / page_size.h
zoom_h = zoom_h / page_size.w
2014-03-13 13:52:43 +00:00
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 == "column" then
zoom = zoom_w * 2
2014-03-13 13:52:43 +00:00
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)
2014-03-13 13:52:43 +00:00
local p_pos = self.view:getSinglePagePosition(pos)
local page_size = self.ui.document:getNativePageDimensions(pageno)
local pos_x = p_pos.x / page_size.w
local pos_y = p_pos.y / page_size.h
local block = self.ui.document:getPageBlock(pageno, pos_x, pos_y)
2014-03-13 13:52:43 +00:00
local margin = self.ui.document.configurable.page_margin * Screen:getDPI()
if block then
local zoom = self.dimen.w / page_size.w / (block.x1 - block.x0)
zoom = zoom/(1 + 3*margin/zoom/page_size.w)
local xpos = (block.x0 + block.x1)/2 * zoom * page_size.w
local ypos = p_pos.y / p_pos.zoom * zoom
return zoom, xpos, ypos
2014-03-13 13:52:43 +00:00
end
local zoom = 2*self.dimen.w / page_size.w
return zoom/(1 + 3*margin/zoom/page_size.w)
end
function ReaderZooming:setZoom()
2014-03-13 13:52:43 +00:00
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)
2014-03-13 13:52:43 +00:00
return function()
self:setZoomMode(mode)
end
end
function ReaderZooming:setZoomMode(mode)
2014-03-13 13:52:43 +00:00
self.ui:handleEvent(Event:new("SetZoomMode", mode))
self.ui:handleEvent(Event:new("InitScrollPageStates"))
end
function ReaderZooming:addToMainMenu(menu_items)
2014-03-13 13:52:43 +00:00
if self.ui.document.info.has_pages then
local function getZoomModeMenuItem(text, mode, separator)
return {
text_func = function()
local default_zoom_mode = G_reader_settings:readSetting("zoom_mode") or self.DEFAULT_ZOOM_MODE
return text .. (mode == default_zoom_mode and "" or "")
end,
checked_func = function()
return self.zoom_mode == mode
end,
callback = self:genSetZoomModeCallBack(mode),
hold_callback = function(touchmenu_instance)
self:makeDefault(mode, touchmenu_instance)
end,
separator = separator,
}
end
menu_items.switch_zoom_mode = {
2014-03-13 13:52:43 +00:00
text = _("Switch zoom mode"),
enabled_func = function()
return self.ui.document.configurable.text_wrap ~= 1
end,
2014-03-13 13:52:43 +00:00
sub_item_table = {
getZoomModeMenuItem(_("Zoom to fit content width"), "contentwidth"),
getZoomModeMenuItem(_("Zoom to fit content height"), "contentheight", true),
getZoomModeMenuItem(_("Zoom to fit page width"), "pagewidth"),
getZoomModeMenuItem(_("Zoom to fit page height"), "pageheight", true),
getZoomModeMenuItem(_("Zoom to fit column"), "column"),
getZoomModeMenuItem(_("Zoom to fit content"), "content"),
getZoomModeMenuItem(_("Zoom to fit page"), "page"),
2014-03-13 13:52:43 +00:00
}
}
2014-03-13 13:52:43 +00:00
end
end
2013-10-18 20:38:07 +00:00
function ReaderZooming:makeDefault(zoom_mode, touchmenu_instance)
UIManager:show(ConfirmBox:new{
text = T(
_("Set default zoom mode to %1?"),
zoom_mode
),
ok_callback = function()
G_reader_settings:saveSetting("zoom_mode", zoom_mode)
if touchmenu_instance then touchmenu_instance:updateItems() end
end,
})
end
2013-10-18 20:38:07 +00:00
return ReaderZooming