mirror of
https://github.com/koreader/koreader
synced 2024-11-16 06:12:56 +00:00
850be52177
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
369 lines
12 KiB
Lua
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
|