PageBrowser: show page number alongside thumbnails

Add a top left menu item -/+ to show none, only on the
first thumbnail of a row, or on all thumbnails.
Also make the page slot separator longer in the bottom
ribbon before pages that start a thumbnails row.
Also show a little spike in the bottom ribbon below page
slots that get their page number displayed, to ease
figuring out the connection.
reviewable/pr10376/r1
poire-z 1 year ago
parent 7bae2ed920
commit 04fba2205d

@ -304,6 +304,7 @@ function BookMapRow:init()
self.indicators = {}
self.bottom_texts = {}
local prev_page_was_read = true -- avoid one at start of row
local extended_marker_h = math.ceil(self.span_height * 0.3)
local unread_marker_h = math.ceil(self.span_height * 0.05)
local read_min_h = math.max(math.ceil(self.span_height * 0.1), unread_marker_h+Size.line.thick)
if self.page_slot_width >= 5 * unread_marker_h then
@ -359,6 +360,35 @@ function BookMapRow:init()
end
prev_page_was_read = false
end
-- Extended separators below the baseline if requested (by PageBrowser
-- to show the start of thumbnail rows)
if self.extended_sep_pages and self.extended_sep_pages[page] then
local w = Size.line.thin
local x
if _mirroredUI then
x = self:getPageX(page, true) - w
else
x = self:getPageX(page)
end
local y = self.pages_frame_height - self.pages_frame_border
table.insert(self.pages_markers, {
x = x, y = y,
w = w, h = extended_marker_h,
color = Blitbuffer.COLOR_BLACK,
})
end
-- Add a little spike below the baseline above each page number displayed, so we
-- can more easily associate the (possibly wider) page number to its page slot.
if self.page_texts and self.page_texts[page] then
local w = Screen:scaleBySize(2)
local x = math.floor((self:getPageX(page) + self:getPageX(page, true) + 0.5)/2 - w/2)
local y = self.pages_frame_height - self.pages_frame_border + 2
table.insert(self.pages_markers, {
x = x, y = y,
w = w, h = math.ceil(w*1.5),
color = Blitbuffer.COLOR_BLACK,
})
end
-- Indicator for bookmark/highlight type, and current page
if self.bookmarked_pages[page] then
local page_bookmark_types = self.bookmarked_pages[page]

