diff --git a/frontend/apps/reader/modules/readertoc.lua b/frontend/apps/reader/modules/readertoc.lua index a70ced5d1..a77619e49 100644 --- a/frontend/apps/reader/modules/readertoc.lua +++ b/frontend/apps/reader/modules/readertoc.lua @@ -104,6 +104,7 @@ end function ReaderToc:resetToc() self.toc = nil + self.toc_menu_items_built = false self.toc_depth = nil self.ticks = nil self.ticks_flattened = nil @@ -314,6 +315,37 @@ function ReaderToc:validateAndFixToc() self.toc_depth = max_depth end +function ReaderToc:completeTocWithChapterLengths() + local toc = self.toc + local first = 1 + local last = #toc + if last == 0 then + return + end + local prev_item_by_level = {} + for i = first, last do + local item = toc[i] + local page = item.page + local depth = item.depth + for j=#prev_item_by_level, depth, -1 do + local prev_item = prev_item_by_level[j] + if prev_item then + prev_item.chapter_length = page - prev_item.page + end + prev_item_by_level[j] = nil + end + prev_item_by_level[depth] = item + end + -- Set the length of the last ones + local page = self.ui.document:getPageCount() + for j=#prev_item_by_level, 0, -1 do + local prev_item = prev_item_by_level[j] + if prev_item then + prev_item.chapter_length = page - prev_item.page + end + end +end + function ReaderToc:getTocIndexByPage(pn_or_xp, skip_ignored_ticks) self:fillToc() if #self.toc == 0 then return end @@ -661,11 +693,16 @@ function ReaderToc:onShowToc() local items_per_page = G_reader_settings:readSetting("toc_items_per_page") or self.toc_items_per_page_default local items_font_size = G_reader_settings:readSetting("toc_items_font_size") or Menu.getItemFontSize(items_per_page) + local items_show_chapter_length = G_reader_settings:isTrue("toc_items_show_chapter_length") local items_with_dots = G_reader_settings:nilOrTrue("toc_items_with_dots") self:fillToc() -- build menu items - if #self.toc > 0 and not self.toc[1].text then + if #self.toc > 0 and not self.toc_menu_items_built then + self.toc_menu_items_built = true + if items_show_chapter_length then + self:completeTocWithChapterLengths() + end -- Have the width of 4 spaces be the unit of indentation local tmp = TextWidget:new{ text = " ", @@ -679,6 +716,11 @@ function ReaderToc:onShowToc() v.index = k v.indent = toc_indent * (v.depth-1) v.text = self:cleanUpTocTitle(v.title, true) + if items_show_chapter_length then + v.post_text = T("(%1)", v.chapter_length) + else + v.post_text = nil + end v.bidi_wrap_func = BD.auto v.mandatory = v.page if has_hidden_flows then @@ -1147,6 +1189,17 @@ Enabling this option will restrict display to the chapter titles of progress bar UIManager:show(items_font) end, } + menu_items.toc_items_show_chapter_length = { + text = _("Show chapter length"), + keep_menu_open = true, + checked_func = function() + return not G_reader_settings:nilOrFalse("toc_items_show_chapter_length") + end, + callback = function() + G_reader_settings:flipNilOrFalse("toc_items_show_chapter_length") + self.toc_menu_items_built = false + end + } menu_items.toc_items_with_dots = { text = _("With dots"), keep_menu_open = true, diff --git a/frontend/ui/elements/reader_menu_order.lua b/frontend/ui/elements/reader_menu_order.lua index ca48996bf..d64d5f0e6 100644 --- a/frontend/ui/elements/reader_menu_order.lua +++ b/frontend/ui/elements/reader_menu_order.lua @@ -35,6 +35,7 @@ local order = { "----------------------------", "toc_items_per_page", "toc_items_font_size", + "toc_items_show_chapter_length", "toc_items_with_dots", "----------------------------", "toc_alt_toc", diff --git a/frontend/ui/widget/menu.lua b/frontend/ui/widget/menu.lua index 46e3b4386..ee2392d38 100644 --- a/frontend/ui/widget/menu.lua +++ b/frontend/ui/widget/menu.lua @@ -184,6 +184,12 @@ function MenuItem:init() self.face = Font:getFace(self.font, self.font_size) -- Font for "mandatory" on the right self.info_face = Font:getFace(self.infont, self.infont_size) + -- Font for post_text if any: for now, this is only used with TOC, showing + -- the chapter length: if feels best to use the face of the main text, but + -- with the size of the mandatory font (which shows some number too). + if self.post_text then + self.post_text_face = Font:getFace(self.font, self.infont_size) + end -- "mandatory" is the text on the right: file size, page number... -- Padding before mandatory @@ -219,10 +225,23 @@ function MenuItem:init() text = self.bidi_wrap_func(text) end + -- Note: support for post_text is currently implemented only when single_line=true + local post_text_widget + local post_text_left_padding = Size.padding.large + local post_text_right_padding = self.with_dots and 0 or Size.padding.large local dots_widget local dots_left_padding = Size.padding.small local dots_right_padding = Size.padding.small if self.single_line then -- items only in single line + if self.post_text then + post_text_widget = TextWidget:new{ + text = self.post_text, + face = self.post_text_face, + bold = self.bold, + fgcolor = self.dim and Blitbuffer.COLOR_DARK_GRAY or nil, + } + available_width = available_width - post_text_widget:getWidth() - post_text_left_padding - post_text_right_padding + end -- No font size change: text will be truncated if it overflows item_name = TextWidget:new{ text = text, @@ -271,6 +290,9 @@ function MenuItem:init() if dots_widget then dots_widget.forced_height = self.dimen.h end + if post_text_widget then + post_text_widget.forced_height = self.dimen.h + end -- And adjust their baselines for proper centering and alignment -- (We made sure the font sizes wouldn't exceed self.dimen.h, so we -- get only non-negative pad_top here, and we're moving them down.) @@ -289,6 +311,9 @@ function MenuItem:init() if dots_widget then dots_widget.forced_baseline = mdtr_baseline end + if post_text_widget then + post_text_widget.forced_baseline = mdtr_baseline + end end elseif self.multilines_show_more_text then @@ -374,6 +399,8 @@ function MenuItem:init() width = state_width, }, item_name, + post_text_widget and HorizontalSpan:new{ width = post_text_left_padding }, + post_text_widget, } } @@ -1083,6 +1110,7 @@ function Menu:updateItems(select_number) state_w = self.state_w or 0, text = Menu.getMenuText(self.item_table[i]), bidi_wrap_func = self.item_table[i].bidi_wrap_func, + post_text = self.item_table[i].post_text, mandatory = self.item_table[i].mandatory, mandatory_func = self.item_table[i].mandatory_func, mandatory_dim = self.item_table[i].mandatory_dim or self.item_table[i].dim,