Hide non-linear fragments

Add option to hide (skip) non-linear fragments, only working
in 1-page mode. Tweaks mostly to footer, toc and skim code
to make it clear(er) which pages belong to linear or non-linear
fragments.
reviewable/pr6897/r1
Jellby 4 years ago committed by poire-z
parent f892d4559f
commit 5e3c554dd7

@ -1 +1 @@
Subproject commit dd34e3497ba30bdfe300d4dd069fefc432263814
Subproject commit 514ac803f17b8fd2db9c85e32fd4118ab15ed85b

@ -257,6 +257,13 @@ function ReaderBookmark:onShowBookmark()
page = self.ui.pagemap:getXPointerPageLabel(page, true)
else
page = self.ui.document:getPageFromXPointer(page)
if self.ui.document:hasHiddenFlows() then
local flow = self.ui.document:getPageFlow(page)
page = self.ui.document:getPageNumberInFlow(page)
if flow > 0 then
page = T("[%1]%2", page, flow)
end
end
end
end
if v.text == nil or v.text == "" then
@ -491,6 +498,13 @@ function ReaderBookmark:updateBookmark(item)
for i=1, #self.bookmarks do
if item.datetime == self.bookmarks[i].datetime and item.page == self.bookmarks[i].page then
local page = self.ui.document:getPageFromXPointer(item.updated_highlight.pos0)
if self.ui.document:hasHiddenFlows() then
local flow = self.ui.document:getPageFlow(page)
page = self.ui.document:getPageNumberInFlow(page)
if flow > 0 then
page = T("[%1]%2", page, flow)
end
end
local new_text = item.updated_highlight.text
self.bookmarks[i].page = item.updated_highlight.pos0
self.bookmarks[i].pos0 = item.updated_highlight.pos0
@ -517,6 +531,13 @@ function ReaderBookmark:renameBookmark(item, from_highlight)
local page = item.page
if not self.ui.document.info.has_pages then
page = self.ui.document:getPageFromXPointer(page)
if self.ui.document:hasHiddenFlows() then
local flow = self.ui.document:getPageFlow(page)
page = self.ui.document:getPageNumberInFlow(page)
if flow > 0 then
page = T("[%1]%2", page, flow)
end
end
end
item.text = T(_("Page %1 %2 @ %3"), page, item.notes, item.datetime)
end

