mirror of
https://github.com/koreader/koreader
synced 2024-11-10 01:10:34 +00:00
747 lines
28 KiB
Lua
747 lines
28 KiB
Lua
local Blitbuffer = require("ffi/blitbuffer")
|
|
local ConfirmBox = require("ui/widget/confirmbox")
|
|
local Device = require("device")
|
|
local InputContainer = require("ui/widget/container/inputcontainer")
|
|
local Event = require("ui/event")
|
|
local ReaderPanning = require("apps/reader/modules/readerpanning")
|
|
local UIManager = require("ui/uimanager")
|
|
local logger = require("logger")
|
|
local _ = require("gettext")
|
|
local Input = Device.input
|
|
local Screen = Device.screen
|
|
|
|
--[[
|
|
Rolling is just like paging in page-based documents except that
|
|
sometimes (in scroll mode) there is no concept of page number to indicate
|
|
current progress.
|
|
There are three kind of progress measurements for credocuments.
|
|
1. page number (in page mode)
|
|
2. progress percentage (in scroll mode)
|
|
3. xpointer (in document dom structure)
|
|
We found that the first two measurements are not suitable for keeping a
|
|
record of the real progress. For example, when switching screen orientation
|
|
from portrait to landscape, or switching view mode from page to scroll, the
|
|
internal xpointer should not be used as the view dimen/mode is changed and
|
|
crengine's pagination mechanism will find a closest xpointer for the new view.
|
|
So if we change the screen orientation or view mode back, we cannot find the
|
|
original place since the internal xpointer is changed, which is counter-
|
|
intuitive as users didn't goto any other page.
|
|
The solution is that we keep a record of the internal xpointer and only change
|
|
it in explicit page turning. And use that xpointer for non-page-turning
|
|
rendering.
|
|
--]]
|
|
local ReaderRolling = InputContainer:new{
|
|
pan_rate = 30, -- default 30 ops, will be adjusted in readerui
|
|
old_doc_height = nil,
|
|
old_page = nil,
|
|
current_pos = 0,
|
|
inverse_reading_order = false,
|
|
-- only used for page view mode
|
|
current_page= nil,
|
|
doc_height = nil,
|
|
xpointer = nil,
|
|
panning_steps = ReaderPanning.panning_steps,
|
|
show_overlap_enable = nil,
|
|
-- nb of lines from previous page to show on next page (scroll mode only)
|
|
overlap_lines = G_reader_settings:readSetting("copt_overlap_lines") or 1,
|
|
cre_top_bar_enabled = false,
|
|
}
|
|
|
|
function ReaderRolling:init()
|
|
if Device:hasKeyboard() or Device:hasKeys() then
|
|
self.key_events = {
|
|
GotoNextView = {
|
|
{ Input.group.PgFwd },
|
|
doc = "go to next view",
|
|
event = "GotoViewRel", args = 1
|
|
},
|
|
GotoPrevView = {
|
|
{ Input.group.PgBack },
|
|
doc = "go to previous view",
|
|
event = "GotoViewRel", args = -1
|
|
},
|
|
MoveUp = {
|
|
{ "Up" },
|
|
doc = "move view up",
|
|
event = "Panning", args = {0, -1}
|
|
},
|
|
MoveDown = {
|
|
{ "Down" },
|
|
doc = "move view down",
|
|
event = "Panning", args = {0, 1}
|
|
},
|
|
GotoFirst = {
|
|
{"1"}, doc = "go to start", event = "GotoPercent", args = 0},
|
|
Goto11 = {
|
|
{"2"}, doc = "go to 11%", event = "GotoPercent", args = 11},
|
|
Goto22 = {
|
|
{"3"}, doc = "go to 22%", event = "GotoPercent", args = 22},
|
|
Goto33 = {
|
|
{"4"}, doc = "go to 33%", event = "GotoPercent", args = 33},
|
|
Goto44 = {
|
|
{"5"}, doc = "go to 44%", event = "GotoPercent", args = 44},
|
|
Goto55 = {
|
|
{"6"}, doc = "go to 55%", event = "GotoPercent", args = 55},
|
|
Goto66 = {
|
|
{"7"}, doc = "go to 66%", event = "GotoPercent", args = 66},
|
|
Goto77 = {
|
|
{"8"}, doc = "go to 77%", event = "GotoPercent", args = 77},
|
|
Goto88 = {
|
|
{"9"}, doc = "go to 88%", event = "GotoPercent", args = 88},
|
|
GotoLast = {
|
|
{"0"}, doc = "go to end", event = "GotoPercent", args = 100},
|
|
}
|
|
end
|
|
|
|
table.insert(self.ui.postInitCallback, function()
|
|
self.doc_height = self.ui.document.info.doc_height
|
|
self.old_doc_height = self.doc_height
|
|
self.ui.document:_readMetadata()
|
|
self.old_page = self.ui.document.info.number_of_pages
|
|
end)
|
|
table.insert(self.ui.postReaderCallback, function()
|
|
self:updatePos()
|
|
-- Disable crengine internal history, with required redraw
|
|
self.ui.document:enableInternalHistory(false)
|
|
self:onRedrawCurrentView()
|
|
end)
|
|
self.ui.menu:registerToMainMenu(self)
|
|
end
|
|
|
|
function ReaderRolling:onReadSettings(config)
|
|
-- 20180503: some fix in crengine has changed the way the DOM is built
|
|
-- for HTML documents and may make XPATHs obtained from previous version
|
|
-- invalid.
|
|
-- We may request the previous (buggy) behaviour though, which we do
|
|
-- if we use a DocSetting previously made that may contain bookmarks
|
|
-- and highlights with old XPATHs.
|
|
-- (EPUB will use the same correct DOM code no matter what DOM version
|
|
-- we request here.)
|
|
if not config:readSetting("cre_dom_version") then
|
|
-- Not previously set, guess which DOM version to use
|
|
if config:readSetting("last_xpointer") then
|
|
-- We have a last_xpointer: this book was previously opened
|
|
-- with possibly a very old version: request the oldest
|
|
config:saveSetting("cre_dom_version", self.ui.document:getOldestDomVersion())
|
|
else
|
|
-- No previous xpointer: book never opened (or sidecar file
|
|
-- purged): we can use the latest DOM version
|
|
config:saveSetting("cre_dom_version", self.ui.document:getLatestDomVersion())
|
|
end
|
|
end
|
|
self.ui.document:requestDomVersion(config:readSetting("cre_dom_version"))
|
|
|
|
local last_xp = config:readSetting("last_xpointer")
|
|
local last_per = config:readSetting("last_percent")
|
|
if last_xp then
|
|
self.xpointer = last_xp
|
|
self.setupXpointer = function()
|
|
self:_gotoXPointer(self.xpointer)
|
|
-- we have to do a real jump in self.ui.document._document to
|
|
-- update status information in CREngine.
|
|
self.ui.document:gotoXPointer(self.xpointer)
|
|
end
|
|
-- we read last_percent just for backward compatibility
|
|
-- FIXME: remove this branch with migration script
|
|
elseif last_per then
|
|
self.setupXpointer = function()
|
|
self:_gotoPercent(last_per)
|
|
-- _gotoPercent calls _gotoPos, which only updates self.current_pos
|
|
-- and self.view.
|
|
-- we need to do a real pos change in self.ui.document._document
|
|
-- to update status information in CREngine.
|
|
self.ui.document:gotoPos(self.current_pos)
|
|
-- _gotoPercent already calls gotoPos, so no need to emit
|
|
-- PosUpdate event in scroll mode
|
|
if self.view.view_mode == "page" then
|
|
self.ui:handleEvent(
|
|
Event:new("PageUpdate", self.ui.document:getCurrentPage()))
|
|
end
|
|
self.xpointer = self.ui.document:getXPointer()
|
|
end
|
|
else
|
|
self.setupXpointer = function()
|
|
self.xpointer = self.ui.document:getXPointer()
|
|
if self.view.view_mode == "page" then
|
|
self.ui:handleEvent(Event:new("PageUpdate", 1))
|
|
end
|
|
end
|
|
end
|
|
self.show_overlap_enable = config:readSetting("show_overlap_enable")
|
|
if self.show_overlap_enable == nil then
|
|
self.show_overlap_enable = DSHOWOVERLAP
|
|
end
|
|
self.inverse_reading_order = config:readSetting("inverse_reading_order") or false
|
|
end
|
|
|
|
-- in scroll mode percent_finished must be save before close document
|
|
-- we cannot do it in onSaveSettings() because getLastPercent() uses self.ui.document
|
|
function ReaderRolling:onCloseDocument()
|
|
self.ui.doc_settings:saveSetting("percent_finished", self:getLastPercent())
|
|
local cache_file_path = self.ui.document:getCacheFilePath() -- nil if no cache file
|
|
self.ui.doc_settings:saveSetting("cache_file_path", cache_file_path)
|
|
if self.ui.document:hasCacheFile() then
|
|
-- also checks if DOM is coherent with styles; if not, invalidate the
|
|
-- cache, so a new DOM is built on next opening
|
|
if self.ui.document:isBuiltDomStale() then
|
|
logger.dbg("cre DOM may not be in sync with styles, invalidating cache file for a full reload at next opening")
|
|
self.ui.document:invalidateCacheFile()
|
|
end
|
|
end
|
|
logger.dbg("cre cache used:", cache_file_path or "none")
|
|
end
|
|
|
|
function ReaderRolling:onCheckDomStyleCoherence()
|
|
if self.ui.document:isBuiltDomStale() then
|
|
UIManager:show(ConfirmBox:new{
|
|
text = _("Styles have changed in such a way that fully reloading the document may be needed for a correct rendering.\nDo you want to reload the document?"),
|
|
ok_callback = function()
|
|
-- Allow for ConfirmBox to be closed before showing
|
|
-- "Opening file" InfoMessage
|
|
UIManager:scheduleIn(0.5, function ()
|
|
self.ui:reloadDocument()
|
|
end)
|
|
end,
|
|
})
|
|
end
|
|
end
|
|
|
|
function ReaderRolling:onSaveSettings()
|
|
-- remove last_percent config since its deprecated
|
|
self.ui.doc_settings:saveSetting("last_percent", nil)
|
|
self.ui.doc_settings:saveSetting("last_xpointer", self.xpointer)
|
|
-- in scrolling mode, the document may already be closed,
|
|
-- so we have to check the condition to avoid crash function self:getLastPercent()
|
|
-- that uses self.ui.document
|
|
if self.ui.document then
|
|
self.ui.doc_settings:saveSetting("percent_finished", self:getLastPercent())
|
|
end
|
|
self.ui.doc_settings:saveSetting("show_overlap_enable", self.show_overlap_enable)
|
|
self.ui.doc_settings:saveSetting("inverse_reading_order", self.inverse_reading_order)
|
|
end
|
|
|
|
function ReaderRolling:onReaderReady()
|
|
self:setupTouchZones()
|
|
self.setupXpointer()
|
|
end
|
|
|
|
function ReaderRolling:setupTouchZones()
|
|
self.ges_events = {}
|
|
self.onGesture = nil
|
|
if not Device:isTouchDevice() then return end
|
|
|
|
local forward_zone = {
|
|
ratio_x = DTAP_ZONE_FORWARD.x, ratio_y = DTAP_ZONE_FORWARD.y,
|
|
ratio_w = DTAP_ZONE_FORWARD.w, ratio_h = DTAP_ZONE_FORWARD.h,
|
|
}
|
|
local backward_zone = {
|
|
ratio_x = DTAP_ZONE_BACKWARD.x, ratio_y = DTAP_ZONE_BACKWARD.y,
|
|
ratio_w = DTAP_ZONE_BACKWARD.w, ratio_h = DTAP_ZONE_BACKWARD.h,
|
|
}
|
|
|
|
local forward_double_tap_zone = {
|
|
ratio_x = DDOUBLE_TAP_ZONE_NEXT_CHAPTER.x, ratio_y = DDOUBLE_TAP_ZONE_NEXT_CHAPTER.y,
|
|
ratio_w = DDOUBLE_TAP_ZONE_NEXT_CHAPTER.w, ratio_h = DDOUBLE_TAP_ZONE_NEXT_CHAPTER.h,
|
|
}
|
|
local backward_double_tap_zone = {
|
|
ratio_x = DDOUBLE_TAP_ZONE_PREV_CHAPTER.x, ratio_y = DDOUBLE_TAP_ZONE_PREV_CHAPTER.y,
|
|
ratio_w = DDOUBLE_TAP_ZONE_PREV_CHAPTER.w, ratio_h = DDOUBLE_TAP_ZONE_PREV_CHAPTER.h,
|
|
}
|
|
|
|
if self.inverse_reading_order then
|
|
forward_zone.ratio_x = 1 - forward_zone.ratio_x - forward_zone.ratio_w
|
|
backward_zone.ratio_x = 1 - backward_zone.ratio_x - backward_zone.ratio_w
|
|
|
|
forward_double_tap_zone.ratio_x =
|
|
1 - forward_double_tap_zone.ratio_x - forward_double_tap_zone.ratio_w
|
|
backward_double_tap_zone.ratio_x =
|
|
1 - backward_double_tap_zone.ratio_x - backward_double_tap_zone.ratio_w
|
|
end
|
|
|
|
self.ui:registerTouchZones({
|
|
{
|
|
id = "tap_forward",
|
|
ges = "tap",
|
|
screen_zone = forward_zone,
|
|
handler = function() return self:onTapForward() end
|
|
},
|
|
{
|
|
id = "tap_backward",
|
|
ges = "tap",
|
|
screen_zone = backward_zone,
|
|
handler = function() return self:onTapBackward() end
|
|
},
|
|
{
|
|
id = "double_tap_forward",
|
|
ges = "double_tap",
|
|
screen_zone = forward_double_tap_zone,
|
|
handler = function() return self:onDoubleTapForward() end
|
|
},
|
|
{
|
|
id = "double_tap_backward",
|
|
ges = "double_tap",
|
|
screen_zone = backward_double_tap_zone,
|
|
handler = function() return self:onDoubleTapBackward() end
|
|
},
|
|
{
|
|
id = "rolling_swipe",
|
|
ges = "swipe",
|
|
screen_zone = {
|
|
ratio_x = 0, ratio_y = 0, ratio_w = 1, ratio_h = 1,
|
|
},
|
|
handler = function(ges) return self:onSwipe(nil, ges) end
|
|
},
|
|
{
|
|
id = "rolling_pan",
|
|
ges = "pan",
|
|
rate = self.pan_rate,
|
|
screen_zone = {
|
|
ratio_x = 0, ratio_y = 0, ratio_w = 1, ratio_h = 1,
|
|
},
|
|
handler = function(ges) return self:onPan(nil, ges) end
|
|
},
|
|
})
|
|
end
|
|
|
|
function ReaderRolling:getLastProgress()
|
|
return self.xpointer
|
|
end
|
|
|
|
function ReaderRolling:addToMainMenu(menu_items)
|
|
-- FIXME: repeated code with page overlap menu for readerpaging
|
|
-- needs to keep only one copy of the logic as for the DRY principle.
|
|
-- The difference between the two menus is only the enabled func.
|
|
local page_overlap_menu = {
|
|
{
|
|
text_func = function()
|
|
return self.show_overlap_enable and _("Disable") or _("Enable")
|
|
end,
|
|
callback = function()
|
|
self.show_overlap_enable = not self.show_overlap_enable
|
|
if not self.show_overlap_enable then
|
|
self.view:resetDimArea()
|
|
end
|
|
end
|
|
},
|
|
}
|
|
for _, menu_entry in ipairs(self.view:genOverlapStyleMenu()) do
|
|
table.insert(page_overlap_menu, menu_entry)
|
|
end
|
|
menu_items.page_overlap = {
|
|
text = _("Page overlap"),
|
|
enabled_func = function() return self.view.view_mode ~= "page" end,
|
|
sub_item_table = page_overlap_menu,
|
|
}
|
|
end
|
|
|
|
function ReaderRolling:getLastPercent()
|
|
if self.view.view_mode == "page" then
|
|
return self.current_page / self.old_page
|
|
else
|
|
-- FIXME: the calculated percent is not accurate in "scroll" mode.
|
|
return self.ui.document:getPosFromXPointer(
|
|
self.ui.document:getXPointer()) / self.doc_height
|
|
end
|
|
end
|
|
|
|
function ReaderRolling:onTapForward()
|
|
self:onGotoViewRel(1)
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onTapBackward()
|
|
self:onGotoViewRel(-1)
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onSwipe(_, ges)
|
|
if ges.direction == "north" then
|
|
self:onGotoViewRel(1)
|
|
elseif ges.direction == "south" then
|
|
self:onGotoViewRel(-1)
|
|
elseif ges.direction == "west" then
|
|
if self.inverse_reading_order then
|
|
self:onGotoViewRel(-1)
|
|
else
|
|
self:onGotoViewRel(1)
|
|
end
|
|
elseif ges.direction == "east" then
|
|
if self.inverse_reading_order then
|
|
self:onGotoViewRel(1)
|
|
else
|
|
self:onGotoViewRel(-1)
|
|
end
|
|
else
|
|
-- update footer (time & battery)
|
|
self.view.footer:updateFooter()
|
|
-- trigger full refresh
|
|
UIManager:setDirty(nil, "full")
|
|
end
|
|
end
|
|
|
|
function ReaderRolling:onPan(_, ges)
|
|
if self.view.view_mode == "scroll" then
|
|
if ges.direction == "north" then
|
|
self:_gotoPos(self.current_pos + ges.distance)
|
|
elseif ges.direction == "south" then
|
|
self:_gotoPos(self.current_pos - ges.distance)
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onPosUpdate(new_pos)
|
|
self.current_pos = new_pos
|
|
self:updateBatteryState()
|
|
end
|
|
|
|
function ReaderRolling:onPageUpdate(new_page)
|
|
self.current_page = new_page
|
|
self:updateBatteryState()
|
|
end
|
|
|
|
function ReaderRolling:onResume()
|
|
self:updateBatteryState()
|
|
end
|
|
|
|
function ReaderRolling:onDoubleTapForward()
|
|
local visible_page_count = self.ui.document:getVisiblePageCount()
|
|
local pageno = self.current_page + (visible_page_count > 1 and 1 or 0)
|
|
local new_page = self.ui.toc:getNextChapter(pageno, 0)
|
|
if new_page then
|
|
self.ui.link:addCurrentLocationToStack()
|
|
self:onGotoPage(new_page)
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onDoubleTapBackward()
|
|
local pageno = self.current_page
|
|
local new_page = self.ui.toc:getPreviousChapter(pageno, 0)
|
|
if new_page then
|
|
self.ui.link:addCurrentLocationToStack()
|
|
self:onGotoPage(new_page)
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onNotCharging()
|
|
self:updateBatteryState()
|
|
end
|
|
|
|
function ReaderRolling:onGotoPercent(percent)
|
|
logger.dbg("goto document offset in percent:", percent)
|
|
self:_gotoPercent(percent)
|
|
self.xpointer = self.ui.document:getXPointer()
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onGotoPage(number)
|
|
if number then
|
|
self:_gotoPage(number)
|
|
end
|
|
self.xpointer = self.ui.document:getXPointer()
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onGotoRelativePage(number)
|
|
if number then
|
|
self:_gotoPage(self.current_page + number)
|
|
end
|
|
self.xpointer = self.ui.document:getXPointer()
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onGotoXPointer(xp, marker_xp)
|
|
if self.mark_func then
|
|
-- unschedule previous marker as it's no more accurate
|
|
UIManager:unschedule(self.mark_func)
|
|
self.mark_func = nil
|
|
end
|
|
if self.unmark_func then
|
|
-- execute scheduled unmark now to clean previous marker
|
|
self.unmark_func()
|
|
self.unmark_func = nil
|
|
end
|
|
self:_gotoXPointer(xp)
|
|
self.xpointer = xp
|
|
|
|
-- Allow tweaking this marker behaviour with a manual setting:
|
|
-- followed_link_marker = false: no marker shown
|
|
-- followed_link_marker = true: maker shown and not auto removed
|
|
-- followed_link_marker = <number>: removed after <number> seconds
|
|
-- (no real need for a menu item, the default is the finest)
|
|
local marker_setting = G_reader_settings:readSetting("followed_link_marker")
|
|
if marker_setting == nil then
|
|
marker_setting = 1 -- default is: shown and removed after 1 second
|
|
end
|
|
|
|
if marker_xp and marker_setting then
|
|
-- Show a mark on left side of screen to give a visual feedback of
|
|
-- where xpointer target is (and remove if after 1s)
|
|
local doc_y = self.ui.document:getPosFromXPointer(marker_xp)
|
|
local top_y = self.ui.document:getCurrentPos()
|
|
local screen_y = doc_y - top_y
|
|
local doc_margins = self.ui.document:getPageMargins()
|
|
local header_height = self.ui.document:getHeaderHeight() -- top full status bar (0 when bottom mini bar used)
|
|
if self.view.view_mode == "page" then
|
|
screen_y = screen_y + doc_margins["top"] + header_height
|
|
end
|
|
local marker_h = Screen:scaleBySize(self.ui.font.font_size * 1.1 * self.ui.font.line_space_percent/100.0)
|
|
-- Make it 4/5 of left margin wide (and bigger when huge margin)
|
|
local marker_w = math.floor(math.max(doc_margins["left"] - Screen:scaleBySize(5), doc_margins["left"] * 4/5))
|
|
|
|
self.mark_func = function()
|
|
self.mark_func = nil
|
|
Screen.bb:paintRect(0, screen_y, marker_w, marker_h, Blitbuffer.COLOR_BLACK)
|
|
Screen["refreshFast"](Screen, 0, screen_y, marker_w, marker_h)
|
|
if type(marker_setting) == "number" then -- hide it
|
|
self.unmark_func = function()
|
|
self.unmark_func = nil
|
|
-- UIManager:setDirty(self.view.dialog, "ui", Geom:new({x=0, y=screen_y, w=marker_w, h=marker_h}))
|
|
-- No need to use setDirty (which would ask crengine to
|
|
-- re-render the page, which may take a few seconds on big
|
|
-- documents): we drew our black marker in the margin, we
|
|
-- can just draw a white one to make it disappear
|
|
Screen.bb:paintRect(0, screen_y, marker_w, marker_h, Blitbuffer.COLOR_WHITE)
|
|
Screen["refreshUI"](Screen, 0, screen_y, marker_w, marker_h)
|
|
end
|
|
UIManager:scheduleIn(marker_setting, self.unmark_func)
|
|
end
|
|
end
|
|
UIManager:scheduleIn(0.5, self.mark_func)
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:getBookLocation()
|
|
return self.xpointer
|
|
end
|
|
|
|
function ReaderRolling:onRestoreBookLocation(saved_location)
|
|
return self:onGotoXPointer(saved_location.xpointer, saved_location.marker_xpointer)
|
|
end
|
|
|
|
function ReaderRolling:onGotoViewRel(diff)
|
|
logger.dbg("goto relative screen:", diff, ", in mode: ", self.view.view_mode)
|
|
if self.view.view_mode == "scroll" then
|
|
local footer_height = (self.view.footer_visible and 1 or 0) * self.view.footer:getHeight()
|
|
local page_visible_height = self.ui.dimen.h - footer_height
|
|
local pan_diff = diff * page_visible_height
|
|
if self.show_overlap_enable then
|
|
local overlap_h = Screen:scaleBySize(self.ui.font.font_size * 1.1 * self.ui.font.line_space_percent/100.0) * self.overlap_lines
|
|
if pan_diff > overlap_h then
|
|
pan_diff = pan_diff - overlap_h
|
|
elseif pan_diff < -overlap_h then
|
|
pan_diff = pan_diff + overlap_h
|
|
end
|
|
end
|
|
local old_pos = self.current_pos
|
|
-- Only draw dim area when we moved a whole page (not when smaller scroll with Pan)
|
|
local do_dim_area = math.abs(diff) == 1
|
|
self:_gotoPos(self.current_pos + pan_diff, do_dim_area)
|
|
if diff > 0 and old_pos == self.current_pos then
|
|
self.ui:handleEvent(Event:new("EndOfBook"))
|
|
end
|
|
elseif self.view.view_mode == "page" then
|
|
local page_count = self.ui.document:getVisiblePageCount()
|
|
local old_page = self.current_page
|
|
self:_gotoPage(self.current_page + diff*page_count)
|
|
if diff > 0 and old_page == self.current_page then
|
|
self.ui:handleEvent(Event:new("EndOfBook"))
|
|
end
|
|
end
|
|
if self.ui.document ~= nil then
|
|
self.xpointer = self.ui.document:getXPointer()
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onPanning(args, _)
|
|
if self.view.view_mode ~= "scroll" then return end
|
|
local _, dy = unpack(args)
|
|
self:_gotoPos(self.current_pos + dy * self.panning_steps.normal)
|
|
self.xpointer = self.ui.document:getXPointer()
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onZoom()
|
|
--@TODO re-read doc_height info after font or lineheight changes 05.06 2012 (houqp)
|
|
self:updatePos()
|
|
end
|
|
|
|
--[[
|
|
remember to signal this event when the document has been zoomed,
|
|
font has been changed, or line height has been changed.
|
|
Note that xpointer should not be changed.
|
|
--]]
|
|
function ReaderRolling:onUpdatePos()
|
|
if self.ui.postReaderCallback ~= nil then -- ReaderUI:init() not yet done
|
|
-- Don't schedule any updatePos as long as ReaderUI:init() is
|
|
-- not finished (one will be called in the ui.postReaderCallback
|
|
-- we have set above) to avoid multiple refreshes.
|
|
return true
|
|
end
|
|
UIManager:scheduleIn(0.1, function () self:updatePos() end)
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:updatePos()
|
|
-- reread document height
|
|
self.ui.document:_readMetadata()
|
|
-- update self.current_pos if the height of document has been changed.
|
|
local new_height = self.ui.document.info.doc_height
|
|
local new_page = self.ui.document.info.number_of_pages
|
|
if self.old_doc_height ~= new_height or self.old_page ~= new_page then
|
|
self:_gotoXPointer(self.xpointer)
|
|
self.old_doc_height = new_height
|
|
self.old_page = new_page
|
|
self.ui:handleEvent(Event:new("UpdateToc"))
|
|
self.view.footer:updateFooter()
|
|
end
|
|
UIManager:setDirty(self.view.dialog, "partial")
|
|
-- Allow for the new rendering to be shown before possibly showing
|
|
-- the "Styles have changes..." ConfirmBox so the user can decide
|
|
-- if it is really needed
|
|
UIManager:scheduleIn(0.1, function ()
|
|
self:onCheckDomStyleCoherence()
|
|
end)
|
|
end
|
|
|
|
--[[
|
|
switching screen mode should not change current page number
|
|
--]]
|
|
function ReaderRolling:onChangeViewMode()
|
|
self.ui.document:_readMetadata()
|
|
self.old_doc_height = self.ui.document.info.doc_height
|
|
self.old_page = self.ui.document.info.number_of_pages
|
|
self.ui:handleEvent(Event:new("UpdateToc"))
|
|
if self.xpointer then
|
|
self:_gotoXPointer(self.xpointer)
|
|
else
|
|
table.insert(self.ui.postInitCallback, function()
|
|
self:_gotoXPointer(self.xpointer)
|
|
end)
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onRedrawCurrentView()
|
|
if self.view.view_mode == "page" then
|
|
self.ui:handleEvent(Event:new("PageUpdate", self.current_page))
|
|
else
|
|
self.ui:handleEvent(Event:new("PosUpdate", self.current_pos))
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onSetDimensions(dimen)
|
|
self.ui.document:setViewDimen(Screen:getSize())
|
|
end
|
|
|
|
function ReaderRolling:onChangeScreenMode(mode)
|
|
-- We need to temporarily re-enable internal history as crengine
|
|
-- uses it to reposition after resize
|
|
self.ui.document:enableInternalHistory(true)
|
|
self.ui:handleEvent(Event:new("SetScreenMode", mode))
|
|
self.ui.document:setViewDimen(Screen:getSize())
|
|
self:onChangeViewMode()
|
|
self:onUpdatePos()
|
|
-- Re-disable internal history, with required redraw
|
|
self.ui.document:enableInternalHistory(false)
|
|
self:onRedrawCurrentView()
|
|
end
|
|
|
|
function ReaderRolling:onColorRenderingUpdate()
|
|
self.ui.document:updateColorRendering()
|
|
end
|
|
|
|
--[[
|
|
PosUpdate event is used to signal other widgets that pos has been changed.
|
|
--]]
|
|
function ReaderRolling:_gotoPos(new_pos, do_dim_area)
|
|
if new_pos == self.current_pos then return end
|
|
if new_pos < 0 then new_pos = 0 end
|
|
if new_pos > self.doc_height then new_pos = self.doc_height end
|
|
-- adjust dim_area according to new_pos
|
|
if self.view.view_mode ~= "page" and self.show_overlap_enable and do_dim_area then
|
|
local footer_height = (self.view.footer_visible and 1 or 0) * self.view.footer:getHeight()
|
|
local page_visible_height = self.ui.dimen.h - footer_height
|
|
local panned_step = new_pos - self.current_pos
|
|
self.view.dim_area.x = 0
|
|
self.view.dim_area.h = page_visible_height - math.abs(panned_step)
|
|
self.view.dim_area.w = self.ui.dimen.w
|
|
if panned_step < 0 then
|
|
self.view.dim_area.y = page_visible_height - self.view.dim_area.h
|
|
elseif panned_step > 0 then
|
|
self.view.dim_area.y = 0
|
|
end
|
|
else
|
|
self.view:resetDimArea()
|
|
end
|
|
self.ui.document:gotoPos(new_pos)
|
|
-- The current page we get in scroll mode may be a bit innacurate,
|
|
-- but we give it anyway to onPosUpdate so footer and statistics can
|
|
-- keep up with page.
|
|
self.ui:handleEvent(Event:new("PosUpdate", new_pos, self.ui.document:getCurrentPage()))
|
|
end
|
|
|
|
function ReaderRolling:_gotoPercent(new_percent)
|
|
self:_gotoPos(new_percent * self.doc_height / 10000)
|
|
end
|
|
|
|
function ReaderRolling:_gotoPage(new_page)
|
|
self.ui.document:gotoPage(new_page)
|
|
if self.view.view_mode == "page" then
|
|
self.ui:handleEvent(Event:new("PageUpdate", self.ui.document:getCurrentPage()))
|
|
else
|
|
self.ui:handleEvent(Event:new("PosUpdate", self.ui.document:getCurrentPos(), self.ui.document:getCurrentPage()))
|
|
end
|
|
end
|
|
|
|
function ReaderRolling:_gotoXPointer(xpointer)
|
|
if self.view.view_mode == "page" then
|
|
self:_gotoPage(self.ui.document:getPageFromXPointer(xpointer))
|
|
else
|
|
self:_gotoPos(self.ui.document:getPosFromXPointer(xpointer))
|
|
end
|
|
end
|
|
|
|
--[[
|
|
currently we don't need to get page links on each page/pos update
|
|
since we can check link on the fly when tapping on the screen
|
|
function ReaderRolling:updatePageLink()
|
|
logger.dbg("update page link")
|
|
local links = self.ui.document:getPageLinks()
|
|
self.view.links = links
|
|
end
|
|
--]]
|
|
|
|
function ReaderRolling:onSetStatusLine(status_line, on_read_settings)
|
|
-- status_line values:
|
|
-- in crengine: 0=header enabled, 1=disabled
|
|
-- in koreader: 0=top status bar, 1=bottom mini bar
|
|
self.ui.document:setStatusLineProp(status_line)
|
|
self.cre_top_bar_enabled = status_line == 0
|
|
if not on_read_settings then
|
|
-- Ignore this event when it is first sent by ReaderCoptListener
|
|
-- on book loading, so we stay with the saved footer settings
|
|
self.view.footer:setVisible(status_line == 1)
|
|
end
|
|
self.ui:handleEvent(Event:new("UpdatePos"))
|
|
end
|
|
|
|
function ReaderRolling:updateBatteryState()
|
|
if self.view.view_mode == "page" and self.cre_top_bar_enabled then
|
|
logger.dbg("update battery state")
|
|
local powerd = Device:getPowerDevice()
|
|
-- -1 is CR_BATTERY_STATE_CHARGING @ crengine/crengine/include/lvdocview.h
|
|
local state = powerd:isCharging() and -1 or powerd:getCapacity()
|
|
if state then
|
|
self.ui.document:setBatteryState(state)
|
|
end
|
|
end
|
|
end
|
|
|
|
return ReaderRolling
|