mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
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.
This commit is contained in:
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user