@ -191,7 +191,19 @@ local footerTextGeneratorMap = {
return ("%s / %s"):format(footer.ui.pagemap:getCurrentPageLabel(true),
footer.ui.pagemap:getLastPageLabel(true))
end
return ("%d / %d"):format(footer.pageno, footer.pages)
if footer.ui.document:hasHiddenFlows() then
-- i.e., if we are hiding non-linear fragments and there's anything to hide,
local flow = footer.ui.document:getPageFlow(footer.pageno)
local page = footer.ui.document:getPageNumberInFlow(footer.pageno)
local pages = footer.ui.document:getTotalPagesInFlow(flow)
if flow == 0 then
return ("%d // %d"):format(page, pages)
else
return ("[%d / %d]%d"):format(page, pages, flow)
end
else
return ("%d / %d"):format(footer.pageno, footer.pages)
end
elseif footer.position then
return ("%d / %d"):format(footer.position, footer.doc_height)
end
@ -200,32 +212,36 @@ local footerTextGeneratorMap = {
local symbol_type = footer.settings.item_prefix or "icons"
local prefix = symbol_prefix[symbol_type].pages_left
local left = footer.ui.toc:getChapterPagesLeft(footer.pageno)
return prefix .. " " .. (left and left or footer.pages - footer.pageno)
return prefix .. " " .. (left or footer.ui.document:getTotalPagesLeft(footer.pageno))
end,
percentage = function(footer)
local symbol_type = footer.settings.item_prefix or "icons"
local prefix = symbol_prefix[symbol_type].percentage
local digits = footer.settings.progress_pct_format or "0"
local string_percentage
if not prefix then
string_percentage = "%." .. digits .. "f%%"
else
string_percentage = prefix .. " %." .. digits .. "f%%"
local string_percentage = "%." .. digits .. "f%%"
if footer.ui.document:hasHiddenFlows() then
local flow = footer.ui.document:getPageFlow(footer.pageno)
if flow ~= 0 then
string_percentage = "[" .. string_percentage .. "]"
end
end
if prefix then
string_percentage = prefix .. " " .. string_percentage
end
return string_percentage:format(footer.progress_bar.percentage * 100)
end,
book_time_to_read = function(footer)
local symbol_type = footer.settings.item_prefix or "icons"
local prefix = symbol_prefix[symbol_type].book_time_to_read
local current_page = footer.ui:getCurrentPage()
return footer:getDataFromStatistics(prefix .. " ", footer.pages - current_page)
local left = footer.ui.document:getTotalPagesLeft(footer.pageno)
return footer:getDataFromStatistics(prefix .. " ", left)
end,
chapter_time_to_read = function(footer)
local symbol_type = footer.settings.item_prefix or "icons"
local prefix = symbol_prefix[symbol_type].chapter_time_to_read
local left = footer.ui.toc:getChapterPagesLeft(footer.pageno)
return footer:getDataFromStatistics(
prefix .. " ", (left and left or footer.pages - footer.pageno))
prefix .. " ", (left or footer.ui.document:getTotalPagesLeft(footer.pageno)))
end,
mem_usage = function(footer)
local symbol_type = footer.settings.item_prefix or "icons"
@ -1724,18 +1740,44 @@ function ReaderFooter:setTocMarkers(reset)
if self.settings.disable_progress_bar or self.settings.progress_style_thin then return end
if reset then
self.progress_bar.ticks = nil
self.pages = self.view.document:getPageCount()
self.pages = self.ui.document:getPageCount()
end
if self.settings.toc_markers then
self.progress_bar.tick_width = Screen:scaleBySize(self.settings.toc_markers_width)
if self.progress_bar.ticks ~= nil then -- already computed
return
end
self.progress_bar.ticks = {}
if self.ui.toc then
self.progress_bar.ticks = self.ui.toc:getTocTicksFlattened()
if self.ui.document:hasHiddenFlows() and self.pageno then
local flow = self.ui.document:getPageFlow(self.pageno)
self.progress_bar.ticks = {}
if self.ui.toc then
-- filter the ticks to show only those in the current flow
for n, pageno in ipairs(self.ui.toc:getTocTicksFlattened()) do
if self.ui.document:getPageFlow(pageno) == flow then
table.insert(self.progress_bar.ticks, self.ui.document:getPageNumberInFlow(pageno))
end
end
end
self.progress_bar.last = self.ui.document:getTotalPagesInFlow(flow)
else
if self.ui.toc then
self.progress_bar.ticks = self.ui.toc:getTocTicksFlattened()
end
if self.view.view_mode == "page" then
self.progress_bar.last = self.pages or self.ui.document:getPageCount()
else
-- in scroll mode, convert pages to positions
if self.ui.toc then
self.progress_bar.ticks = {}
for n, pageno in ipairs(self.ui.toc:getTocTicksFlattened()) do
local idx = self.ui.toc:getTocIndexByPage(pageno)
local pos = self.ui.document:getPosFromXPointer(self.ui.toc.toc[idx].xpointer)
table.insert(self.progress_bar.ticks, pos)
end
end
self.progress_bar.last = self.doc_height or self.ui.document.info.doc_height
end
end
self.progress_bar.last = self.pages or self.view.document:getPageCount()
else
self.progress_bar.ticks = nil
end
@ -1770,7 +1812,14 @@ end
function ReaderFooter:updateFooterPage(force_repaint, force_recompute)
if type(self.pageno) ~= "number" then return end
self.progress_bar.percentage = self.pageno / self.pages
if self.ui.document:hasHiddenFlows() then
local flow = self.ui.document:getPageFlow(self.pageno)
local page = self.ui.document:getPageNumberInFlow(self.pageno)
local pages = self.ui.document:getTotalPagesInFlow(flow)
self.progress_bar.percentage = page / pages
else
self.progress_bar.percentage = self.pageno / self.pages
end
self:updateFooterText(force_repaint, force_recompute)
end
@ -1882,19 +1931,39 @@ function ReaderFooter:_updateFooterText(force_repaint, force_recompute)
end
end
function ReaderFooter:onTocReset()
self:setTocMarkers(true)
if self.view.view_mode == "page" then
self:updateFooterPage()
else
self:updateFooterPos()
end
end
function ReaderFooter:onPageUpdate(pageno)
local toc_markers_update = false
if self.ui.document:hasHiddenFlows() then
local flow = self.pageno and self.ui.document:getPageFlow(self.pageno)
local new_flow = pageno and self.ui.document:getPageFlow(pageno)
if pageno and new_flow ~= flow then
toc_markers_update = true
end
end
self.pageno = pageno
self.pages = self.view.document:getPageCount()
self.pages = self.ui.document:getPageCount()
if toc_markers_update then
self:setTocMarkers(true)
end
self.ui.doc_settings:saveSetting("doc_pages", self.pages) -- for Book information
self:updateFooterPage()
end
function ReaderFooter:onPosUpdate(pos, pageno)
self.position = pos
self.doc_height = self.view.document.info.doc_height
self.doc_height = self.ui.document.info.doc_height
if pageno then
self.pageno = pageno
self.pages = self.view.document:getPageCount()
self.pages = self.ui.document:getPageCount()
self.ui.doc_settings:saveSetting("doc_pages", self.pages) -- for Book information
end
self:updateFooterPos()
@ -2065,7 +2134,7 @@ function ReaderFooter:refreshFooter(refresh, signal)
-- We *do* need to ensure we at least re-compute the footer layout, though, especially when going from visible to invisible...
self:onUpdateFooter(refresh and not signal, refresh and signal)
if signal then
self.ui:handleEvent(Event:new("SetPageBottomMargin", self.view.document.configurable.b_page_margin))
self.ui:handleEvent(Event:new("SetPageBottomMargin", self.ui.document.configurable.b_page_margin))
end
end

@ -62,6 +62,12 @@ function ReaderGoto:onShowGotoDialog()
self.goto_dialog = InputDialog:new{
title = dialog_title,
input_hint = input_hint,
description = self.document:hasHiddenFlows() and
_([[
x for an absolute page number
[x] for a page number in the main (linear) flow
[x]y for a page number in the non-linear fragment y]])
or nil,
buttons = {
{
{
@ -134,20 +140,51 @@ function ReaderGoto:gotoPage()
end
end
self:close()
elseif self.ui.document:hasHiddenFlows() then
-- if there are hidden flows, we accept the syntax [x]y
-- for page number x in flow number y (y defaults to 0 if not present)
local flow
number, flow = string.match(page_number, "^ *%[(%d+)%](%d*) *$")
flow = tonumber(flow) or 0
number = tonumber(number)
if number then
if self.ui.document.flows[flow] ~= nil then
if number < 1 or number > self.ui.document:getTotalPagesInFlow(flow) then
return
end
local page = 0
-- in flow 0 (linear), we count pages skipping non-linear flows,
-- in a non-linear flow the target page is immediate
if flow == 0 then
for i=1, number do
page = self.ui.document:getNextPage(page)
end
else
page = self.ui.document:getFirstPageInFlow(flow) + number - 1
end
if page > 0 then
self.ui:handleEvent(Event:new("GotoPage", page))
self:close()
end
end
end
end
end
function ReaderGoto:onGoToBeginning()
self.ui.link:addCurrentLocationToStack()
self.ui:handleEvent(Event:new("GotoPage", 1))
local new_page = self.ui.document:getNextPage(0)
if new_page then
self.ui.link:addCurrentLocationToStack()
self.ui:handleEvent(Event:new("GotoPage", new_page))
end
return true
end
function ReaderGoto:onGoToEnd()
local endpage = self.document:getPageCount()
if endpage then
local new_page = self.ui.document:getPrevPage(0)
if new_page then
self.ui.link:addCurrentLocationToStack()
self.ui:handleEvent(Event:new("GotoPage", endpage))
self.ui:handleEvent(Event:new("GotoPage", new_page))
end
return true
end

@ -1034,7 +1034,7 @@ end
-- mode, and other zoom modes than Fit page
function ReaderPaging:onGotoNextChapter()
local pageno = self.current_page
local new_page = self.ui.toc:getNextChapter(pageno, 0)
local new_page = self.ui.toc:getNextChapter(pageno)
if new_page then
self.ui.link:addCurrentLocationToStack()
self:onGotoPage(new_page)
@ -1044,7 +1044,7 @@ end
function ReaderPaging:onGotoPrevChapter()
local pageno = self.current_page
local new_page = self.ui.toc:getPreviousChapter(pageno, 0)
local new_page = self.ui.toc:getPreviousChapter(pageno)
if new_page then
self.ui.link:addCurrentLocationToStack()
self:onGotoPage(new_page)

@ -55,7 +55,8 @@ local ReaderRolling = InputContainer:new{
-- With visible_pages=2, in 2-pages mode, ensure the first
-- page is always odd or even (odd is logical to avoid a
-- same page when turning first 2-pages set of document)
odd_or_even_first_page = 1 -- 1 = odd, 2 = even, nil or others = free
odd_or_even_first_page = 1, -- 1 = odd, 2 = even, nil or others = free
hide_nonlinear_flows = nil,
}
function ReaderRolling:init()
@ -206,7 +207,7 @@ function ReaderRolling:onReadSettings(config)
self.setupXpointer = function()
self.xpointer = self.ui.document:getXPointer()
if self.view.view_mode == "page" then
self.ui:handleEvent(Event:new("PageUpdate", 1))
self.ui:handleEvent(Event:new("PageUpdate", self.ui.document:getNextPage(0)))
end
end
end
@ -230,6 +231,12 @@ function ReaderRolling:onReadSettings(config)
G_reader_settings:readSetting("copt_visible_pages") or 1
self.ui.document:setVisiblePageCount(self.visible_pages)
self.hide_nonlinear_flows = config:readSetting("hide_nonlinear_flows")
if self.hide_nonlinear_flows == nil then
self.hide_nonlinear_flows = G_reader_settings:isTrue("hide_nonlinear_flows")
end
self.ui.document:setHideNonlinearFlows(self.hide_nonlinear_flows)
-- Set a callback to allow showing load and rendering progress
-- (this callback will be cleaned up by cre.cpp closeDocument(),
-- no need to handle it in :onCloseDocument() here.)
@ -302,10 +309,14 @@ function ReaderRolling:onSaveSettings()
self.ui.doc_settings:saveSetting("show_overlap_enable", self.show_overlap_enable)
self.ui.doc_settings:saveSetting("inverse_reading_order", self.inverse_reading_order)
self.ui.doc_settings:saveSetting("visible_pages", self.visible_pages)
self.ui.doc_settings:saveSetting("hide_nonlinear_flows", self.hide_nonlinear_flows)
end
function ReaderRolling:onReaderReady()
self:setupTouchZones()
if self.hide_nonlinear_flows then
self.ui.document:cacheFlows()
end
self.setupXpointer()
end
@ -457,6 +468,31 @@ You can set how many lines are shown.]])
help_text = _([[When page overlap is enabled, some lines from the previous pages are shown on the next page.]]),
sub_item_table = page_overlap_menu,
}
if self.ui.document:hasNonLinearFlows() then
local hide_nonlinear_text = _("When this option is enabled, if a document contains non-linear fragments, they will be hidden from the normal page flow, but they are still accessible through links, Toc or Go to. This currently works only in single-page, non-scrolling mode.")
menu_items.hide_nonlinear_flows = {
text = _("Hide non-linear fragments"),
enabled_func = function()
return self.view.view_mode == "page" and self.ui.document:getVisiblePageCount() == 1
end,
checked_func = function() return self.hide_nonlinear_flows end,
callback = function()
self:onToggleHideNonlinear()
end,
hold_callback = function()
UIManager:show(ConfirmBox:new{
text = T(
hide_nonlinear_text .. _("\n\nSet default hide non-linear fragments to %1?"),
self.hide_nonlinear_flows and _("enabled") or _("disabled")
),
ok_callback = function()
G_reader_settings:saveSetting("hide_nonlinear_flows", self.hide_nonlinear_flows)
end,
})
end,
help_text = hide_nonlinear_text,
}
end
end
function ReaderRolling:getLastPercent()
@ -526,8 +562,18 @@ end
function ReaderRolling:onGotoNextChapter()
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
local new_page
if self.ui.document:hasHiddenFlows() then
-- Find next chapter start
new_page = self.ui.document:getNextPage(pageno)
while new_page > 0 do
if self.ui.toc:isChapterStart(new_page) then break end
new_page = self.ui.document:getNextPage(new_page)
end
else
new_page = self.ui.toc:getNextChapter(pageno) or 0
end
if new_page > 0 then
self.ui.link:addCurrentLocationToStack()
self:onGotoPage(new_page)
end
@ -536,8 +582,18 @@ end
function ReaderRolling:onGotoPrevChapter()
local pageno = self.current_page
local new_page = self.ui.toc:getPreviousChapter(pageno, 0)
if new_page then
local new_page
if self.ui.document:hasHiddenFlows() then
-- Find previous chapter start
new_page = self.ui.document:getPrevPage(pageno)
while new_page > 0 do
if self.ui.toc:isChapterStart(new_page) then break end
new_page = self.ui.document:getPrevPage(new_page)
end
else
new_page = self.ui.toc:getPreviousChapter(pageno) or 0
end
if new_page > 0 then
self.ui.link:addCurrentLocationToStack()
self:onGotoPage(new_page)
end
@ -721,7 +777,23 @@ function ReaderRolling:onGotoViewRel(diff)
else
diff = math.floor(diff)
end
self:_gotoPage(self.current_page + diff*page_count)
local new_page = self.current_page
if self.ui.document:hasHiddenFlows() then
local test_page
for i=1, math.abs(diff*page_count) do
if diff > 0 then
test_page = self.ui.document:getNextPage(new_page)
else
test_page = self.ui.document:getPrevPage(new_page)
end
if test_page > 0 then
new_page = test_page
end
end
else
new_page = new_page + diff*page_count
end
self:_gotoPage(new_page)
if diff > 0 and old_page == self.current_page then
self.ui:handleEvent(Event:new("EndOfBook"))
end
@ -783,12 +855,13 @@ function ReaderRolling:updatePos()
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
if self.hide_nonlinear_flows then
self.ui.document:cacheFlows()
end
self:_gotoXPointer(self.xpointer)
self.old_doc_height = new_height
self.old_page = new_page
self.ui:handleEvent(Event:new("UpdateToc"))
self.view.footer:setTocMarkers(true)
self.view.footer:onUpdateFooter()
end
self:updateTopStatusBarMarkers()
UIManager:setDirty(self.view.dialog, "partial")
@ -808,7 +881,6 @@ function ReaderRolling:onChangeViewMode()
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"))
self.view.footer:setTocMarkers(true)
if self.xpointer then
self:_gotoXPointer(self.xpointer)
-- Ensure a whole screen refresh is always enqueued
@ -1310,6 +1382,20 @@ Note that %1 (out of %2) xpaths from your bookmarks and highlights have been nor
})
end
function ReaderRolling:onToggleHideNonlinear()
self.hide_nonlinear_flows = not self.hide_nonlinear_flows
self.ui.document:setHideNonlinearFlows(self.hide_nonlinear_flows)
-- The document may change due to forced pagebreaks between flows being
-- added or removed, so we need to find our location
self:onUpdatePos()
-- Even if the document doesn't change, we must ensure that the
-- flow and call caches are cleared, to get the right page numbers,
-- which may have changed, and the correct flow structure. Also,
-- the footer needs updating, and TOC markers may come or go.
self.ui.document:cacheFlows()
self.ui:handleEvent(Event:new("UpdateToc"))
end
-- Duplicated in ReaderPaging
function ReaderRolling:onToggleReadingOrder()
self.inverse_reading_order = not self.inverse_reading_order

