You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koreader/frontend/ui/elements/font_ui_fallbacks.lua

162 lines
6.3 KiB
Lua

local FFIUtil = require("ffi/util")
local Font = require("ui/font")
local FontList = require("fontlist")
local InfoMessage = require("ui/widget/infomessage")
local UIManager = require("ui/uimanager")
local util = require("util")
local _ = require("gettext")
local T = FFIUtil.template
-- Some "Noto Sans *" fonts are already in ui/font.lua Font.fallbacks,
-- because they are required to display supported UI languages.
-- Don't allow them to be disabled.
-- Duplicated from (and should be kept in sync with) ui/font.lua, but here
-- by face name and there by font file/path name.
local hardcoded_fallbacks = {
"Noto Sans CJK SC",
"Noto Sans Arabic UI",
"Noto Sans Devanagari UI",
"Noto Sans Bengali UI",
}
-- Add any user font after Noto Sans CJK SC in the menu
local additional_fallback_insert_indice = 2 -- (indice in the above list)
local alt_name = {
-- Make it clear this "CJK SC" font actually supports all other CJK variant
["Noto Sans CJK SC"] = "Noto Sans CJK SC (TC, JA, KO)"
}
local fallback_candidates = nil
local fallback_candidates_path_to_name = nil
local genFallbackCandidates = function()
if fallback_candidates then
return
end
fallback_candidates = {}
fallback_candidates_path_to_name = {}
for _, font_path in ipairs(FontList:getFontList()) do
local fontinfo = FontList.fontinfo[font_path] -- (NotoColorEmoji.tff happens to get no fontinfo)
if fontinfo and #fontinfo == 1 then -- Ignore font files with multiple faces
fontinfo = fontinfo[1]
if util.stringStartsWith(fontinfo.name, "Noto Sans ") and
not fontinfo.bold and not fontinfo.italic and
not fontinfo.serif and not fontinfo.mono then
fallback_candidates[fontinfo.name] = fontinfo
fallback_candidates_path_to_name[font_path] = fontinfo.name
end
end
end
end
local more_info_text = _([[
If some book titles, dictionary entries and such are not displayed well but shown as ￾￾ or <20><>, it may be necessary to download the required fonts for those languages. They can then be enabled as additional UI fallback fonts.
Fonts for many languages can be downloaded at:
https://fonts.google.com/noto
Only fonts named "Noto Sans xyz" or "Noto Sans xyz UI" (regular, not bold nor italic, not Serif) will be available in this menu.]])
local getSubMenuItems = function()
genFallbackCandidates()
-- Order the menu items in the order the fallback fonts are used
local seen_names = {}
local ordered_names = {}
local checked_names = {}
local enabled_names = {}
for _, name in ipairs(hardcoded_fallbacks) do
table.insert(ordered_names, name)
seen_names[name] = true
checked_names[name] = true
enabled_names[name] = false
end
if G_reader_settings:has("font_ui_fallbacks") then
local additional_fallbacks = G_reader_settings:readSetting("font_ui_fallbacks")
for i=#additional_fallbacks, 1, -1 do
local path = additional_fallbacks[i]
local name = fallback_candidates_path_to_name[path]
if not name or seen_names[name] then
-- No longer found, or made hardcoded: remove it
table.remove(additional_fallbacks, i)
else
table.insert(ordered_names, additional_fallback_insert_indice, name)
seen_names[name] = true
checked_names[name] = true
enabled_names[name] = true
end
end
if #additional_fallbacks == 0 then -- all removed
G_reader_settings:delSetting("font_ui_fallbacks")
end
end
local add_separator_idx = #ordered_names
for name, fontinfo in FFIUtil.orderedPairs(fallback_candidates) do
if not seen_names[name] then
table.insert(ordered_names, name)
checked_names[name] = false
enabled_names[name] = true
end
end
local menu_items = {
{
text = _("About additional UI fallback fonts"),
callback = function()
UIManager:show(InfoMessage:new{
text = more_info_text,
})
end,
keep_menu_open = true,
separator = true,
}
}
for idx, name in ipairs(ordered_names) do
local fontinfo = fallback_candidates[name]
local item = {
text = alt_name[name] or name,
separator = idx == add_separator_idx,
checked_func = function()
return checked_names[name]
end,
enabled_func = function()
return enabled_names[name]
end,
callback = function()
local additional_fallbacks = G_reader_settings:readSetting("font_ui_fallbacks", {})
if checked_names[name] then -- enabled: remove it
for i=#additional_fallbacks, 1, -1 do
if additional_fallbacks[i] == fontinfo.path then
table.remove(additional_fallbacks, i)
if #additional_fallbacks == 0 then
G_reader_settings:delSetting("font_ui_fallbacks")
end
break
end
end
checked_names[name] = false
else -- disabled: add it
if #additional_fallbacks < Font.additional_fallback_max_nb then
table.insert(additional_fallbacks, 1, fontinfo.path)
checked_names[name] = true
else
UIManager:show(InfoMessage:new{
text = T(_("The number of allowed additional fallback fonts is limited to %1.\nUncheck some of them if you want to add this one."), Font.additional_fallback_max_nb),
})
return
end
end
UIManager:show(InfoMessage:new{
text = _("This will take effect on next restart."),
})
end,
}
table.insert(menu_items, item)
end
return menu_items
end
return {
text = _("Additional UI fallback fonts"),
sub_item_table_func = getSubMenuItems,
}