diff --git a/frontend/apps/reader/modules/readerpagemap.lua b/frontend/apps/reader/modules/readerpagemap.lua index f2daba680..e2e834a18 100644 --- a/frontend/apps/reader/modules/readerpagemap.lua +++ b/frontend/apps/reader/modules/readerpagemap.lua @@ -212,6 +212,7 @@ function ReaderPageMap:onShowPageList() -- We use the per-page and font-size settings set for the ToC local items_per_page = G_reader_settings:readSetting("toc_items_per_page") or 14 local items_font_size = G_reader_settings:readSetting("toc_items_font_size") or Menu.getItemFontSize(items_per_page) + local items_with_dots = G_reader_settings:nilOrTrue("toc_items_with_dots") local pl_menu = Menu:new{ title = _("Reference page numbers list"), @@ -225,6 +226,8 @@ function ReaderPageMap:onShowPageList() items_font_size = items_font_size, line_color = require("ffi/blitbuffer").COLOR_WHITE, single_line = true, + align_baselines = true, + with_dots = items_with_dots, on_close_ges = { GestureRange:new{ ges = "two_finger_swipe", diff --git a/frontend/apps/reader/modules/readertoc.lua b/frontend/apps/reader/modules/readertoc.lua index dc571df47..0174bcd3a 100644 --- a/frontend/apps/reader/modules/readertoc.lua +++ b/frontend/apps/reader/modules/readertoc.lua @@ -643,7 +643,7 @@ 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_separator = G_reader_settings:isTrue("toc_items_show_separator") + local items_with_dots = G_reader_settings:nilOrTrue("toc_items_with_dots") -- Estimate expand/collapse icon size -- *2/5 to acount for Menu top title and bottom icons, and add some space between consecutive icons local icon_size = math.floor(Screen:getHeight() / items_per_page * 2/5) @@ -703,10 +703,11 @@ function ReaderToc:onShowToc() cface = Font:getFace("x_smallinfofont"), single_line = true, align_baselines = true, + with_dots = items_with_dots, items_per_page = items_per_page, items_font_size = items_font_size, items_padding = can_collapse and math.floor(Size.padding.fullscreen / 2) or nil, -- c.f., note above. Menu's default is twice that. - line_color = items_show_separator and Blitbuffer.COLOR_DARK_GRAY or Blitbuffer.COLOR_WHITE, + line_color = Blitbuffer.COLOR_WHITE, on_close_ges = { GestureRange:new{ ges = "two_finger_swipe", @@ -1062,14 +1063,14 @@ Enabling this option will restrict display to the chapter titles of progress bar UIManager:show(items_font) end, } - menu_items.toc_items_show_separator = { - text = _("Add a separator between ToC entries"), + menu_items.toc_items_with_dots = { + text = _("With dots"), keep_menu_open = true, checked_func = function() - return G_reader_settings:isTrue("toc_items_show_separator") + return G_reader_settings:nilOrTrue("toc_items_with_dots") end, callback = function() - G_reader_settings:flipNilOrFalse("toc_items_show_separator") + G_reader_settings:flipNilOrTrue("toc_items_with_dots") end } end diff --git a/frontend/ui/elements/reader_menu_order.lua b/frontend/ui/elements/reader_menu_order.lua index 16366535c..bd69c36b2 100644 --- a/frontend/ui/elements/reader_menu_order.lua +++ b/frontend/ui/elements/reader_menu_order.lua @@ -33,7 +33,7 @@ local order = { "----------------------------", "toc_items_per_page", "toc_items_font_size", - "toc_items_show_separator", + "toc_items_with_dots", "----------------------------", "bookmarks_items_per_page", "bookmarks_items_font_size", diff --git a/frontend/ui/widget/menu.lua b/frontend/ui/widget/menu.lua index dc303c6d4..804f28687 100644 --- a/frontend/ui/widget/menu.lua +++ b/frontend/ui/widget/menu.lua @@ -151,6 +151,8 @@ local MenuItem = InputContainer:new{ multilines_show_more_text = false, -- Align text & mandatory baselines (only when single_line=true) align_baselines = false, + -- Show a line of dots (also called tab or dot leaders) between text and mandatory + with_dots = false, } function MenuItem:init() @@ -265,6 +267,9 @@ function MenuItem:init() text = self.bidi_wrap_func(text) end + 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 -- No font size change: text will be truncated if it overflows item_name = TextWidget:new{ @@ -279,21 +284,54 @@ function MenuItem:init() -- feeling (which might make it no more truncated, but well...) local text_max_width_if_ellipsis = available_width + text_mandatory_padding - text_ellipsis_mandatory_padding item_name:setMaxWidth(text_max_width_if_ellipsis) + else + if self.with_dots then + local dots_width = available_width + text_mandatory_padding - w - dots_left_padding - dots_right_padding + if dots_width > 0 then + local dots_text, dots_min_width = self:getDotsText(self.info_face) + -- Don't show any dots if there would be less than 3 + if dots_width >= dots_min_width then + dots_widget = TextWidget:new{ + text = dots_text, + face = self.info_face, -- same as mandatory widget, to keep their baseline adjusted + max_width = dots_width, + truncate_with_ellipsis = false, + } + end + end + end end if self.align_baselines then -- Align baselines of text and mandatory + -- The container widgets would additionally center these widgets, + -- so make sure they all get a height=self.dimen.h so they don't + -- risk being shifted later and becoming misaligned local name_baseline = item_name:getBaseline() - local mandatory_baseline = mandatory_widget:getBaseline() - local baselines_diff = Math.round(name_baseline - mandatory_baseline) + local mdtr_baseline = mandatory_widget:getBaseline() + local name_height = item_name:getSize().h + local mdtr_height = mandatory_widget:getSize().h + -- Make all the TextWidgets be self.dimen.h + item_name.forced_height = self.dimen.h + mandatory_widget.forced_height = self.dimen.h + if dots_widget then + dots_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.) + local name_missing_pad_top = math.floor( (self.dimen.h - name_height) / 2) + local mdtr_missing_pad_top = math.floor( (self.dimen.h - mdtr_height) / 2) + name_baseline = name_baseline + name_missing_pad_top + mdtr_baseline = mdtr_baseline + mdtr_missing_pad_top + local baselines_diff = Math.round(name_baseline - mdtr_baseline) if baselines_diff > 0 then - mandatory_widget = VerticalGroup:new{ - VerticalSpan:new{width = baselines_diff}, - mandatory_widget, - } - elseif baselines_diff < 0 then - item_name = VerticalGroup:new{ - VerticalSpan:new{width = -baselines_diff}, - item_name, - } + mdtr_baseline = mdtr_baseline + baselines_diff + else + name_baseline = name_baseline - baselines_diff + end + item_name.forced_baseline = name_baseline + mandatory_widget.forced_baseline = mdtr_baseline + if dots_widget then + dots_widget.forced_baseline = mdtr_baseline end end @@ -381,6 +419,13 @@ function MenuItem:init() } } + if dots_widget then + mandatory_widget = HorizontalGroup:new{ + dots_widget, + HorizontalSpan:new{ width = dots_right_padding }, + mandatory_widget, + } + end local mandatory_container = RightContainer:new{ dimen = Geom:new{w = self.content_width, h = self.dimen.h}, mandatory_widget, @@ -427,6 +472,34 @@ function MenuItem:init() } end +local _dots_cached_info + +function MenuItem:getDotsText(face) + local screen_w = Screen:getWidth() + if not _dots_cached_info or _dots_cached_info.screen_width ~= screen_w + or _dots_cached_info.face ~= face then + local unit = "." + local tmp = TextWidget:new{ + text = unit, + face = face, + } + local unit_w = tmp:getSize().w + tmp:free() + -- (We assume/expect no kerning will happen between consecutive units) + local nb_units = math.ceil(screen_w / unit_w) + local min_width = unit_w * 3 -- have it not shown if smaller than this + local text = unit:rep(nb_units) + _dots_cached_info = { + text = text, + min_width = min_width, + screen_width = screen_w, + face = face, + } + end + return _dots_cached_info.text, _dots_cached_info.min_width + +end + function MenuItem:onFocus(initial_focus) if Device:isTouchDevice() then -- Devices which are Keys capable will get this onFocus called by @@ -1079,6 +1152,7 @@ function Menu:updateItems(select_number) single_line = self.single_line, multilines_show_more_text = multilines_show_more_text, align_baselines = self.align_baselines, + with_dots = self.with_dots, line_color = self.line_color, items_padding = self.items_padding, }