diff --git a/frontend/apps/reader/modules/readerbookmark.lua b/frontend/apps/reader/modules/readerbookmark.lua index 45dfa0900..0a22f7b4c 100644 --- a/frontend/apps/reader/modules/readerbookmark.lua +++ b/frontend/apps/reader/modules/readerbookmark.lua @@ -24,7 +24,6 @@ local Screen = require("device").screen local T = require("ffi/util").template local ReaderBookmark = InputContainer:extend{ - bookmarks_items_per_page_default = 14, -- mark the type of a bookmark with a symbol + non-expandable space display_prefix = { highlight = "\u{2592}\u{2002}", -- "medium shade" @@ -45,8 +44,7 @@ function ReaderBookmark:init() -- The Bookmarks items per page and items' font size can now be -- configured. Previously, the ones set for the file browser -- were used. Initialize them from these ones. - local items_per_page = G_reader_settings:readSetting("items_per_page") - or self.bookmarks_items_per_page_default + local items_per_page = G_reader_settings:readSetting("items_per_page") or Menu.items_per_page_default G_reader_settings:saveSetting("bookmarks_items_per_page", items_per_page) local items_font_size = G_reader_settings:readSetting("items_font_size") if items_font_size and items_font_size ~= Menu.getItemFontSize(items_per_page) then @@ -55,6 +53,7 @@ function ReaderBookmark:init() end end self.items_text = G_reader_settings:readSetting("bookmarks_items_text_type", "note") + self.items_max_lines = G_reader_settings:readSetting("bookmarks_items_max_lines") self.ui.menu:registerToMainMenu(self) -- NOP our own gesture handling @@ -75,27 +74,6 @@ end ReaderBookmark.onPhysicalKeyboardConnected = ReaderBookmark.registerKeyEvents -function ReaderBookmark:genItemTextMenuItem(type, get_string) - local text_type = { - text = _("highlighted text"), - all = _("highlighted text and note"), - note = _("note, or highlighted text"), - } - if get_string then - return text_type[type] - end - return { - text = text_type[type], - checked_func = function() - return self.items_text == type - end, - callback = function() - self.items_text = type - G_reader_settings:saveSetting("bookmarks_items_text_type", type) - end, - } -end - function ReaderBookmark:addToMainMenu(menu_items) menu_items.bookmarks = { text = _("Bookmarks"), @@ -103,7 +81,7 @@ function ReaderBookmark:addToMainMenu(menu_items) self:onShowBookmark() end, } - if not Device:isTouchDevice() and not ( Device:hasScreenKB() or Device:hasSymKey() ) then + if not Device:isTouchDevice() and not (Device:hasScreenKB() or Device:hasSymKey()) then menu_items.toggle_bookmark = { text_func = function() return self:isPageBookmarked() and _("Remove bookmark for current page") or _("Bookmark current page") @@ -128,24 +106,57 @@ function ReaderBookmark:addToMainMenu(menu_items) menu_items.bookmarks_settings = { text = _("Bookmarks"), sub_item_table = { + { + text_func = function() + return T(_("Max lines per bookmark: %1"), self.items_max_lines or _("disabled")) + end, + keep_menu_open = true, + callback = function(touchmenu_instance) + local default_value = 4 + local spin_wodget = SpinWidget:new{ + title_text = _("Max lines per bookmark"), + info_text = _("Set maximum number of lines to enable flexible item heights."), + value = self.items_max_lines or default_value, + value_min = 1, + value_max = 10, + default_value = default_value, + ok_always_enabled = true, + callback = function(spin) + G_reader_settings:saveSetting("bookmarks_items_max_lines", spin.value) + self.items_max_lines = spin.value + touchmenu_instance:updateItems() + end, + extra_text = _("Disable"), + extra_callback = function() + G_reader_settings:delSetting("bookmarks_items_max_lines") + self.items_max_lines = nil + touchmenu_instance:updateItems() + end, + } + UIManager:show(spin_wodget) + end, + }, { text_func = function() local curr_perpage = G_reader_settings:readSetting("bookmarks_items_per_page") return T(_("Bookmarks per page: %1"), curr_perpage) end, + enabled_func = function() + return not self.items_max_lines + end, keep_menu_open = true, callback = function(touchmenu_instance) local curr_perpage = G_reader_settings:readSetting("bookmarks_items_per_page") local items = SpinWidget:new{ + title_text = _("Bookmarks per page"), value = curr_perpage, value_min = 6, value_max = 24, - default_value = self.bookmarks_items_per_page_default, - title_text = _("Bookmarks per page"), + default_value = Menu.items_per_page_default, callback = function(spin) G_reader_settings:saveSetting("bookmarks_items_per_page", spin.value) - if touchmenu_instance then touchmenu_instance:updateItems() end - end + touchmenu_instance:updateItems() + end, } UIManager:show(items) end, @@ -163,21 +174,24 @@ function ReaderBookmark:addToMainMenu(menu_items) local default_font_size = Menu.getItemFontSize(curr_perpage) local curr_font_size = G_reader_settings:readSetting("bookmarks_items_font_size", default_font_size) local items_font = SpinWidget:new{ + title_text = _("Bookmark font size"), value = curr_font_size, value_min = 10, value_max = 72, default_value = default_font_size, - title_text = _("Bookmark font size"), callback = function(spin) G_reader_settings:saveSetting("bookmarks_items_font_size", spin.value) - if touchmenu_instance then touchmenu_instance:updateItems() end - end + touchmenu_instance:updateItems() + end, } UIManager:show(items_font) end, }, { text = _("Shrink bookmark font size to fit more text"), + enabled_func = function() + return not self.items_max_lines + end, checked_func = function() return G_reader_settings:isTrue("bookmarks_items_multilines_show_more_text") end, @@ -186,6 +200,16 @@ function ReaderBookmark:addToMainMenu(menu_items) end, separator = true, }, + { + text_func = function() + return T(_("Show in items: %1"), self:genShowInItemsMenuItems()) + end, + sub_item_table = { + self:genShowInItemsMenuItems("text"), + self:genShowInItemsMenuItems("all"), + self:genShowInItemsMenuItems("note"), + }, + }, { text = _("Show separator between items"), checked_func = function() @@ -194,17 +218,7 @@ function ReaderBookmark:addToMainMenu(menu_items) callback = function() G_reader_settings:flipNilOrFalse("bookmarks_items_show_separator") end, - }, - { - text_func = function() - local curr_type = G_reader_settings:readSetting("bookmarks_items_text_type", "note") - return T(_("Show in items: %1"), self:genItemTextMenuItem(curr_type, true)) - end, - sub_item_table = { - self:genItemTextMenuItem("text"), - self:genItemTextMenuItem("all"), - self:genItemTextMenuItem("note"), - }, + separator = true, }, { text = _("Sort by largest page number"), @@ -228,6 +242,28 @@ function ReaderBookmark:addToMainMenu(menu_items) } end +function ReaderBookmark:genShowInItemsMenuItems(value) + local strings = { + text = _("highlighted text"), + all = _("highlighted text and note"), + note = _("note, or highlighted text"), + } + if value == nil then + value = G_reader_settings:readSetting("bookmarks_items_text_type", "note") + return strings[value] + end + return { + text = strings[value], + checked_func = function() + return self.items_text == value + end, + callback = function() + self.items_text = value + G_reader_settings:saveSetting("bookmarks_items_text_type", value) + end, + } +end + -- page bookmarks, dogear function ReaderBookmark:onToggleBookmark() @@ -574,13 +610,13 @@ function ReaderBookmark:onShowBookmark() } local bm_menu = Menu:new{ title = T(_("Bookmarks (%1)"), #item_table), - subtitle = "", item_table = item_table, is_borderless = true, is_popout = false, title_bar_fm_style = true, items_per_page = items_per_page, items_font_size = items_font_size, + items_max_lines = self.items_max_lines, multilines_show_more_text = multilines_show_more_text, line_color = show_separator and Blitbuffer.COLOR_DARK_GRAY or Blitbuffer.COLOR_WHITE, title_bar_left_icon = "appbar.menu", @@ -1303,6 +1339,7 @@ function ReaderBookmark:onSearchBookmark() UIManager:show(input_dialog) input_dialog:onShowKeyboard() + return true end function ReaderBookmark:filterByEditedText() diff --git a/frontend/ui/widget/menu.lua b/frontend/ui/widget/menu.lua index 674f555dc..fa2e933a6 100644 --- a/frontend/ui/widget/menu.lua +++ b/frontend/ui/widget/menu.lua @@ -103,7 +103,7 @@ function MenuItem:init() local shortcut_icon_dimen if self.shortcut then - local icon_width = math.floor(self.dimen.h * 4/5) + local icon_width = self.entry.shortcut_icon_width or math.floor(self.dimen.h * 4/5) shortcut_icon_dimen = Geom:new{ x = 0, y = 0, @@ -374,7 +374,7 @@ function MenuItem:init() text = text, face = self.face, width = available_width, - height = max_item_height, + height = self.entry.height and (self.entry.height - 2 * Size.span.vertical_default - self.linesize) or max_item_height, height_adjust = true, height_overflow_show_ellipsis = true, alignment = "left", @@ -589,13 +589,14 @@ local Menu = FocusManager:extend{ header_padding = Size.padding.default, dimen = nil, item_table = nil, -- NOT mandatory (will be empty) + item_table_stack = nil, + item_shortcuts = { -- const "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Del", "Z", "X", "C", "V", "B", "N", "M", ".", "Sym", }, - item_table_stack = nil, - is_enable_shortcut = true, + is_enable_shortcut = Device:hasKeyboard(), item_dimen = nil, page = 1, @@ -610,6 +611,9 @@ local Menu = FocusManager:extend{ items_mandatory_font_size = nil, multilines_show_more_text = nil, -- Global settings or default values will be used if not provided + -- Setting this to a number enables flexible height of items + -- and sets the maximum number of lines in an item, longer items are truncated + items_max_lines = nil, -- set this to true to not paint as popup menu is_borderless = false, @@ -628,8 +632,10 @@ local Menu = FocusManager:extend{ function Menu:_recalculateDimen(no_recalculate_dimen) local perpage = self.items_per_page or G_reader_settings:readSetting("items_per_page") or self.items_per_page_default - if self.perpage ~= perpage then + local font_size = self.items_font_size or G_reader_settings:readSetting("items_font_size") or Menu.getItemFontSize(perpage) + if self.perpage ~= perpage or self.font_size ~= font_size then self.perpage = perpage + self.font_size = font_size no_recalculate_dimen = false end @@ -654,6 +660,10 @@ function Menu:_recalculateDimen(no_recalculate_dimen) h = math.floor(self.available_height / perpage), } + if self.items_max_lines then + self:setupItemHeights() + end + self.page_num = self:getPageNumber(#self.item_table) if self.page > self.page_num then self.page = self.page_num @@ -950,11 +960,6 @@ function Menu:init() } self.ges_events.Close = self.on_close_ges - if not Device:hasKeyboard() then - -- remove menu item shortcut for K4 - self.is_enable_shortcut = false - end - if Device:hasKeys() then -- set up keyboard events self.key_events.Close = { { Input.group.Back } } @@ -1036,17 +1041,21 @@ function Menu:updateItems(select_number, no_recalculate_dimen) select_number = 1 end - self.font_size = self.items_font_size or G_reader_settings:readSetting("items_font_size") - or Menu.getItemFontSize(self.perpage) - local infont_size = self.items_mandatory_font_size or (self.font_size - 4) - local multilines_show_more_text = self.multilines_show_more_text - if multilines_show_more_text == nil then - multilines_show_more_text = G_reader_settings:isTrue("items_multilines_show_more_text") + local items_nb -- number of items in the visible page + local idx_offset, multilines_show_more_text + if self.items_max_lines then + items_nb = #self.page_items[self.page] + else + items_nb = self.perpage + idx_offset = (self.page - 1) * items_nb + multilines_show_more_text = self.multilines_show_more_text + if multilines_show_more_text == nil then + multilines_show_more_text = G_reader_settings:isTrue("items_multilines_show_more_text") + end end - local idx_offset = (self.page - 1) * self.perpage - for idx = 1, self.perpage do - local index = idx_offset + idx + for idx = 1, items_nb do + local index = self.items_max_lines and self.page_items[self.page][idx] or idx_offset + idx local item = self.item_table[index] if item == nil then break end item.idx = index -- index is valid only for items that have been displayed @@ -1056,6 +1065,9 @@ function Menu:updateItems(select_number, no_recalculate_dimen) -- give different shortcut_style to keys in different lines of keyboard shortcut_style = (idx < 11 or idx > 20) and "square" or "grey_square" end + if self.items_max_lines then + self.item_dimen.h = item.height + end local item_tmp = MenuItem:new{ show_parent = self.show_parent, state_w = self.state_w, @@ -1068,7 +1080,7 @@ function Menu:updateItems(select_number, no_recalculate_dimen) bold = self.item_table.current == index or item.bold == true, dim = item.dim, font_size = self.font_size, - infont_size = infont_size, + infont_size = self.items_mandatory_font_size or (self.font_size - 4), dimen = self.item_dimen:copy(), shortcut = item_shortcut, shortcut_style = shortcut_style, @@ -1176,7 +1188,71 @@ function Menu:getPageNumber(item_number) if #self.item_table == 0 or item_number == 0 then return 1 end - return math.ceil(math.min(item_number, #self.item_table) / self.perpage) + if self.items_max_lines then + for page, items in ipairs(self.page_items) do + if item_number <= items[#items] then + return page + end + end + return #self.page_items + else + return math.ceil(math.min(item_number, #self.item_table) / self.perpage) + end +end + +function Menu:setupItemHeights() + if #self.item_table == 0 then + self.page_items = {{}} + return + end + + local face = Font:getFace("smallinfofont", self.font_size) + local line_height = TextBoxWidget:new{ + text = "A", + face = face, + }:getSize().h + local infont_size = self.items_mandatory_font_size or (self.font_size - 4) + local infont_face = Font:getFace("infont", infont_size) + local infont_char_width = TextWidget:new{ + text = "0", + face = infont_face, + bold = true, + }:getSize().w + local available_width = self.inner_dimen.w + if self.is_enable_shortcut then + available_width = available_width - line_height - Size.span.horizontal_default + end + + self.page_items = {} -- list of all 'items in the page' indexed by page + local items = {} -- items in a page + local items_height = 0 -- of all items in a page + for i = 1, #self.item_table do + local item = self.item_table[i] + -- exact item height can be calculated by building the TextBoxWidget for item text, + -- but it is slow, so estimate the number of lines by building the TextWidget + local item_text_width = TextWidget:new{ + text = item.text, + face = face, + bold = item.bold, + }:getSize().w + local item_available_width = available_width - infont_char_width * (item.mandatory and #item.mandatory or 0) + local lines_nb = math.min(math.ceil(item_text_width / item_available_width), self.items_max_lines) + item.height = lines_nb * line_height + 2 * Size.span.vertical_default + self.linesize + item.shortcut_icon_width = line_height -- letter shortcuts of fixed size (1 line) + + -- put items in pages + items_height = items_height + item.height + if items_height <= self.available_height then + table.insert(items, i) + else -- start building next page + table.insert(self.page_items, items) + items = { i } + items_height = item.height + end + if i == #self.item_table then -- last page + table.insert(self.page_items, items) + end + end end function Menu:onScreenResize(dimen)