mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Paged documents: rework zoom options (#6885)
- Move zoom options from top menu to bottom config - Add option to manually define zoom (relative to page width) and overlap (in percent) - Add options to zoom to columns or rows, possibly with overlap. Add panning direction options when page forward in these modes
This commit is contained in:
@@ -25,9 +25,6 @@ function ReaderCropping:onPageCrop(mode)
|
||||
end
|
||||
return
|
||||
elseif mode == "none" then
|
||||
if self.document.configurable.text_wrap ~= 1 then
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "pagewidth", "cropping"))
|
||||
end
|
||||
return
|
||||
end
|
||||
-- backup original view dimen
|
||||
@@ -51,7 +48,7 @@ function ReaderCropping:onPageCrop(mode)
|
||||
-- mode, just force readerview to recalculate visible_area
|
||||
self.view:recalculate()
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "page", "cropping"))
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "page"))
|
||||
end
|
||||
|
||||
-- prepare bottom buttons so we know the size available for the page above it
|
||||
@@ -152,11 +149,11 @@ end
|
||||
|
||||
function ReaderCropping:setCropZoomMode(confirmed)
|
||||
if confirmed then
|
||||
-- if original zoom mode is not "content", set zoom mode to "contentwidth"
|
||||
self:setZoomMode(
|
||||
self.orig_zoom_mode:find("content")
|
||||
and self.orig_zoom_mode
|
||||
or "contentwidth")
|
||||
-- if original zoom mode is "page???", set zoom mode to "content???"
|
||||
local zoom_mode_type = self.orig_zoom_mode:match("page(.*)")
|
||||
self:setZoomMode(zoom_mode_type
|
||||
and "content"..zoom_mode_type
|
||||
or self.orig_zoom_mode)
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
else
|
||||
self:setZoomMode(self.orig_zoom_mode)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
local EventListener = require("ui/widget/eventlistener")
|
||||
local Event = require("ui/event")
|
||||
local ReaderZooming = require("apps/reader/modules/readerzooming")
|
||||
local util = require("util")
|
||||
|
||||
local ReaderKoptListener = EventListener:new{}
|
||||
|
||||
@@ -14,9 +16,13 @@ end
|
||||
|
||||
function ReaderKoptListener:onReadSettings(config)
|
||||
-- normal zoom mode is zoom mode used in non-reflow mode.
|
||||
self.normal_zoom_mode = config:readSetting("normal_zoom_mode") or
|
||||
local normal_zoom_mode = config:readSetting("normal_zoom_mode") or
|
||||
G_reader_settings:readSetting("zoom_mode") or "page"
|
||||
self:setZoomMode(self.normal_zoom_mode)
|
||||
normal_zoom_mode = util.arrayContains(ReaderZooming.available_zoom_modes, normal_zoom_mode)
|
||||
and normal_zoom_mode
|
||||
or "page"
|
||||
self.normal_zoom_mode = normal_zoom_mode
|
||||
self:setZoomMode(normal_zoom_mode)
|
||||
self.document.configurable.contrast = config:readSetting("kopt_contrast") or
|
||||
G_reader_settings:readSetting("kopt_contrast") or 1.0
|
||||
self.ui:handleEvent(Event:new("GammaUpdate", 1/self.document.configurable.contrast))
|
||||
|
||||
@@ -6,6 +6,7 @@ local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local Math = require("optmath")
|
||||
local MultiConfirmBox = require("ui/widget/multiconfirmbox")
|
||||
local Notification = require("ui/widget/notification")
|
||||
local ReaderZooming = require("apps/reader/modules/readerzooming")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local bit = require("bit")
|
||||
local logger = require("logger")
|
||||
@@ -193,6 +194,9 @@ function ReaderPaging:onReadSettings(config)
|
||||
if self.inverse_reading_order == nil then
|
||||
self.inverse_reading_order = G_reader_settings:isTrue("inverse_reading_order")
|
||||
end
|
||||
for _, v in ipairs(ReaderZooming.zoom_pan_settings) do
|
||||
self[v] = config:readSetting(v) or G_reader_settings:readSetting(v) or ReaderZooming[v]
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderPaging:onSaveSettings()
|
||||
@@ -840,134 +844,115 @@ function ReaderPaging:onGotoPageRel(diff)
|
||||
logger.dbg("goto relative page:", diff)
|
||||
local new_va = self.visible_area:copy()
|
||||
local x_pan_off, y_pan_off = 0, 0
|
||||
local right_to_left = (self.ui.document.configurable.writing_direction > 0)
|
||||
local bottom_to_top = self.ui.zooming.zoom_bottom_to_top
|
||||
local h_progress = 1 - self.ui.zooming.zoom_overlap_h / 100
|
||||
local v_progress = 1 - self.ui.zooming.zoom_overlap_v / 100
|
||||
local old_va = self.visible_area
|
||||
local old_page = self.current_page
|
||||
local x, y, w, h = "x", "y", "w", "h"
|
||||
local x_diff = diff
|
||||
local y_diff = diff
|
||||
|
||||
if self.zoom_mode:find("width") then
|
||||
y_pan_off = self.visible_area.h * diff
|
||||
elseif self.zoom_mode:find("height") then
|
||||
-- negative x panning if writing direction is right to left
|
||||
local direction = self.ui.document.configurable.writing_direction
|
||||
x_pan_off = self.visible_area.w * diff * (direction == 1 and -1 or 1)
|
||||
elseif self.zoom_mode:find("column") then
|
||||
-- zoom mode for two-column navigation
|
||||
|
||||
y_pan_off = self.visible_area.h * diff
|
||||
y_pan_off = Math.roundAwayFromZero(y_pan_off)
|
||||
new_va.x = Math.roundAwayFromZero(self.visible_area.x)
|
||||
new_va.y = Math.roundAwayFromZero(self.visible_area.y+y_pan_off)
|
||||
-- intra-column navigation (vertical), this is the default behavior
|
||||
-- if we do not reach the end of a column
|
||||
|
||||
if new_va:notIntersectWith(self.page_area) then
|
||||
-- if we leave the page, we must either switch to the other column
|
||||
-- or switch to another page (we are crossing the end of a column)
|
||||
|
||||
x_pan_off = self.visible_area.w * diff
|
||||
x_pan_off = Math.roundAwayFromZero(x_pan_off)
|
||||
new_va.x = Math.roundAwayFromZero(self.visible_area.x+x_pan_off)
|
||||
new_va.y = Math.roundAwayFromZero(self.visible_area.y)
|
||||
-- inter-column displacement (horizontal)
|
||||
|
||||
if new_va:notIntersectWith(self.page_area) then
|
||||
-- if we leave the page with horizontal displacement, then we are
|
||||
-- already in the border column, we must turn the page
|
||||
|
||||
local new_page = self.current_page + diff
|
||||
if diff > 0 and new_page == self.number_of_pages + 1 then
|
||||
self.ui:handleEvent(Event:new("EndOfBook"))
|
||||
else
|
||||
self:_gotoPage(new_page)
|
||||
end
|
||||
|
||||
if y_pan_off < 0 then
|
||||
-- if we are going back to previous page, reset view area
|
||||
-- to bottom right of previous page, end of second column
|
||||
self.view:PanningUpdate(self.page_area.w, self.page_area.h)
|
||||
end
|
||||
|
||||
else
|
||||
-- if we do not leave the page with horizontal displacement,
|
||||
-- it means that we can stay on this page and switch column
|
||||
|
||||
if diff > 0 then
|
||||
-- end of first column, set view area to the top right of
|
||||
-- current page, beginning of second column
|
||||
self.view:PanningUpdate(self.page_area.w, -self.page_area.h)
|
||||
else
|
||||
-- move backwards to the first column, set the view area to the
|
||||
-- bottom left of the current page
|
||||
self.view:PanningUpdate(-self.page_area.w, self.page_area.h)
|
||||
end
|
||||
end
|
||||
|
||||
-- if we are here, the panning has already been updated so return
|
||||
return true
|
||||
-- Adjust directions according to settings
|
||||
if self.ui.zooming.zoom_direction_vertical then -- invert axes
|
||||
y, x, h, w = x, y, w, h
|
||||
h_progress, v_progress = v_progress, h_progress
|
||||
if right_to_left then
|
||||
x_diff, y_diff = -x_diff, -y_diff
|
||||
end
|
||||
if bottom_to_top then
|
||||
x_diff = -x_diff
|
||||
end
|
||||
elseif bottom_to_top then
|
||||
y_diff = -y_diff
|
||||
end
|
||||
if right_to_left then
|
||||
x_diff = -x_diff
|
||||
end
|
||||
|
||||
elseif self.zoom_mode ~= "free" then -- do nothing in "free" zoom mode
|
||||
-- must be fit content or page zoom mode
|
||||
if self.visible_area.w == self.page_area.w then
|
||||
y_pan_off = self.visible_area.h * diff
|
||||
if self.zoom_mode ~= "free" then
|
||||
x_pan_off = Math.roundAwayFromZero(self.visible_area[w] * h_progress * x_diff)
|
||||
y_pan_off = Math.roundAwayFromZero(self.visible_area[h] * v_progress * y_diff)
|
||||
end
|
||||
|
||||
-- Auxiliary functions to (as much as possible) keep things clear
|
||||
-- If going backwards (diff < 0) "end" is equivalent to "beginning", "next" to "previous";
|
||||
-- in column mode, "line" is equivalent to "column".
|
||||
local function at_end(axis)
|
||||
-- returns true if we're at the end of line (axis = x) or page (axis = y)
|
||||
local len, _diff
|
||||
if axis == x then
|
||||
len, _diff = w, x_diff
|
||||
else
|
||||
x_pan_off = self.visible_area.w * diff
|
||||
len, _diff = h, y_diff
|
||||
end
|
||||
return old_va[axis] + old_va[len] + _diff > self.page_area[axis] + self.page_area[len]
|
||||
or old_va[axis] + _diff < self.page_area[axis]
|
||||
end
|
||||
local function goto_end(axis, _diff)
|
||||
-- updates view area to the end of line (axis = x) or page (axis = y)
|
||||
local len = axis == x and w or h
|
||||
_diff = _diff or (axis == x and x_diff or y_diff)
|
||||
new_va[axis] = _diff > 0
|
||||
and old_va[axis] + self.page_area[len] - old_va[len]
|
||||
or self.page_area[axis]
|
||||
end
|
||||
local function goto_next_line()
|
||||
new_va[y] = old_va[y] + y_pan_off
|
||||
goto_end(x, -x_diff)
|
||||
end
|
||||
local function goto_next_page()
|
||||
local new_page = self.current_page + diff
|
||||
if new_page > self.number_of_pages then
|
||||
self.ui:handleEvent(Event:new("EndOfBook"))
|
||||
goto_end(y)
|
||||
goto_end(x)
|
||||
elseif new_page > 0 then
|
||||
self:_gotoPage(new_page)
|
||||
goto_end(y, -y_diff)
|
||||
else
|
||||
goto_end(x)
|
||||
end
|
||||
end
|
||||
-- adjust offset to help with page turn decision
|
||||
-- we dont take overlap into account here yet, otherwise new_va will
|
||||
-- always intersect with page_area
|
||||
x_pan_off = Math.roundAwayFromZero(x_pan_off)
|
||||
y_pan_off = Math.roundAwayFromZero(y_pan_off)
|
||||
new_va.x = Math.roundAwayFromZero(self.visible_area.x+x_pan_off)
|
||||
new_va.y = Math.roundAwayFromZero(self.visible_area.y+y_pan_off)
|
||||
|
||||
if new_va:notIntersectWith(self.page_area) then
|
||||
-- view area out of page area, do a page turn
|
||||
local new_page = self.current_page + diff
|
||||
if diff > 0 and new_page == self.number_of_pages + 1 then
|
||||
self.ui:handleEvent(Event:new("EndOfBook"))
|
||||
-- Move the view area towerds line end
|
||||
new_va[x] = old_va[x] + x_pan_off
|
||||
new_va[y] = old_va[y]
|
||||
|
||||
-- Handle cases when the view area gets out of page boundaries
|
||||
if not self.page_area:contains(new_va) then
|
||||
if not at_end(x) then
|
||||
goto_end(x)
|
||||
else
|
||||
self:_gotoPage(new_page)
|
||||
goto_next_line()
|
||||
if not self.page_area:contains(new_va) then
|
||||
if not at_end(y) then
|
||||
goto_end(y)
|
||||
else
|
||||
goto_next_page()
|
||||
end
|
||||
end
|
||||
end
|
||||
-- if we are going back to previous page, reset
|
||||
-- view area to bottom of previous page
|
||||
if x_pan_off < 0 then
|
||||
self.view:PanningUpdate(self.page_area.w, 0)
|
||||
elseif y_pan_off < 0 then
|
||||
self.view:PanningUpdate(0, self.page_area.h)
|
||||
end
|
||||
else
|
||||
-- not end of page yet, goto next view
|
||||
-- adjust panning step according to overlap
|
||||
local overlap = self.overlap
|
||||
if x_pan_off > overlap then
|
||||
-- moving to next view, move view
|
||||
x_pan_off = x_pan_off - overlap
|
||||
elseif x_pan_off < -overlap then
|
||||
x_pan_off = x_pan_off + overlap
|
||||
end
|
||||
if y_pan_off > overlap then
|
||||
y_pan_off = y_pan_off - overlap
|
||||
elseif y_pan_off < -overlap then
|
||||
y_pan_off = y_pan_off + overlap
|
||||
end
|
||||
-- we have to calculate again to count into overlap
|
||||
new_va.x = Math.roundAwayFromZero(self.visible_area.x+x_pan_off)
|
||||
new_va.y = Math.roundAwayFromZero(self.visible_area.y+y_pan_off)
|
||||
-- fit new view area into page area
|
||||
new_va:offsetWithin(self.page_area, 0, 0)
|
||||
-- calculate panning offsets
|
||||
local panned_x = new_va.x - self.visible_area.x
|
||||
local panned_y = new_va.y - self.visible_area.y
|
||||
-- adjust for crazy floating point overflow...
|
||||
if math.abs(panned_x) < 1 then
|
||||
panned_x = 0
|
||||
end
|
||||
if math.abs(panned_y) < 1 then
|
||||
panned_y = 0
|
||||
end
|
||||
-- singal panning update
|
||||
self.view:PanningUpdate(panned_x, panned_y)
|
||||
-- update dime area in ReaderView
|
||||
if self.show_overlap_enable then
|
||||
end
|
||||
|
||||
-- signal panning update
|
||||
local panned_x, panned_y = (new_va.x - old_va.x), (new_va.y - old_va.y)
|
||||
-- adjust for crazy floating point overflow...
|
||||
if math.abs(panned_x) < 1 then
|
||||
panned_x = 0
|
||||
end
|
||||
if math.abs(panned_y) < 1 then
|
||||
panned_y = 0
|
||||
end
|
||||
self.view:PanningUpdate(panned_x, panned_y)
|
||||
|
||||
-- update dim area in ReaderView
|
||||
if self.show_overlap_enable then
|
||||
if self.current_page ~= old_page then
|
||||
self.view.dim_area.x = 0
|
||||
self.view.dim_area.y = 0
|
||||
else
|
||||
self.view.dim_area.h = new_va.h - math.abs(panned_y)
|
||||
self.view.dim_area.w = new_va.w - math.abs(panned_x)
|
||||
if panned_y < 0 then
|
||||
@@ -981,8 +966,6 @@ function ReaderPaging:onGotoPageRel(diff)
|
||||
self.view.dim_area.x = 0
|
||||
end
|
||||
end
|
||||
-- update self.visible_area
|
||||
self.visible_area = new_va
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
@@ -573,12 +573,17 @@ function ReaderView:recalculate()
|
||||
self.visible_area.h = self.visible_area.h - self.ui.view.footer:getHeight()
|
||||
end
|
||||
if self.ui.document.configurable.writing_direction == 0 then
|
||||
-- starts from left top of page_area
|
||||
-- starts from left of page_area
|
||||
self.visible_area.x = self.page_area.x
|
||||
self.visible_area.y = self.page_area.y
|
||||
else
|
||||
-- start from right top of page_area
|
||||
-- start from right of page_area
|
||||
self.visible_area.x = self.page_area.x + self.page_area.w - self.visible_area.w
|
||||
end
|
||||
if self.ui.zooming.zoom_bottom_to_top then
|
||||
-- starts from bottom of page_area
|
||||
self.visible_area.y = self.page_area.y + self.page_area.h - self.visible_area.h
|
||||
else
|
||||
-- starts from top of page_area
|
||||
self.visible_area.y = self.page_area.y
|
||||
end
|
||||
if not self.page_scroll then
|
||||
@@ -736,6 +741,9 @@ In combination with zoom to fit page, page height, content height or content, co
|
||||
end
|
||||
|
||||
self.page_scroll = page_scroll
|
||||
if not page_scroll then
|
||||
self.ui.document.configurable.page_scroll = 0
|
||||
end
|
||||
self:recalculate()
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
end
|
||||
|
||||
@@ -6,8 +6,10 @@ local Geom = require("ui/geometry")
|
||||
local GestureRange = require("ui/gesturerange")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local SpinWidget = require("ui/widget/spinwidget")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local logger = require("logger")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
local Input = Device.input
|
||||
local Screen = Device.screen
|
||||
@@ -15,9 +17,35 @@ local T = require("ffi/util").template
|
||||
|
||||
local ReaderZooming = InputContainer:new{
|
||||
zoom = 1.0,
|
||||
available_zoom_modes = {
|
||||
"page",
|
||||
"pagewidth",
|
||||
"pageheight",
|
||||
"content",
|
||||
"contentwidth",
|
||||
"contentheight",
|
||||
"columns",
|
||||
"rows",
|
||||
"manual",
|
||||
},
|
||||
-- default to nil so we can trigger ZoomModeUpdate events on start up
|
||||
zoom_mode = nil,
|
||||
DEFAULT_ZOOM_MODE = "pagewidth",
|
||||
-- for pan mode: fit to width/zoom_factor,
|
||||
-- with overlap of zoom_overlap_h % (horizontally)
|
||||
-- and zoom_overlap_v % (vertically).
|
||||
zoom_factor = 2,
|
||||
zoom_pan_settings = {
|
||||
"zoom_factor",
|
||||
"zoom_overlap_h",
|
||||
"zoom_overlap_v",
|
||||
"zoom_bottom_to_top",
|
||||
"zoom_direction_vertical",
|
||||
},
|
||||
zoom_overlap_h = 40,
|
||||
zoom_overlap_v = 40,
|
||||
zoom_bottom_to_top = nil, -- true for bottom-to-top
|
||||
zoom_direction_vertical = nil, -- true for column mode
|
||||
current_page = 1,
|
||||
rotation = 0,
|
||||
paged_modes = {
|
||||
@@ -71,25 +99,35 @@ function ReaderZooming:init()
|
||||
doc = "zoom to fit content height",
|
||||
event = "SetZoomMode", args = "contentheight"
|
||||
},
|
||||
ZoomToFitColumn = {
|
||||
{ "Shift", "C" },
|
||||
doc = "zoom to fit column",
|
||||
event = "SetZoomMode", args = "colu"
|
||||
ZoomManual = {
|
||||
{ "Shift", "M" },
|
||||
doc = "manual zoom mode",
|
||||
event = "SetZoomMode", args = "manual"
|
||||
},
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderZooming:onReadSettings(config)
|
||||
local zoom_mode = config:readSetting("zoom_mode") or
|
||||
G_reader_settings:readSetting("zoom_mode") or
|
||||
self.DEFAULT_ZOOM_MODE
|
||||
local zoom_mode = config:readSetting("zoom_mode")
|
||||
or G_reader_settings:readSetting("zoom_mode")
|
||||
or self.DEFAULT_ZOOM_MODE
|
||||
zoom_mode = util.arrayContains(self.available_zoom_modes, zoom_mode)
|
||||
and zoom_mode
|
||||
or self.DEFAULT_ZOOM_MODE
|
||||
self:setZoomMode(zoom_mode, true) -- avoid informative message on load
|
||||
for _, setting in ipairs(self.zoom_pan_settings) do
|
||||
self[setting] = config:readSetting(setting) or
|
||||
G_reader_settings:readSetting(setting) or
|
||||
self[setting]
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderZooming:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("zoom_mode", self.orig_zoom_mode or self.zoom_mode)
|
||||
for _, setting in ipairs(self.zoom_pan_settings) do
|
||||
self.ui.doc_settings:saveSetting(setting, self[setting])
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderZooming:onSpread(arg, ges)
|
||||
@@ -161,6 +199,108 @@ function ReaderZooming:onZoom(direction)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderZooming:onDefineZoom(btn)
|
||||
local config = self.ui.document.configurable
|
||||
local settings = ({
|
||||
[7] = {right_to_left = false, zoom_bottom_to_top = false, zoom_direction_vertical = false},
|
||||
[6] = {right_to_left = false, zoom_bottom_to_top = false, zoom_direction_vertical = true },
|
||||
[5] = {right_to_left = false, zoom_bottom_to_top = true, zoom_direction_vertical = false},
|
||||
[4] = {right_to_left = false, zoom_bottom_to_top = true, zoom_direction_vertical = true },
|
||||
[3] = {right_to_left = true, zoom_bottom_to_top = true, zoom_direction_vertical = true },
|
||||
[2] = {right_to_left = true, zoom_bottom_to_top = true, zoom_direction_vertical = false},
|
||||
[1] = {right_to_left = true, zoom_bottom_to_top = false, zoom_direction_vertical = true },
|
||||
[0] = {right_to_left = true, zoom_bottom_to_top = false, zoom_direction_vertical = false},
|
||||
})[config.zoom_direction]
|
||||
local zoom_range_number = config.zoom_range_number
|
||||
local zoom_factor = config.zoom_factor
|
||||
local zoom_mode_genus = ({
|
||||
[4] = "page",
|
||||
[3] = "content",
|
||||
[2] = "columns",
|
||||
[1] = "rows",
|
||||
[0] = "manual",
|
||||
})[config.zoom_mode_genus]
|
||||
local zoom_mode_type = ({
|
||||
[2] = "",
|
||||
[1] = "width",
|
||||
[0] = "height",
|
||||
})[config.zoom_mode_type]
|
||||
settings.zoom_overlap_h = config.zoom_overlap_h
|
||||
settings.zoom_overlap_v = config.zoom_overlap_v
|
||||
if btn == "set_zoom_overlap_h" then
|
||||
self:_zoomPanChange(_("Set horizontal overlap"), "zoom_overlap_h")
|
||||
settings.zoom_overlap_h = self.zoom_overlap_h
|
||||
elseif btn == "set_zoom_overlap_v" then
|
||||
self:_zoomPanChange(_("Set vertical overlap"), "zoom_overlap_v")
|
||||
settings.zoom_overlap_v = self.zoom_overlap_v
|
||||
end
|
||||
|
||||
local zoom_mode
|
||||
if zoom_mode_genus == "page" or zoom_mode_genus == "content" then
|
||||
zoom_mode = zoom_mode_genus..zoom_mode_type
|
||||
else
|
||||
zoom_mode = zoom_mode_genus
|
||||
self.ui:handleEvent(Event:new("SetScrollMode", false))
|
||||
end
|
||||
zoom_mode = util.arrayContains(self.available_zoom_modes, zoom_mode) and zoom_mode or self.DEFAULT_ZOOM_MODE
|
||||
settings.zoom_mode = zoom_mode
|
||||
|
||||
if settings.right_to_left then
|
||||
if settings.zoom_bottom_to_top then
|
||||
config.writing_direction = 2
|
||||
else
|
||||
config.writing_direction = 1
|
||||
end
|
||||
else
|
||||
config.writing_direction = 0
|
||||
end
|
||||
settings.right_to_left = nil
|
||||
|
||||
if zoom_mode == "columns" or zoom_mode == "rows" then
|
||||
if btn ~= "columns" and btn ~= "rows" then
|
||||
self.ui:handleEvent(Event:new("SetZoomPan", settings, true))
|
||||
settings.zoom_factor = self:setNumberOf(
|
||||
zoom_mode,
|
||||
zoom_range_number,
|
||||
zoom_mode == "columns" and settings.zoom_overlap_h or settings.zoom_overlap_v
|
||||
)
|
||||
end
|
||||
elseif zoom_mode == "manual" then
|
||||
if btn == "manual" then
|
||||
config.zoom_factor = self:getNumberOf("columns")
|
||||
else
|
||||
self:setNumberOf("columns", zoom_factor)
|
||||
end
|
||||
self.ui:handleEvent(Event:new("SetZoomPan", settings, true))
|
||||
end
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", zoom_mode))
|
||||
if btn == "columns" or btn == "rows" then
|
||||
config.zoom_range_number = self:getNumberOf(
|
||||
zoom_mode,
|
||||
btn == "columns" and settings.zoom_overlap_h or settings.zoom_overlap_v
|
||||
)
|
||||
end
|
||||
if tonumber(btn) then
|
||||
UIManager:show(InfoMessage:new{
|
||||
timeout = 2,
|
||||
text = T(_([[Zoom set to:
|
||||
|
||||
mode: %1
|
||||
number of columns: %2
|
||||
number of rows: %4
|
||||
horizontal overlap: %3 %
|
||||
vertical overlap: %5 %
|
||||
zoom factor: %6]]),
|
||||
zoom_mode,
|
||||
("%.2f"):format(self:getNumberOf("columns", settings.zoom_overlap_h)),
|
||||
settings.zoom_overlap_h,
|
||||
("%.2f"):format(self:getNumberOf("rows", settings.zoom_overlap_v)),
|
||||
settings.zoom_overlap_v,
|
||||
("%.2f"):format(self:getNumberOf("columns"))),
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderZooming:onSetZoomMode(new_mode)
|
||||
self.view.zoom_mode = new_mode
|
||||
if self.zoom_mode ~= new_mode then
|
||||
@@ -168,7 +308,11 @@ function ReaderZooming:onSetZoomMode(new_mode)
|
||||
self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode))
|
||||
self.zoom_mode = new_mode
|
||||
self:setZoom()
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates", new_mode))
|
||||
if new_mode == "manual" then
|
||||
self.ui:handleEvent(Event:new("SetScrollMode", false))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates", new_mode))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -241,12 +385,9 @@ 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 zoom
|
||||
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
|
||||
if not (self.zoom_mode and self.zoom_mode:match("^page") or self.ui.document.configurable.trim_page == 3) 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.
|
||||
@@ -283,12 +424,15 @@ function ReaderZooming:getZoom(pageno)
|
||||
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
|
||||
else
|
||||
local zoom_factor = self.ui.doc_settings:readSetting("zoom_factor")
|
||||
or G_reader_settings:readSetting("zoom_factor")
|
||||
or self.zoom_factor
|
||||
zoom = zoom_w * zoom_factor
|
||||
end
|
||||
if zoom and zoom > 10 and not Cache:willAccept(zoom * (self.dimen.w * self.dimen.h + 64)) then
|
||||
logger.dbg("zoom too large, adjusting")
|
||||
@@ -309,7 +453,7 @@ function ReaderZooming:getZoom(pageno)
|
||||
if zoom < 0 then return 0 end
|
||||
end
|
||||
end
|
||||
return zoom
|
||||
return zoom, zoom_w, zoom_h
|
||||
end
|
||||
|
||||
function ReaderZooming:getRegionalZoomCenter(pageno, pos)
|
||||
@@ -345,54 +489,109 @@ function ReaderZooming:genSetZoomModeCallBack(mode)
|
||||
end
|
||||
|
||||
function ReaderZooming:setZoomMode(mode, no_warning)
|
||||
if not no_warning and self.ui.view.page_scroll and self.paged_modes[mode] then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = T(_([[
|
||||
if not no_warning and self.ui.view.page_scroll then
|
||||
local message
|
||||
if self.paged_modes[mode] then
|
||||
message = T(_([[
|
||||
%1
|
||||
|
||||
In combination with continuous view (scroll mode), this can cause unexpected vertical shifts when turning pages.]]), self.paged_modes[mode]),
|
||||
timeout = 5,
|
||||
})
|
||||
In combination with continuous view (scroll mode), this can cause unexpected vertical shifts when turning pages.]]),
|
||||
self.paged_modes[mode])
|
||||
elseif self.zoom_mode == "manual" then
|
||||
message = _([[
|
||||
"Manual zoom works best with page view."
|
||||
|
||||
Please enable page view instead of continuous view (scroll mode).]])
|
||||
end
|
||||
if message then
|
||||
UIManager:show(InfoMessage:new{text = message, timeout = 5})
|
||||
end
|
||||
end
|
||||
|
||||
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"),
|
||||
}
|
||||
}
|
||||
local function _getOverlapFactorForNum(n, overlap)
|
||||
-- Auxiliary function to "distribute" an overlap between tiles
|
||||
overlap = overlap * (n - 1) / n
|
||||
return (100 / (100 - overlap))
|
||||
end
|
||||
|
||||
function ReaderZooming:getNumberOf(what, overlap)
|
||||
-- Number of columns (if what ~= "rows") or rows (if what == "rows")
|
||||
local zoom, zoom_w, zoom_h = self:getZoom(self.current_page)
|
||||
local zoom_factor = zoom / (what == "rows" and zoom_h or zoom_w)
|
||||
if overlap then
|
||||
overlap = (what == "rows" and self.zoom_overlap_v or self.zoom_overlap_h)
|
||||
zoom_factor = (overlap - 100 * zoom_factor) / (overlap - 100) -- Thanks Xcas for this one...
|
||||
end
|
||||
return zoom_factor
|
||||
end
|
||||
|
||||
function ReaderZooming:setNumberOf(what, num, overlap)
|
||||
-- Sets number of columns (if what ~= "rows") or rows (if what == "rows")
|
||||
local _, zoom_w, zoom_h = self:getZoom(self.current_page)
|
||||
local overlap_factor = overlap and _getOverlapFactorForNum(num, overlap) or 1
|
||||
local zoom_factor = num / overlap_factor
|
||||
if what == "rows" then
|
||||
zoom_factor = zoom_factor * zoom_h / zoom_w
|
||||
end
|
||||
self.ui:handleEvent(Event:new("SetZoomPan", {zoom_factor = zoom_factor}))
|
||||
self.ui:handleEvent(Event:new("RedrawCurrentPage"))
|
||||
end
|
||||
|
||||
function ReaderZooming:_zoomFactorChange(title_text, direction, precision)
|
||||
local zoom_factor, overlap = self:getNumberOf(direction)
|
||||
UIManager:show(SpinWidget:new{
|
||||
width = math.floor(Screen:getWidth() * 0.6),
|
||||
value = zoom_factor,
|
||||
value_min = 0.1,
|
||||
value_max = 10,
|
||||
value_step = 0.1,
|
||||
value_hold_step = 1,
|
||||
precision = "%.1f",
|
||||
ok_text = title_text,
|
||||
title_text = title_text,
|
||||
callback = function(spin)
|
||||
zoom_factor = spin.value
|
||||
self:setNumberOf(direction, zoom_factor, overlap)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
function ReaderZooming:_zoomPanChange(text, setting)
|
||||
UIManager:show(SpinWidget:new{
|
||||
width = math.floor(Screen:getWidth() * 0.6),
|
||||
value = self[setting],
|
||||
value_min = 0,
|
||||
value_max = 90,
|
||||
value_step = 1,
|
||||
value_hold_step = 10,
|
||||
ok_text = _("Set"),
|
||||
title_text = text,
|
||||
callback = function(spin)
|
||||
self.ui:handleEvent(Event:new("SetZoomPan", {[setting] = spin.value}))
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
function ReaderZooming:onZoomFactorChange()
|
||||
self:_zoomFactorChange(_("Set Zoom factor"), false, "%.1f")
|
||||
end
|
||||
|
||||
function ReaderZooming:onSetZoomPan(settings, no_redraw)
|
||||
for k, v in pairs(settings) do
|
||||
self[k] = v
|
||||
self.ui.doc_settings:saveSetting(k, v)
|
||||
end
|
||||
if not no_redraw then
|
||||
self.ui:handleEvent(Event:new("RedrawCurrentPage"))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderZooming:onBBoxUpdate()
|
||||
self:onDefineZoom()
|
||||
end
|
||||
|
||||
function ReaderZooming:makeDefault(zoom_mode, touchmenu_instance)
|
||||
|
||||
Reference in New Issue
Block a user