diff --git a/frontend/apps/reader/modules/readerfont.lua b/frontend/apps/reader/modules/readerfont.lua index d6ea6a45b..3cb7aad71 100644 --- a/frontend/apps/reader/modules/readerfont.lua +++ b/frontend/apps/reader/modules/readerfont.lua @@ -14,8 +14,10 @@ local Notification = require("ui/widget/notification") local Screen = require("device").screen local UIManager = require("ui/uimanager") local cre -- Delayed loading -local T = require("ffi/util").template +local logger = require("logger") +local util = require("util") local _ = require("gettext") +local T = require("ffi/util").template local C_ = _.pgettext local optionsutil = require("ui/data/optionsutil") @@ -30,8 +32,19 @@ local ReaderFont = InputContainer:extend{ steps = {0,1,1,1,1,1,2,2,2,3,3,3,4,4,5}, } +-- Keep a list of the new fonts seen at launch +local newly_added_fonts = nil -- not yet filled + function ReaderFont:init() self:registerKeyEvents() + self:setupFaceMenuTable() + self.ui.menu:registerToMainMenu(self) + -- NOP our own gesture handling + self.ges_events = nil +end + +function ReaderFont:setupFaceMenuTable() + logger.dbg("building font face menu table") -- Build face_table for menu self.face_table = {} -- Font settings @@ -62,6 +75,7 @@ function ReaderFont:init() -- Font list cre = require("document/credocument"):engineInit() local face_list = cre.getFontFaces() + face_list = self:sortFaceList(face_list) for k, v in ipairs(face_list) do local font_filename, font_faceindex, is_monospace = cre.getFontFaceFilenameAndFaceIndex(v) table.insert(self.face_table, { @@ -86,6 +100,9 @@ function ReaderFont:init() if v == fallback_font then text = text .. " �" end + if newly_added_fonts[v] then + text = text .. " \u{EA93}" -- "NEW" in a black square, from nerdfont + end return text end, font_func = function(size) @@ -97,6 +114,10 @@ function ReaderFont:init() end, callback = function() self:onSetFont(v) + -- We add it to the recently selected list only for tap on the + -- menu item (and not when :onSetFont() would be triggered by + -- a gesture/profile), which may be convenient for some users. + self:addToRecentlySelectedList(v) end, hold_callback = function(touchmenu_instance) self:makeDefault(v, is_monospace, touchmenu_instance) @@ -107,13 +128,18 @@ function ReaderFont:init() menu_item_id = v, }) end + self.face_table.refresh_func = function() + self:setupFaceMenuTable() + -- This might be used by TouchMenu to refresh its font list menu, + -- so return the newly created menu table. + return self.face_table + end self.face_table.open_on_menu_item_id_func = function() return self.font_face end - self.ui.menu:registerToMainMenu(self) - - -- NOP our own gesture handling - self.ges_events = nil + -- Have TouchMenu show half of the usual nb of items, so we + -- have more room to see how the text looks with that font + self.face_table.max_per_page = 5 end function ReaderFont:onGesture() end @@ -393,15 +419,17 @@ function ReaderFont:makeDefault(face, is_monospace, touchmenu_instance) end function ReaderFont:addToMainMenu(menu_items) - -- Have TouchMenu show half of the usual nb of items, so we - -- have more room to see how the text looks with that font - self.face_table.max_per_page = 5 -- insert table to main reader menu menu_items.change_font = { text_func = function() return T(_("Font: %1"), BD.wrap(self.font_face)) end, - sub_item_table = self.face_table, + sub_item_table_func = function() + if self.face_table.needs_refresh and self.face_table.refresh_func then + self.face_table.refresh_func() + end + return self.face_table + end } end @@ -723,6 +751,35 @@ function ReaderFont:getFontSettingsTable() G_reader_settings:flipNilOrTrue("font_menu_use_font_face") end, help_text = _([[In the font menu, display each font name with its own font face.]]), + }) + + table.insert(settings_table, { + text = _("Sort fonts by recently selected"), + checked_func = function() + return G_reader_settings:isTrue("font_menu_sort_by_recently_selected") + end, + callback = function() + G_reader_settings:flipTrue("font_menu_sort_by_recently_selected") + self.face_table.needs_refresh = true + end, + hold_callback = function() + UIManager:show(ConfirmBox:new{ + text = _([[ +The font list menu can show fonts sorted by name or by most recently selected. +New fonts discovered at KOReader startup will be shown first. + +Do you want to clear the history of selected fonts?]]), + ok_text = _("Clear"), + ok_callback = function() + G_reader_settings:delSetting("cre_fonts_recently_selected") + -- Recreate it now, sorted alphabetically (we may not go visit + -- and refresh the font menu until quit, but we want to be able + -- to notice newly added fonts at next startup). + self:sortFaceList(cre.getFontFaces()) + self.face_table.needs_refresh = true + end, + }) + end, separator = true, }) @@ -808,6 +865,65 @@ This setting allows scaling all monospace fonts by this percentage so they can f return settings_table end +function ReaderFont:addToRecentlySelectedList(face) + local idx = util.arrayContains(self.fonts_recently_selected, face) + if idx then + table.remove(self.fonts_recently_selected, idx) + end + table.insert(self.fonts_recently_selected, 1, face) + if G_reader_settings:isTrue("font_menu_sort_by_recently_selected") then + self.face_table.needs_refresh = true + end +end + +function ReaderFont:sortFaceList(face_list) + self.fonts_recently_selected = G_reader_settings:readSetting("cre_fonts_recently_selected") + if not self.fonts_recently_selected then + -- Init this list with the alphabetical list we got + self.fonts_recently_selected = face_list + G_reader_settings:saveSetting("cre_fonts_recently_selected", self.fonts_recently_selected) + -- We got no list of previously known fonts, so we can't say which are new. + newly_added_fonts = {} + return face_list + end + if not newly_added_fonts then + -- First call after launch: check for fonts not yet known + newly_added_fonts = {} + local seen_fonts = {} + for _, face in ipairs(self.fonts_recently_selected) do + seen_fonts[face] = false -- was there last time, might no longer be now + end + for _, face in ipairs(face_list) do + if seen_fonts[face] == nil then -- not known + newly_added_fonts[face] = true + -- Add newly seen fonts at start of the recently set list, + -- so the user can see and test them more easily. + table.insert(self.fonts_recently_selected, 1, face) + end + seen_fonts[face] = true + end + -- Remove no-longer-there fonts from our list + util.arrayRemove(self.fonts_recently_selected, function(t, i, j) + return seen_fonts[t[i]] + end) + end + if G_reader_settings:isTrue("font_menu_sort_by_recently_selected") then + return self.fonts_recently_selected + end + -- Otherwise, return face_list as we got it, alphabetically (as sorted by crengine), + -- but still with newly added fonts first + if next(newly_added_fonts) then + local move_idx = 1 + for i=1, #face_list do + if newly_added_fonts[face_list[i]] then + table.insert(face_list, move_idx, table.remove(face_list, i)) + move_idx = move_idx + 1 + end + end + end + return face_list +end + -- Default sample file local FONT_TEST_DEFAULT_SAMPLE_PATH = "frontend/ui/elements/font-test-sample-default.template" -- Users can set their own sample file, that will be used if found diff --git a/frontend/ui/widget/touchmenu.lua b/frontend/ui/widget/touchmenu.lua index dea9bb39c..864e375a8 100644 --- a/frontend/ui/widget/touchmenu.lua +++ b/frontend/ui/widget/touchmenu.lua @@ -798,6 +798,11 @@ end function TouchMenu:backToUpperMenu(no_close) if #self.item_table_stack ~= 0 then self.item_table = table.remove(self.item_table_stack) + -- Allow a menu table to refresh itself when going up (ie. from a setting + -- submenu that may want to have its parent menu updated). + if self.item_table.needs_refresh and self.item_table.refresh_func then + self.item_table = self.item_table.refresh_func() + end self.page = 1 if self.parent_id then self:_recalculatePageLayout() -- we need an accurate self.perpage