@ -13,6 +13,7 @@ local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local OverlapGroup = require("ui/widget/overlapgroup")
local Size = require("ui/size")
local TextBoxWidget = require("ui/widget/textboxwidget")
local TextWidget = require("ui/widget/textwidget")
local TitleBar = require("ui/widget/titlebar")
local UIManager = require("ui/uimanager")
@ -21,6 +22,7 @@ local VerticalSpan = require("ui/widget/verticalspan")
local Input = Device.input
local Screen = Device.screen
local logger = require("logger")
local util = require("util")
local _ = require("gettext")
-- We use the BookMapRow widget, a local widget defined in bookmapwidget.lua,
@ -134,6 +136,21 @@ function PageBrowserWidget:init()
self.span_height = test_w:getSize().h + BookMapRow.toc_span_border
test_w:free()
-- For page numbers alongside thumbnails, use the same font size
-- we use for them in the ribbon
self.page_num_font_face = Font:getFace("infofont", 10)
if not self.page_num_width then
-- We'll be displaying the number vertically, so get the width we'd need
-- to display some wide single char (this will influence side and inter
-- thumbnails margins).
test_w = TextWidget:new{
text = "W",
face = self.page_num_font_face,
}
self.page_num_width = test_w:getWidth()
test_w:free()
end
self.min_nb_rows = 1
self.max_nb_rows = 6
self.min_nb_cols = 1
@ -245,7 +262,9 @@ function PageBrowserWidget:updateLayout()
end
self.nb_grid_items = self.nb_rows * self.nb_cols
-- Set our items target size
self.grid_item_margin = Screen:scaleBySize(10) -- borders will eat into this, it should be larger than borders thin+thick
-- Borders may eat into the margin, and the horizontal margin should be able to contain the page number
-- (let's use this computed margin also vertically)
self.grid_item_margin = self.page_num_width + Size.padding.small + Size.border.thick + Size.border.thin
self.grid_item_height = math.floor((self.grid_height - (self.nb_rows)*self.grid_item_margin) / self.nb_rows) -- no need for top margin, title bottom padding is enough
self.grid_item_width = math.floor((self.grid_width - (1+self.nb_cols)*self.grid_item_margin) / self.nb_cols)
self.grid_item_dimen = Geom:new{
@ -255,9 +274,17 @@ function PageBrowserWidget:updateLayout()
self.grid:clear()
self.thumbnails_pagenums = self.ui.doc_settings:readSetting("page_browser_thumbnails_pagenums")
or G_reader_settings:readSetting("page_browser_thumbnails_pagenums") or 2
for idx = 1, self.nb_grid_items do
local row = math.floor((idx-1)/self.nb_cols) -- start from 0
local col = (idx-1) % self.nb_cols
local show_pagenum -- no page number shown on the left side of a thumbnail, unless:
if self.thumbnails_pagenums == 1 then -- only for the first thumbnail of each row
show_pagenum = col == 0
elseif self.thumbnails_pagenums == 2 then -- for all thumnbnails
show_pagenum = true
end
if BD.mirroredUILayout() then
col = self.nb_cols - col - 1
end
@ -267,6 +294,7 @@ function PageBrowserWidget:updateLayout()
dimen = self.grid_item_dimen:copy(),
}
table.insert(self.grid, FrameContainer:new{
show_pagenum = show_pagenum,
overlap_offset = {offset_x, offset_y},
margin = 0,
padding = 0,
@ -305,6 +333,14 @@ function PageBrowserWidget:update()
end
self.requests_batch_id = "PageBrowserWidget"..tostring(os.time())
for i=#self.grid, 1, -1 do
if self.grid[i].is_page_num_widget then
-- Remove page_num_widgets, as we'll be recreating them
local widget = table.remove(self.grid, i)
widget:free()
end
end
if not self.focus_page then
self.focus_page = self.cur_page or 1
end
@ -326,64 +362,96 @@ function PageBrowserWidget:update()
p_start = 1
end
-- Extended separators below the baseline for pages starting thumbnail rows
local extended_sep_pages = {}
for p=grid_page_start+self.nb_cols, grid_page_end, self.nb_cols do
extended_sep_pages[p] = true
end
-- Show the page number or label at the bottom page slot every N slots, with N
-- the nb of thumbnails so we get at least one page label in our viewport.
local page_texts_cycle = math.min(self.nb_grid_items, 10) -- but max 10
local next_p = p_start
local cur_page_label_idx = 1
local page_texts = {}
local page_texts = {} -- to be provided to the bottom ribbon BookMapRow
self.pagenum_page_texts = {} -- to be displayed alongside thumbnails
for p=p_start, p_end do
-- This may be expensive, so compute only the ones we need for display
local show_at_bottom
if p >= next_p then
-- Only show a page text if there is no indicator on that slot
if p ~= self.cur_page and not self.bookmarked_pages[p] and not self.previous_locations[p] then
local page_text
if self.page_labels then
local page_label
for idx=cur_page_label_idx, #self.page_labels do
local item = self.page_labels[idx]
if item.page >= p then
if item.page == p then
page_label = item.label
end
break
show_at_bottom = true
end
end
local show_near_thumbnail
if p >= grid_page_start and p <= grid_page_end then
show_near_thumbnail = self.grid[p - grid_page_start + 1].show_pagenum
end
if show_at_bottom or show_near_thumbnail then
local page_text, thumbnail_page_text
if self.page_labels then
local page_label
for idx=cur_page_label_idx, #self.page_labels do
local item = self.page_labels[idx]
if item.page >= p then
if item.page == p then
page_label = item.label
end
cur_page_label_idx = idx
end
if page_label then
page_text = self.ui.pagemap:cleanPageLabel(page_label)
end
elseif self.has_hidden_flows then
local flow = self.ui.document:getPageFlow(p)
if flow == 0 then
page_text = tostring(self.ui.document:getPageNumberInFlow(p))
else
page_text = string.format("[%d]%d", self.ui.document:getPageNumberInFlow(p), self.ui.document:getPageFlow(p))
break
end
cur_page_label_idx = idx
end
if page_label then
page_text = self.ui.pagemap:cleanPageLabel(page_label)
elseif show_near_thumbnail then
-- When reference pages may span multiple screen pages, the above may not get
-- a page_text for some pages, which is fine for the bottom ribbon: it will
-- display it for the next slot where a new reference page starts.
-- But for thumbnails, we want to show some page number text, so fetch
-- the previous one (that started on a previous screen page).
thumbnail_page_text = self.ui.pagemap:cleanPageLabel(self.page_labels[cur_page_label_idx].label)
end
elseif self.has_hidden_flows then
local flow = self.ui.document:getPageFlow(p)
if flow == 0 then
page_text = tostring(self.ui.document:getPageNumberInFlow(p))
else
page_text = tostring(p)
local page_number_in_flow = self.ui.document:getPageNumberInFlow(p)
local page_flow = self.ui.document:getPageFlow(p)
page_text = string.format("[%d]%d", page_number_in_flow, page_flow)
-- Use something that will feel alike brackets when vertically
-- (Harfbuzz will properly mirror these if the UI is RTL)
thumbnail_page_text = string.format("\u{2E1D}%d\u{2E0C}%d", page_number_in_flow, page_flow)
end
if page_text then
local page_block, page_block_dx -- centered by default
if p == p_start or p == grid_page_start or p == grid_page_end+1 then
page_block = "left"
page_block_dx = Size.padding.tiny
if p == grid_page_start then
page_block_dx = page_block_dx + self.view_finder_bw + 1
end
elseif p == p_end or p == grid_page_end or p == grid_page_start-1 then
page_block = "right"
page_block_dx = Size.padding.tiny
if p == grid_page_end then
page_block_dx = page_block_dx + self.view_finder_bw + 1
end
else
page_text = tostring(p)
end
if page_text and show_at_bottom then
local page_block, page_block_dx -- centered by default
if p == p_start or p == grid_page_start or p == grid_page_end+1 then
page_block = "left"
page_block_dx = Size.padding.tiny
if p == grid_page_start then
page_block_dx = page_block_dx + self.view_finder_bw + 1
end
elseif p == p_end or p == grid_page_end or p == grid_page_start-1 then
page_block = "right"
page_block_dx = Size.padding.tiny
if p == grid_page_end then
page_block_dx = page_block_dx + self.view_finder_bw + 1
end
page_texts[p] = {
text = page_text,
block = page_block,
block_dx = page_block_dx,
}
next_p = p + page_texts_cycle
end
page_texts[p] = {
text = page_text,
block = page_block,
block_dx = page_block_dx,
}
next_p = p + page_texts_cycle
end
if show_near_thumbnail then
-- Dedicated thumbnail_page_text, or the default one
self.pagenum_page_texts[p] = thumbnail_page_text or page_text
end
end
end
@ -477,6 +545,7 @@ function PageBrowserWidget:update()
read_pages = self.read_pages,
current_session_duration = self.current_session_duration,
page_texts = page_texts,
extended_sep_pages = extended_sep_pages,
}
self.row[1] = row
@ -601,6 +670,36 @@ function PageBrowserWidget:showTile(grid_idx, page, tile, do_refresh)
-- thumb_frame will overflow its CenterContainer because of the added borders,
-- but CenterContainer handles that well. We will refresh the outer dimensions.
local page_num_widget
if item_frame.show_pagenum and self.pagenum_page_texts[page] then
local page_text = table.concat(util.splitToChars(self.pagenum_page_texts[page]), "\n")
page_num_widget = TextBoxWidget:new{
text = page_text,
width = self.page_num_width,
face = self.page_num_font_face,
line_height = 0, -- no additional line height
alignment = BD.mirroredUILayout() and "left" or "right",
alignment_strict = true,
is_page_num_widget = true, -- so we can clear them in :update()
}
-- Only now that we know the thumbnail size, we can position this vertical
-- page number widget alongside and at the top of the thumbnail left edge
local thumb_frame_dimen = thumb_frame:getSize()
local dw = self.grid_item_width - thumb_frame_dimen.w
local dh = self.grid_item_height - thumb_frame_dimen.h
local dx = math.floor(dw/2)
local dy = math.floor(dh/2)
local offset_y = item_frame.overlap_offset[2] + dy
local offset_x
if BD.mirroredUILayout() then
offset_x = item_frame.overlap_offset[1] + self.grid_item_width - dx + Size.padding.small
else
offset_x = item_frame.overlap_offset[1] + dx - page_num_widget:getSize().w - Size.padding.small
end
page_num_widget.overlap_offset = {offset_x, offset_y}
table.insert(self.grid, page_num_widget)
end
if do_refresh then
if self.wait_for_refresh_on_show_tile then
self.wait_for_refresh_on_show_tile = nil
@ -609,6 +708,9 @@ function PageBrowserWidget:showTile(grid_idx, page, tile, do_refresh)
UIManager:waitForVSync()
end
UIManager:setDirty(self, function()
if page_num_widget then
return "ui", thumb_frame.dimen:combine(page_num_widget.dimen)
end
return "ui", thumb_frame.dimen
end)
end
@ -687,6 +789,33 @@ function PageBrowserWidget:showMenu()
width = plus_minus_width,
}
},
{
{
text = _("Thumbnail page numbers"),
callback = function() end,
align = "left",
},
{
text = "\u{2796}", -- Heavy minus sign
enabled_func = function() return self.thumbnails_pagenums > 0 end,
callback = function()
if self:updateThumbnailPageNumsDisplayType(-1, true) then
self:updateLayout()
end
end,
width = plus_minus_width,
},
{
text = "\u{2795}", -- Heavy plus sign
enabled_func = function() return self.thumbnails_pagenums < 2 end,
callback = function()
if self:updateThumbnailPageNumsDisplayType(1, true) then
self:updateLayout()
end
end,
width = plus_minus_width,
}
},
{
{
text = _("Chapters in bottom ribbon"),
@ -809,10 +938,12 @@ function PageBrowserWidget:saveSettings(reset)
self.ui.doc_settings:saveSetting("page_browser_toc_depth", self.nb_toc_spans)
self.ui.doc_settings:saveSetting("page_browser_nb_rows", self.nb_rows)
self.ui.doc_settings:saveSetting("page_browser_nb_cols", self.nb_cols)
self.ui.doc_settings:saveSetting("page_browser_thumbnails_pagenums", self.thumbnails_pagenums)
-- We also save nb_rows/nb_cols as global settings, so they will apply on other books
-- where they were not already set
G_reader_settings:saveSetting("page_browser_nb_rows", self.nb_rows)
G_reader_settings:saveSetting("page_browser_nb_cols", self.nb_cols)
G_reader_settings:saveSetting("page_browser_thumbnails_pagenums", self.thumbnails_pagenums)
end
function PageBrowserWidget:updateNbTocSpans(value, relative, rollover)
@ -886,6 +1017,27 @@ function PageBrowserWidget:updateNbRows(value, relative)
return true
end
function PageBrowserWidget:updateThumbnailPageNumsDisplayType(value, relative)
local new_thumbnails_pagenums
if relative then
new_thumbnails_pagenums = self.thumbnails_pagenums + value
else
new_thumbnails_pagenums = value
end
if new_thumbnails_pagenums < 0 then
new_thumbnails_pagenums = 0
end
if new_thumbnails_pagenums > 2 then
new_thumbnails_pagenums = 2
end
if new_thumbnails_pagenums == self.thumbnails_pagenums then
return false
end
self.thumbnails_pagenums = new_thumbnails_pagenums
self:saveSettings()
return true
end
function PageBrowserWidget:updateFocusPage(value, relative)
local new_focus_page
if relative then

Loading…
Cancel
Save