BookMap: add "Overview" mode

Add a restricted but convenient mode showing BookMap like
in initial view, while still allowing chapter levels to be
tweaked. This allows getting back to this view with another
gesture to see the overall progress in the book, while
still having the normal BookMap in flat mode acting as
an alternative ToC.
Available as an action to associate to a gesture, and
with long-press on the "Book map" menu item.
reviewable/pr10544/r1
poire-z 12 months ago
parent b7078caf29
commit 04425b74fc

@ -68,6 +68,12 @@ function ReaderThumbnail:addToMainMenu(menu_items)
callback = function() callback = function()
self:onShowBookMap() self:onShowBookMap()
end, end,
-- Show the alternative overview mode (which is just a restricted
-- variation of the main book map) with long-press (let's avoid
-- adding another item in the crowded first menu).
hold_callback = function()
self:onShowBookMap(true)
end,
} }
menu_items.page_browser = { menu_items.page_browser = {
text = _("Page browser"), text = _("Page browser"),
@ -77,10 +83,11 @@ function ReaderThumbnail:addToMainMenu(menu_items)
} }
end end
function ReaderThumbnail:onShowBookMap() function ReaderThumbnail:onShowBookMap(overview_mode)
local BookMapWidget = require("ui/widget/bookmapwidget") local BookMapWidget = require("ui/widget/bookmapwidget")
UIManager:show(BookMapWidget:new{ UIManager:show(BookMapWidget:new{
ui = self.ui, ui = self.ui,
overview_mode = overview_mode,
}) })
return true return true
end end

