@ -13,6 +13,7 @@ local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require ( " ui/widget/container/inputcontainer " )
local InputContainer = require ( " ui/widget/container/inputcontainer " )
local OverlapGroup = require ( " ui/widget/overlapgroup " )
local OverlapGroup = require ( " ui/widget/overlapgroup " )
local Size = require ( " ui/size " )
local Size = require ( " ui/size " )
local TextBoxWidget = require ( " ui/widget/textboxwidget " )
local TextWidget = require ( " ui/widget/textwidget " )
local TextWidget = require ( " ui/widget/textwidget " )
local TitleBar = require ( " ui/widget/titlebar " )
local TitleBar = require ( " ui/widget/titlebar " )
local UIManager = require ( " ui/uimanager " )
local UIManager = require ( " ui/uimanager " )
@ -21,6 +22,7 @@ local VerticalSpan = require("ui/widget/verticalspan")
local Input = Device.input
local Input = Device.input
local Screen = Device.screen
local Screen = Device.screen
local logger = require ( " logger " )
local logger = require ( " logger " )
local util = require ( " util " )
local _ = require ( " gettext " )
local _ = require ( " gettext " )
-- We use the BookMapRow widget, a local widget defined in bookmapwidget.lua,
-- 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
self.span_height = test_w : getSize ( ) . h + BookMapRow.toc_span_border
test_w : free ( )
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.min_nb_rows = 1
self.max_nb_rows = 6
self.max_nb_rows = 6
self.min_nb_cols = 1
self.min_nb_cols = 1
@ -245,7 +262,9 @@ function PageBrowserWidget:updateLayout()
end
end
self.nb_grid_items = self.nb_rows * self.nb_cols
self.nb_grid_items = self.nb_rows * self.nb_cols
-- Set our items target size
-- 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_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_width = math.floor ( ( self.grid_width - ( 1 + self.nb_cols ) * self.grid_item_margin ) / self.nb_cols )
self.grid_item_dimen = Geom : new {
self.grid_item_dimen = Geom : new {
@ -255,9 +274,17 @@ function PageBrowserWidget:updateLayout()
self.grid : clear ( )
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
for idx = 1 , self.nb_grid_items do
local row = math.floor ( ( idx - 1 ) / self.nb_cols ) -- start from 0
local row = math.floor ( ( idx - 1 ) / self.nb_cols ) -- start from 0
local col = ( idx - 1 ) % self.nb_cols
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
if BD.mirroredUILayout ( ) then
col = self.nb_cols - col - 1
col = self.nb_cols - col - 1
end
end
@ -267,6 +294,7 @@ function PageBrowserWidget:updateLayout()
dimen = self.grid_item_dimen : copy ( ) ,
dimen = self.grid_item_dimen : copy ( ) ,
}
}
table.insert ( self.grid , FrameContainer : new {
table.insert ( self.grid , FrameContainer : new {
show_pagenum = show_pagenum ,
overlap_offset = { offset_x , offset_y } ,
overlap_offset = { offset_x , offset_y } ,
margin = 0 ,
margin = 0 ,
padding = 0 ,
padding = 0 ,
@ -305,6 +333,14 @@ function PageBrowserWidget:update()
end
end
self.requests_batch_id = " PageBrowserWidget " .. tostring ( os.time ( ) )
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
if not self.focus_page then
self.focus_page = self.cur_page or 1
self.focus_page = self.cur_page or 1
end
end
@ -326,17 +362,34 @@ function PageBrowserWidget:update()
p_start = 1
p_start = 1
end
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
-- 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.
-- 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 page_texts_cycle = math.min ( self.nb_grid_items , 10 ) -- but max 10
local next_p = p_start
local next_p = p_start
local cur_page_label_idx = 1
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
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
if p >= next_p then
-- Only show a page text if there is no indicator on that slot
-- 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
if p ~= self.cur_page and not self.bookmarked_pages [ p ] and not self.previous_locations [ p ] then
local page_text
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
if self.page_labels then
local page_label
local page_label
for idx = cur_page_label_idx , # self.page_labels do
for idx = cur_page_label_idx , # self.page_labels do
@ -351,18 +404,30 @@ function PageBrowserWidget:update()
end
end
if page_label then
if page_label then
page_text = self.ui . pagemap : cleanPageLabel ( page_label )
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
end
elseif self.has_hidden_flows then
elseif self.has_hidden_flows then
local flow = self.ui . document : getPageFlow ( p )
local flow = self.ui . document : getPageFlow ( p )
if flow == 0 then
if flow == 0 then
page_text = tostring ( self.ui . document : getPageNumberInFlow ( p ) )
page_text = tostring ( self.ui . document : getPageNumberInFlow ( p ) )
else
else
page_text = string.format ( " [%d]%d " , self.ui . document : getPageNumberInFlow ( p ) , self.ui . document : getPageFlow ( 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
end
else
else
page_text = tostring ( p )
page_text = tostring ( p )
end
end
if page_text then
if page_text and show_at_bottom then
local page_block , page_block_dx -- centered by default
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
if p == p_start or p == grid_page_start or p == grid_page_end + 1 then
page_block = " left "
page_block = " left "
@ -384,6 +449,9 @@ function PageBrowserWidget:update()
}
}
next_p = p + page_texts_cycle
next_p = p + page_texts_cycle
end
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
end
end
end
@ -477,6 +545,7 @@ function PageBrowserWidget:update()
read_pages = self.read_pages ,
read_pages = self.read_pages ,
current_session_duration = self.current_session_duration ,
current_session_duration = self.current_session_duration ,
page_texts = page_texts ,
page_texts = page_texts ,
extended_sep_pages = extended_sep_pages ,
}
}
self.row [ 1 ] = row
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,
-- thumb_frame will overflow its CenterContainer because of the added borders,
-- but CenterContainer handles that well. We will refresh the outer dimensions.
-- 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 do_refresh then
if self.wait_for_refresh_on_show_tile then
if self.wait_for_refresh_on_show_tile then
self.wait_for_refresh_on_show_tile = nil
self.wait_for_refresh_on_show_tile = nil
@ -609,6 +708,9 @@ function PageBrowserWidget:showTile(grid_idx, page, tile, do_refresh)
UIManager : waitForVSync ( )
UIManager : waitForVSync ( )
end
end
UIManager : setDirty ( self , function ( )
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
return " ui " , thumb_frame.dimen
end )
end )
end
end
@ -687,6 +789,33 @@ function PageBrowserWidget:showMenu()
width = plus_minus_width ,
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 " ) ,
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_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_rows " , self.nb_rows )
self.ui . doc_settings : saveSetting ( " page_browser_nb_cols " , self.nb_cols )
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
-- We also save nb_rows/nb_cols as global settings, so they will apply on other books
-- where they were not already set
-- where they were not already set
G_reader_settings : saveSetting ( " page_browser_nb_rows " , self.nb_rows )
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_nb_cols " , self.nb_cols )
G_reader_settings : saveSetting ( " page_browser_thumbnails_pagenums " , self.thumbnails_pagenums )
end
end
function PageBrowserWidget : updateNbTocSpans ( value , relative , rollover )
function PageBrowserWidget : updateNbTocSpans ( value , relative , rollover )
@ -886,6 +1017,27 @@ function PageBrowserWidget:updateNbRows(value, relative)
return true
return true
end
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 )
function PageBrowserWidget : updateFocusPage ( value , relative )
local new_focus_page
local new_focus_page
if relative then
if relative then