2
0
mirror of https://github.com/koreader/koreader synced 2024-11-18 03:25:46 +00:00
koreader/frontend/apps/reader/modules/readerzooming.lua
poire-z 850be52177
Keep some menus open when Tap or Hold (#4189)
TouchMenu: added options to menu items with the following defaults:
    keep_menu_open = false
    hold_keep_menu_open = true
So, default for Tap callback is to close menu, and for Hold callback
to keep menu open.
In both cases, provide the TouchMenu instance as the 1st argument to
the callback functions (instead of a refresh_menu_func I added in #3941)
so the callback can do more things, like closing, refreshing,
changing menu items text and re-ordering...

ReaderZooming: show symbol for default (like it was done for
ReaderFont, ReaderHyphenation...)
TextEditor plugin: update the previously opened files list in real
time, so the menu can be kept open and used as the TextEditor main
interface.
SSH plugin: keep menu open and update the Start/Stop state in real time
ReadTimer plugin: tried to do what feels right (but I don't use it)

Also remove forgotten cp in the move/paste file code
2018-09-04 23:55:58 +02:00

369 lines
12 KiB
Lua

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
local Geom = require("ui/geometry")
local Event = require("ui/event")
local logger = require("logger")
local T = require("ffi/util").template
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"
},
ZoomToFitColumn = {
{ "Shift", "C" },
doc = "zoom to fit column",
event = "SetZoomMode", args = "colu"
},
}
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") or
G_reader_settings:readSetting("zoom_mode") or
self.DEFAULT_ZOOM_MODE
self:setZoomMode(zoom_mode)
end
function ReaderZooming:onSaveSettings()
self.ui.doc_settings:saveSetting("zoom_mode", self.orig_zoom_mode or 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
local xpos, ypos
self.zoom, xpos, ypos = self:getRegionalZoomCenter(self.current_page, ges.pos)
logger.info("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", "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)
logger.info("zoom", direction)
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)
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
logger.info("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: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)
-- 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)
if self.zoom_mode == "content"
or self.zoom_mode == "contentwidth"
or self.zoom_mode == "contentheight"
or self.zoom_mode == "column" then
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
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
-- rotated by 90 or 270 degrees
zoom_w = zoom_w / page_size.h
zoom_h = zoom_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 == "column" then
zoom = zoom_w * 2
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
local pos_y = p_pos.y / page_size.h
local block = self.ui.document:getPageBlock(pageno, pos_x, pos_y)
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
end
local zoom = 2*self.dimen.w / page_size.w
return zoom/(1 + 3*margin/zoom/page_size.w)
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(menu_items)
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 = {
text = _("Switch zoom mode"),
enabled_func = function()
return self.ui.document.configurable.text_wrap ~= 1
end,
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"),
}
}
end
end
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
return ReaderZooming