@ -141,6 +141,7 @@ local settingsList = {
toc = {category="none", event="ShowToc", title=_("Table of contents"), reader=true}, toc = {category="none", event="ShowToc", title=_("Table of contents"), reader=true},
book_map = {category="none", event="ShowBookMap", title=_("Book map"), reader=true, condition=Device:isTouchDevice()}, book_map = {category="none", event="ShowBookMap", title=_("Book map"), reader=true, condition=Device:isTouchDevice()},
book_map_overview = {category="none", event="ShowBookMap", arg=true, title=_("Book map (overview)"), reader=true, condition=Device:isTouchDevice()},
page_browser = {category="none", event="ShowPageBrowser", title=_("Page browser"), reader=true, condition=Device:isTouchDevice()}, page_browser = {category="none", event="ShowPageBrowser", title=_("Page browser"), reader=true, condition=Device:isTouchDevice()},
bookmarks = {category="none", event="ShowBookmark", title=_("Bookmarks"), reader=true}, bookmarks = {category="none", event="ShowBookmark", title=_("Bookmarks"), reader=true},
bookmark_search = {category="none", event="SearchBookmark", title=_("Bookmark search"), reader=true}, bookmark_search = {category="none", event="SearchBookmark", title=_("Bookmark search"), reader=true},
@ -333,6 +334,7 @@ local dispatcher_menu_order = {
"toc", "toc",
"book_map", "book_map",
"book_map_overview",
"page_browser", "page_browser",
"bookmarks", "bookmarks",
"bookmark_search", "bookmark_search",

@ -588,7 +588,6 @@ end
-- BookMapWidget: shows a map of content, including TOC, boomarks, read pages, non-linear flows... -- BookMapWidget: shows a map of content, including TOC, boomarks, read pages, non-linear flows...
local BookMapWidget = InputContainer:extend{ local BookMapWidget = InputContainer:extend{
title = _("Book map"),
-- Focus page: show the BookMapRow containing this page -- Focus page: show the BookMapRow containing this page
-- in the middle of screen -- in the middle of screen
focus_page = nil, focus_page = nil,
@ -596,6 +595,8 @@ local BookMapWidget = InputContainer:extend{
launcher = nil, launcher = nil,
-- Extra symbols to show below pages -- Extra symbols to show below pages
extra_symbols_pages = nil, extra_symbols_pages = nil,
-- Restricted mode, as initial view (all on one screen), but allowing chapter levels changes
overview_mode = false,
-- Make this local subwidget available for reuse by PageBrowser -- Make this local subwidget available for reuse by PageBrowser
BookMapRow = BookMapRow, BookMapRow = BookMapRow,
@ -675,12 +676,13 @@ function BookMapWidget:init()
self.row_left_spacing = self.scrollbar_width self.row_left_spacing = self.scrollbar_width
self.swipe_hint_bar_width = Screen:scaleBySize(6) self.swipe_hint_bar_width = Screen:scaleBySize(6)
local title = self.overview_mode and _("Book map (overview)") or _("Book map")
self.title_bar = TitleBar:new{ self.title_bar = TitleBar:new{
fullscreen = true, fullscreen = true,
title = self.title, title = title,
left_icon = "appbar.menu", left_icon = "appbar.menu",
left_icon_tap_callback = function() self:showMenu() end, left_icon_tap_callback = function() self:showMenu() end,
left_icon_hold_callback = function() left_icon_hold_callback = not self.overview_mode and function()
self:toggleDefaultSettings() -- toggle between user settings and default view self:toggleDefaultSettings() -- toggle between user settings and default view
end, end,
close_callback = function() self:onClose() end, close_callback = function() self:onClose() end,
@ -809,6 +811,11 @@ function BookMapWidget:update()
-- Non-flat book map shows a grid with TOC items following each others. -- Non-flat book map shows a grid with TOC items following each others.
self.flat_map = self.ui.doc_settings:readSetting("book_map_flat", false) self.flat_map = self.ui.doc_settings:readSetting("book_map_flat", false)
self.toc_depth = self.ui.doc_settings:readSetting("book_map_toc_depth", self.max_toc_depth) self.toc_depth = self.ui.doc_settings:readSetting("book_map_toc_depth", self.max_toc_depth)
if self.overview_mode then
-- Restricted to grid mode, fitting on the screen. Only toc depth can be adjusted.
self.flat_map = false
self.toc_depth = self.ui.doc_settings:readSetting("book_map_overview_toc_depth", self.max_toc_depth)
end
if self.flat_map then if self.flat_map then
self.nb_toc_spans = 0 -- no span shown in grid self.nb_toc_spans = 0 -- no span shown in grid
else else
@ -882,6 +889,9 @@ function BookMapWidget:update()
-- Show the whole book without scrollbar initially -- Show the whole book without scrollbar initially
self.pages_per_row = self.ui.doc_settings:readSetting("book_map_pages_per_row", self.fit_pages_per_row) self.pages_per_row = self.ui.doc_settings:readSetting("book_map_pages_per_row", self.fit_pages_per_row)
if self.overview_mode then
self.pages_per_row = self.fit_pages_per_row
end
self.page_slot_width = nil -- will be fetched from the first BookMapRow self.page_slot_width = nil -- will be fetched from the first BookMapRow
-- Build BookMapRows as we walk the ToC -- Build BookMapRows as we walk the ToC
@ -1126,7 +1136,7 @@ function BookMapWidget:showMenu()
local plus_minus_width = Screen:scaleBySize(60) local plus_minus_width = Screen:scaleBySize(60)
local buttons = { local buttons = {
{{ {{
text = _("About book map"), text = self.overview_mode and _("About book map (overview)") or _("About book map"),
align = "left", align = "left",
callback = function() callback = function()
self:showAbout() self:showAbout()
@ -1166,7 +1176,7 @@ function BookMapWidget:showMenu()
b:refresh() b:refresh()
end, end,
}}, }},
{{ not self.overview_mode and {{
text = _("Switch current/initial views"), text = _("Switch current/initial views"),
align = "left", align = "left",
enabled_func = function() return self.toc_depth > 0 end, enabled_func = function() return self.toc_depth > 0 end,
@ -1174,7 +1184,7 @@ function BookMapWidget:showMenu()
self:toggleDefaultSettings() self:toggleDefaultSettings()
end, end,
}}, }},
{{ not self.overview_mode and {{
text = _("Switch grid/flat views"), text = _("Switch grid/flat views"),
align = "left", align = "left",
enabled_func = function() return self.toc_depth > 0 end, enabled_func = function() return self.toc_depth > 0 end,
@ -1211,7 +1221,7 @@ function BookMapWidget:showMenu()
width = plus_minus_width, width = plus_minus_width,
} }
}, },
{ not self.overview_mode and {
{ {
text = _("Page slot width"), text = _("Page slot width"),
callback = function() end, callback = function() end,
@ -1268,6 +1278,12 @@ function BookMapWidget:showMenu()
} }
}, },
} }
-- Remove false buttons from the list if overview_mode
for i = #buttons, 1, -1 do
if not buttons[i] then
table.remove(buttons, i)
end
end
button_dialog = ButtonDialog:new{ button_dialog = ButtonDialog:new{
-- width = math.floor(Screen:getWidth() / 2), -- width = math.floor(Screen:getWidth() / 2),
width = math.floor(Screen:getWidth() * 0.9), -- max width, will get smaller width = math.floor(Screen:getWidth() * 0.9), -- max width, will get smaller
@ -1280,8 +1296,7 @@ function BookMapWidget:showMenu()
UIManager:show(button_dialog) UIManager:show(button_dialog)
end end
function BookMapWidget:showAbout() function BookMapWidget:showAbout()
UIManager:show(InfoMessage:new{ local text = _([[
text = _([[
Book map displays an overview of the book content. Book map displays an overview of the book content.
If statistics are enabled, black bars are shown for already read pages (gray for pages read in the current reading session). Their heights vary depending on the time spent reading the page. If statistics are enabled, black bars are shown for already read pages (gray for pages read in the current reading session). Their heights vary depending on the time spent reading the page.
@ -1292,14 +1307,28 @@ Under the pages, these indicators may be shown:
highlighted text highlighted text
highlighted text with notes highlighted text with notes
bookmarked page bookmarked page
focused page when coming from Pages browser focused page when coming from Pages browser]])
On a newly opened book, the book map will start in grid mode showing all chapter levels, fitting on a single screen, to give the best initial overview of the book's content.]]), if self.overview_mode then
}) text = text .. "\n\n" .. _([[
In overview mode, the book map is always in grid mode and ensured to fit on a single screen. Chapter levels can be changed for the most confortable overview.]])
else
text = text .. "\n\n" .. _([[
On a newly opened book, the book map will start in grid mode showing all chapter levels, fitting on a single screen, to give the best initial overview of the book's content.]])
end
UIManager:show(InfoMessage:new{ text = text })
end end
function BookMapWidget:showGestures() function BookMapWidget:showGestures()
UIManager:show(InfoMessage:new{ local text
if self.overview_mode then
text = _([[
Tap on a location in the book to browse thumbnails of the pages there.
Swipe along the left screen edge to change the level of chapters to include in the book map.
Any multiswipe will close the book map.]])
else
text = _([[ text = _([[
Tap on a location in the book to browse thumbnails of the pages there. Tap on a location in the book to browse thumbnails of the pages there.
@ -1311,8 +1340,9 @@ Swipe or pan vertically on content to scroll.
Long-press on to switch between current and initial views. Long-press on to switch between current and initial views.
Any multiswipe will close the book map.]]), Any multiswipe will close the book map.]])
}) end
UIManager:show(InfoMessage:new{ text = text })
end end
function BookMapWidget:onClose(close_all_parents) function BookMapWidget:onClose(close_all_parents)
@ -1430,6 +1460,10 @@ function BookMapWidget:saveSettings(reset)
self.toc_depth = nil self.toc_depth = nil
self.pages_per_row = nil self.pages_per_row = nil
end end
if self.overview_mode then
self.ui.doc_settings:saveSetting("book_map_overview_toc_depth", self.toc_depth)
return
end
self.ui.doc_settings:saveSetting("book_map_flat", self.flat_map) self.ui.doc_settings:saveSetting("book_map_flat", self.flat_map)
self.ui.doc_settings:saveSetting("book_map_toc_depth", self.toc_depth) self.ui.doc_settings:saveSetting("book_map_toc_depth", self.toc_depth)
self.ui.doc_settings:saveSetting("book_map_pages_per_row", self.pages_per_row) self.ui.doc_settings:saveSetting("book_map_pages_per_row", self.pages_per_row)
@ -1465,7 +1499,7 @@ function BookMapWidget:updateTocDepth(depth, flat)
else else
new_toc_depth = new_toc_depth + depth new_toc_depth = new_toc_depth + depth
end end
if new_toc_depth < 0 then if new_toc_depth < 0 and not self.overview_mode then
new_toc_depth = - new_toc_depth new_toc_depth = - new_toc_depth
new_flat_map = not new_flat_map new_flat_map = not new_flat_map
end end
@ -1524,6 +1558,9 @@ function BookMapWidget:onSwipe(arg, ges)
end end
end end
if ges.pos.y > Screen:getHeight() * 7/8 then if ges.pos.y > Screen:getHeight() * 7/8 then
if self.overview_mode then
return true
end
-- Swipe along the bottom screen edge: increase/decrease pages per row -- Swipe along the bottom screen edge: increase/decrease pages per row
if direction == "west" or direction == "east" then if direction == "west" or direction == "east" then
-- Have a swipe distance 0.8 x screen width do *2 or *1/2 -- Have a swipe distance 0.8 x screen width do *2 or *1/2
@ -1545,6 +1582,13 @@ function BookMapWidget:onSwipe(arg, ges)
return true return true
end end
end end
if self.overview_mode and not self.cropping_widget._is_scrollable and direction == "south" then
-- Swipe south won't have any effect in overview mode as we fit on the page (except on
-- really big books, where we can still be scrollable), so allow swipe south to close
-- as on some other fullscreen widgets.
self:onClose()
return true
end
-- Let our MovableContainer handle other swipes: -- Let our MovableContainer handle other swipes:
-- return self.cropping_widget:onScrollableSwipe(arg, ges) -- return self.cropping_widget:onScrollableSwipe(arg, ges)
-- No, we prefer not to, and have swipe north/south do full prev/next page -- No, we prefer not to, and have swipe north/south do full prev/next page
@ -1565,6 +1609,9 @@ function BookMapWidget:onSwipe(arg, ges)
end end
function BookMapWidget:onPinch(arg, ges) function BookMapWidget:onPinch(arg, ges)
if self.overview_mode then
return true
end
local updated = false local updated = false
if ges.direction == "horizontal" or ges.direction == "diagonal" then if ges.direction == "horizontal" or ges.direction == "diagonal" then
local new_pages_per_row = math.ceil(self.pages_per_row * 1.5) local new_pages_per_row = math.ceil(self.pages_per_row * 1.5)
@ -1594,6 +1641,9 @@ function BookMapWidget:onPinch(arg, ges)
end end
function BookMapWidget:onSpread(arg, ges) function BookMapWidget:onSpread(arg, ges)
if self.overview_mode then
return true
end
local updated = false local updated = false
if ges.direction == "horizontal" or ges.direction == "diagonal" then if ges.direction == "horizontal" or ges.direction == "diagonal" then
local new_pages_per_row = math.floor(self.pages_per_row * (2/3)) local new_pages_per_row = math.floor(self.pages_per_row * (2/3))
@ -1663,7 +1713,9 @@ function BookMapWidget:paintTo(bb, x, y)
InputContainer.paintTo(self, bb, x, y) InputContainer.paintTo(self, bb, x, y)
-- And explicitely paint "swipe" hints along the left and bottom borders -- And explicitely paint "swipe" hints along the left and bottom borders
self:paintLeftVerticalSwipeHint(bb, x, y) self:paintLeftVerticalSwipeHint(bb, x, y)
self:paintBottomHorizontalSwipeHint(bb, x, y) if not self.overview_mode then
self:paintBottomHorizontalSwipeHint(bb, x, y)
end
end end
function BookMapWidget:paintLeftVerticalSwipeHint(bb, x, y) function BookMapWidget:paintLeftVerticalSwipeHint(bb, x, y)
@ -1683,6 +1735,9 @@ function BookMapWidget:paintLeftVerticalSwipeHint(bb, x, y)
v.top = self.title_bar_h + math.floor(self.crop_height * 1/6) v.top = self.title_bar_h + math.floor(self.crop_height * 1/6)
v.height = math.floor(self.crop_height * 4/6) v.height = math.floor(self.crop_height * 4/6)
v.nb_units = self.max_toc_depth * 2 + 1 v.nb_units = self.max_toc_depth * 2 + 1
if self.overview_mode then
v.nb_units = self.max_toc_depth + 1
end
v.unit_h = math.floor(v.height / v.nb_units) v.unit_h = math.floor(v.height / v.nb_units)
self.vs_hint_info = v self.vs_hint_info = v
end end
@ -1695,6 +1750,9 @@ function BookMapWidget:paintLeftVerticalSwipeHint(bb, x, y)
else -- lower part of the vertical bar else -- lower part of the vertical bar
unit_idx = self.max_toc_depth + self.toc_depth unit_idx = self.max_toc_depth + self.toc_depth
end end
if self.overview_mode then
unit_idx = self.toc_depth
end
local dy = unit_idx * v.unit_h local dy = unit_idx * v.unit_h
if unit_idx == v.nb_units - 1 then if unit_idx == v.nb_units - 1 then
-- avoid possible rounding error for last unit -- avoid possible rounding error for last unit

Loading…
Cancel
Save