@ -62,6 +62,7 @@ end
function ReaderToc:onUpdateToc()
self:resetToc()
self.ui:handleEvent(Event:new("TocReset"))
--- @note: Let this propagate, plugins/statistics uses it to react to changes in document pagination
--return true
@ -168,25 +169,35 @@ function ReaderToc:validateAndFixToc()
nb_bogus = nb_bogus + 1
-- See how many pages we'd need fixing on either side
local nb_prev = 0
local nb_prev_main = 0
for j = i-1, first, -1 do
local ppage = toc[j].fixed_page or toc[j].page
if ppage <= page then
break
else
nb_prev = nb_prev + 1
if self.ui.document:getPageFlow(ppage) == 0 then
nb_prev_main = nb_prev_main + 1
end
end
end
local nb_next = 1
for j = i+1, last do
local nb_next = 0
local nb_next_main = 0
for j = i, last do
local npage = toc[j].fixed_page or toc[j].page
if npage >= cur_page then
break
else
nb_next = nb_next + 1
if self.ui.document:getPageFlow(npage) == 0 then
nb_next_main = nb_next_main + 1
end
end
end
logger.dbg("BOGUS TOC:", i, page, "<", i-1, cur_page, "-", nb_prev, nb_next)
if nb_prev <= nb_next then -- less changes when fixing previous pages
-- Note: by comparing only the entries that belong to the main (linear) flow
-- we give priority to moving non-linear bogus entries
if nb_prev_main <= nb_next_main then -- less changes when fixing previous pages
local fixed_page
if i-nb_prev-1 >= 1 then
fixed_page = toc[i-nb_prev-1].fixed_page or toc[i-nb_prev-1].page
@ -436,21 +447,46 @@ function ReaderToc:isChapterEnd(cur_pageno)
end
function ReaderToc:getChapterPagesLeft(pageno)
--if self:isChapterEnd(pageno) then return 0 end
local next_chapter = self:getNextChapter(pageno)
if next_chapter then
next_chapter = next_chapter - pageno - 1
if self.ui.document:hasHiddenFlows() then
-- Count pages until new chapter
local pages_left = 0
local test_page = self.ui.document:getNextPage(pageno)
while test_page > 0 do
pages_left = pages_left + 1
if self:isChapterStart(test_page) then
return pages_left - 1
end
test_page = self.ui.document:getNextPage(test_page)
end
else
local next_chapter = self:getNextChapter(pageno)
if next_chapter then
next_chapter = next_chapter - pageno - 1
end
return next_chapter
end
return next_chapter
end
function ReaderToc:getChapterPagesDone(pageno)
if self:isChapterStart(pageno) then return 0 end
local previous_chapter = self:getPreviousChapter(pageno)
if previous_chapter then
previous_chapter = pageno - previous_chapter
if self.ui.document:hasHiddenFlows() then
-- Count pages until chapter start
local pages_done = 0
local test_page = self.ui.document:getPrevPage(pageno)
while test_page > 0 do
pages_done = pages_done + 1
if self:isChapterStart(test_page) then
return pages_done
end
test_page = self.ui.document:getPrevPage(test_page)
end
else
local previous_chapter = self:getPreviousChapter(pageno)
if previous_chapter then
previous_chapter = pageno - previous_chapter
end
return previous_chapter
end
return previous_chapter
end
function ReaderToc:updateCurrentNode()
@ -489,7 +525,34 @@ function ReaderToc:onShowToc()
for _,v in ipairs(self.toc) do
v.text = self.toc_indent:rep(v.depth-1)..self:cleanUpTocTitle(v.title)
v.mandatory = v.page
if v.orig_page then -- bogus page fixed: show original page number
if self.ui.document:hasHiddenFlows() then
local flow = self.ui.document:getPageFlow(v.page)
if v.orig_page then -- bogus page fixed: show original page number
-- This is an ugly piece of code, which can result in an ugly TOC,
-- but it shouldn't be needed very often, only when bogus page numbers
-- are fixed, and then showing everything gets complicated
local orig_flow = self.ui.document:getPageFlow(v.orig_page)
if flow == 0 and orig_flow == flow then
v.mandatory = T("(%1) %2", self.ui.document:getPageNumberInFlow(v.orig_page), self.ui.document:getPageNumberInFlow(v.page))
elseif flow == 0 and orig_flow ~= flow then
v.mandatory = T("[%1]%2", self.ui.document:getPageNumberInFlow(v.orig_page), self.ui.document:getPageFlow(v.orig_page))
elseif flow > 0 and orig_flow == flow then
v.mandatory = T("[(%1) %2]%3", self.ui.document:getPageNumberInFlow(v.orig_page),
self.ui.document:getPageNumberInFlow(v.page), self.ui.document:getPageFlow(v.page))
else
v.mandatory = T("([%1]%2) [%3]%4", self.ui.document:getPageNumberInFlow(v.orig_page), self.ui.document:getPageFlow(v.orig_page),
self.ui.document:getPageNumberInFlow(v.page), self.ui.document:getPageFlow(v.page))
end
else
-- Plain numbers for the linear entries,
-- for non-linear entries we use the same syntax as in the Go to dialog
if flow == 0 then
v.mandatory = self.ui.document:getPageNumberInFlow(v.page)
else
v.mandatory = T("[%1]%2", self.ui.document:getPageNumberInFlow(v.page), self.ui.document:getPageFlow(v.page))
end
end
elseif v.orig_page then -- bogus page fixed: show original page number
v.mandatory = T("(%1) %2", v.orig_page, v.page)
end
if self.ui.pagemap and self.ui.pagemap:wantsPageLabels() then

