ReaderToc: option to show a dotted line (#7669)

A dotted line joining the ToC entry text to the
page number may make it easier to use.
(This replaces the menu item separator from d879062e.)
Also fix baselines aligment, which could be a bit off.
reviewable/pr7673/r1
poire-z 3 years ago committed by GitHub
parent a20cac6904
commit f0ecbeb1d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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",

@ -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

@ -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",

@ -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,
}

Loading…
Cancel
Save