@ -92,6 +92,7 @@ function SkimToWidget:init()
ticks = self.ticks_flattened,
tick_width = Size.line.medium,
last = self.page_count,
alt = self.ui.document.flows,
}
self.skimto_progress = FrameContainer:new{
padding = Size.padding.button,

@ -58,6 +58,11 @@ local CreDocument = Document:new{
default_css = "./data/cr3.css",
provider = "crengine",
provider_name = "Cool Reader Engine",
hide_nonlinear_flows = false,
flows = {},
page_in_flow = {},
last_linear_page = nil,
}
-- NuPogodi, 20.05.12: inspect the zipfile content
@ -283,10 +288,188 @@ function CreDocument:updateColorRendering()
end
end
function CreDocument:setHideNonlinearFlows(hide_nonlinear_flows)
if hide_nonlinear_flows ~= self.hide_nonlinear_flows then
self.hide_nonlinear_flows = hide_nonlinear_flows
self._document:setIntProperty("crengine.doc.nonlinear.pagebreak.force", self.hide_nonlinear_flows and 1 or 0)
end
end
function CreDocument:getPageCount()
return self._document:getPages()
end
-- Whether the document has any non-linear flow to care about
function CreDocument:hasNonLinearFlows()
return self._document:hasNonLinearFlows()
end
-- Whether non-linear flows (if any) will be hidden
function CreDocument:hasHiddenFlows()
return self.flows[1] ~= nil
end
-- Get the next/prev page number, skipping non-linear flows,
-- i.e. the next/prev page that is either in the current
-- flow or in the linear flow (flow 0)
-- If "page" is 0, these give the initial and final linear pages
function CreDocument:getNextPage(page)
if self:hasHiddenFlows() then
if page < 0 or page >= self:getPageCount() then
return 0
elseif page == 0 then
return self:getFirstPageInFlow(0)
end
local flow = self:getPageFlow(page)
local start_page = page + 1
local end_page = self:getLastLinearPage()
local test_page = start_page
-- max to ensure at least one iteration
-- (in case the current flow goes after all linear pages)
while test_page <= math.max(end_page, start_page) do
local test_page_flow = self:getPageFlow(test_page)
if test_page_flow == flow or test_page_flow == 0 then
-- same flow as current, or linear flow, this is a "good" page
return test_page
elseif test_page_flow > 0 then
-- some other non-linear flow, skip all pages in this flow
test_page = test_page + self:getTotalPagesInFlow(test_page_flow)
else
-- went beyond the last page
break
end
end
return 0
else
return Document.getNextPage(self, page)
end
end
function CreDocument:getPrevPage(page)
if self:hasHiddenFlows() then
if page < 0 or page > self:getPageCount() then
return 0
elseif page == 0 then
return self:getLastLinearPage()
end
local flow = self:getPageFlow(page)
local start_page = page - 1
local end_page = self:getFirstPageInFlow(0)
local test_page = start_page
-- min to ensure at least one iteration
-- (in case the current flow goes before all linear pages)
while test_page >= math.min(end_page, start_page) do
local test_page_flow = self:getPageFlow(test_page)
if test_page_flow == flow or test_page_flow == 0 then
-- same flow as current, or linear flow, this is a "good" page
return test_page
elseif test_page_flow > 0 then
-- some other non-linear flow, skip all pages in this flow
test_page = self:getFirstPageInFlow(test_page_flow) - 1
else
-- went beyond the first page
break
end
end
return 0
else
return Document.getPrevPage(self, page)
end
end
function CreDocument:getPageFlow(page)
-- Only report non-linear pages if "hide_nonlinear_flows" is enabled, and in 1-page mode,
-- otherwise all pages are linear (flow 0)
if self.hide_nonlinear_flows and self._view_mode == self.PAGE_VIEW_MODE and self:getVisiblePageCount() == 1 then
return self._document:getPageFlow(page)
else
return 0
end
end
function CreDocument:getLastLinearPage()
return self.last_linear_page
end
function CreDocument:getFirstPageInFlow(flow)
return self.flows[flow][1]
end
function CreDocument:getTotalPagesInFlow(flow)
return self.flows[flow][2]
end
function CreDocument:getPageNumberInFlow(page)
if self:hasHiddenFlows() then
return self.page_in_flow[page]
else
return page
end
end
function CreDocument:cacheFlows()
-- Build the cache tables "flows" and "page_in_flow", if there are
-- any non-linear flows in the source document. Also set the value
-- of "last_linear_page", to possibly speed up counting in documents
-- with many non-linear pages at the end.
-- flows[i] contains {ini, num}, where ini is the first page in flow i,
-- and num is the total number of pages in the flow.
-- page_in_flow[i] contains the number of page i with its flow.
--
-- So, flows[0][1] is the first page in the linear flow,
-- and page_in_flow[flows[0][1]] must be 1, because it is the first
self.flows = {}
self.page_in_flow = {}
if self:hasNonLinearFlows() and self.hide_nonlinear_flows then
for i=1,self:getPageCount() do
local flow = self:getPageFlow(i)
if self.flows[flow] ~= nil then
self.flows[flow][2] = self.flows[flow][2]+1
else
self.flows[flow] = {i, 1}
end
self.page_in_flow[i] = self.flows[flow][2]
if flow == 0 then
self.last_linear_page = i
end
end
else
self.last_linear_page = self:getPageCount()
self.flows[0] = {1, self.last_linear_page}
end
end
function CreDocument:getTotalPagesLeft(page)
if self:hasHiddenFlows() then
local pages_left
local last_linear = self:getLastLinearPage()
if page > last_linear then
-- If beyond the last linear page, count only the pages in the current flow
local flow = self:getPageFlow(page)
pages_left = self:getTotalPagesInFlow(flow) - self:getPageNumberInFlow(page)
else
-- Otherwise, count all pages until the last linear,
-- except the flows that start (and end) between
-- the current page and the last linear
pages_left = last_linear - page
for flow, tab in ipairs(self.flows) do
-- tab[1] is the initial page of the flow
-- tab[2] is the total number of pages in the flow
if tab[1] > last_linear then
break
end
-- strict >, to make sure we include pages in the current flow
if tab[1] > page then
pages_left = pages_left - tab[2]
end
end
end
return pages_left
else
return Document.getTotalPagesLeft(self, page)
end
end
function CreDocument:getCoverPageImage()
-- no need to render document in order to get cover image
if not self:loadDocument() then
@ -578,7 +761,7 @@ function CreDocument:gotoPos(pos)
end
function CreDocument:gotoPage(page)
logger.dbg("CreDocument: goto page", page)
logger.dbg("CreDocument: goto page", page, "flow", self:getPageFlow(page))
self._document:gotoPage(page)
end
@ -766,6 +949,9 @@ function CreDocument:setViewMode(new_mode)
self._view_mode = self.PAGE_VIEW_MODE
end
self._document:setViewMode(self._view_mode)
if self.hide_nonlinear_flows then
self:cacheFlows()
end
end
end
@ -1272,6 +1458,7 @@ function CreDocument:setupCallCache()
elseif name:sub(1,6) == "enable" then add_reset = true
elseif name == "zoomFont" then add_reset = true -- not used by koreader
elseif name == "resetCallCache" then add_reset = true
elseif name == "cacheFlows" then add_reset = true
-- These may have crengine do native highlight or unhighlight
-- (we could keep the original buffer and use a scratch buffer while
@ -1313,6 +1500,11 @@ function CreDocument:setupCallCache()
elseif name == "getCacheFilePath" then no_wrap = true
elseif name == "getStatistics" then no_wrap = true
elseif name == "getNormalizedXPointer" then no_wrap = true
elseif name == "getNextPage" then no_wrap = true
elseif name == "getPrevPage" then no_wrap = true
elseif name == "getPageFlow" then no_wrap = true
elseif name == "getPageNumberInFlow" then no_wrap = true
elseif name == "getTotalPagesLeft" then no_wrap = true
-- Some get* have different results by page/pos
elseif name == "getLinkFromPosition" then cache_by_tag = true

@ -188,6 +188,48 @@ function Document:getPageCount()
return self.info.number_of_pages
end
-- Some functions that look quite silly, but they can be
-- overridden for document types that support separate flows
-- (e.g. CreDocument)
function Document:hasNonLinearFlows()
return false
end
function Document:hasHiddenFlows()
return false
end
function Document:getNextPage(page)
local new_page = page + 1
return (new_page > 0 and new_page < self.info.number_of_pages) and new_page or 0
end
function Document:getPrevPage(page)
if page == 0 then return self.info.number_of_pages end
local new_page = page - 1
return (new_page > 0 and new_page < self.info.number_of_pages) and new_page or 0
end
function Document:getTotalPagesLeft(page)
return self.info.number_of_pages - page
end
function Document:getPageFlow(page)
return 0
end
function Document:getFirstPageInFlow(flow)
return 1
end
function Document:getTotalPagesInFlow(flow)
return self.info.number_of_pages
end
function Document:getPageNumberInFlow(page)
return page
end
-- calculates page dimensions
function Document:getPageDimensions(pageno, zoom, rotation)
local native_dimen = self:getNativePageDimensions(pageno):copy()

@ -16,6 +16,7 @@ local order = {
"toggle_bookmark",
"bookmark_browsing_mode",
"page_map",
"hide_nonlinear_flows",
"----------------------------",
"go_to",
"skim_to",

@ -11,7 +11,8 @@ Configurable attributes:
* bordersize
* bordercolor
* bgcolor
* rectcolor -- infill color
* altcolor -- alternate backrgound color for "alt" pages
* rectdim -- dim amount for infill
* ticks (list) -- default to nil, use this if you want to insert markers
* tick_width
* last -- maximum tick, used with ticks
@ -42,13 +43,15 @@ local ProgressWidget = Widget:new{
bordersize = Screen:scaleBySize(1),
bordercolor = Blitbuffer.COLOR_BLACK,
bgcolor = Blitbuffer.COLOR_WHITE,
rectcolor = Blitbuffer.COLOR_DIM_GRAY,
altcolor = Blitbuffer.COLOR_LIGHT_GRAY,
rectdim = 2/3,
percentage = nil,
ticks = nil,
tick_width = Screen:scaleBySize(3),
last = nil,
fill_from_right = false,
allow_mirroring = true,
alt = nil, -- table with alternate pages to mark with different color (in the form {{ini1, len1}, {ini2, len2}, ...})
_mirroredUI = BD.mirroredUILayout(),
_orig_margin_v = nil,
_orig_bordersize = nil,
@ -73,27 +76,52 @@ function ProgressWidget:paintTo(bb, x, y)
bb:paintBorder(x, y,
my_size.w, my_size.h,
self.bordersize, self.bordercolor, self.radius)
-- background for alternate pages (e.g. non-linear flows)
if self.alt and self.alt[1] ~= nil then
local bar_width = (my_size.w-2*self.margin_h)
local y_pos = y + self.margin_v + self.bordersize
local bar_height = my_size.h-2*(self.margin_v+self.bordersize)
for i=1, #self.alt do
local tick_x = bar_width*((self.alt[i][1]-1)/self.last)
local width = bar_width*(self.alt[i][2]/self.last)
width = math.ceil(tick_x + width)
tick_x = math.floor(tick_x)
width = width - tick_x
if self._mirroredUI then
tick_x = bar_width - tick_x - width
end
bb:paintRect(
x + self.margin_h + tick_x,
y_pos,
width,
bar_height,
self.altcolor)
end
end
-- paint percentage infill
-- note that "lightenRect" is misleading, it actualy darkens stuff
if self.percentage >= 0 and self.percentage <= 1 then
if self.fill_from_right or (self._mirroredUI and not self.fill_from_right) then
bb:paintRect(x+self.margin_h + math.ceil((my_size.w-2*self.margin_h)*(1-self.percentage)),
bb:lightenRect(x+self.margin_h + math.ceil((my_size.w-2*self.margin_h)*(1-self.percentage)),
math.ceil(y+self.margin_v+self.bordersize),
math.ceil((my_size.w-2*self.margin_h)*self.percentage),
my_size.h-2*(self.margin_v+self.bordersize),
self.rectcolor)
self.rectdim)
else
bb:paintRect(x+self.margin_h,
bb:lightenRect(x+self.margin_h,
math.ceil(y+self.margin_v+self.bordersize),
math.ceil((my_size.w-2*self.margin_h)*self.percentage),
my_size.h-2*(self.margin_v+self.bordersize), self.rectcolor)
my_size.h-2*(self.margin_v+self.bordersize),
self.rectdim)
end
end
-- ticks
if self.ticks and self.last and self.last > 0 then
local bar_width = (my_size.w-2*self.margin_h)
local y_pos = y + self.margin_v + self.bordersize
local bar_height = my_size.h-2*(self.margin_v+self.bordersize)
for i=1, #self.ticks do
local tick_x = bar_width*(self.ticks[i]/self.last)
for i, tick in ipairs(self.ticks) do
local tick_x = bar_width*(tick/self.last)
if self._mirroredUI then
tick_x = bar_width - tick_x
end

Loading…
Cancel
Save