From d6d49a64a79bf07820651ee2418ed6d1c5a3ed59 Mon Sep 17 00:00:00 2001 From: poire-z Date: Fri, 6 Dec 2019 22:55:35 +0100 Subject: [PATCH] [RTL UI] use auto or LTR text direction in some specific cases Allow TextBoxWidget new text direction/lang parameters to be set on upper widgets, and propagate them all the way to it (ScrollTextWidget, InputText, InputDialog, TextViewer). Use specific non-default ones in some specific cases: - Force LTR text direction when showing HTML and CSS, and configuration files (in some plugins). - Use Wikipedia server language and text direction when showing an article. - Use auto with Dictionary results, as we don't know the dictionary language, and they may contain mixed content. - Force LTR when showing some paths (still needs more of them) TextEditor plugin: add 2 new options "Auto paragraph direction" and "Force paragraph direction LTR". Footnotes popup: grab HTML direction, and forward it to MuPDF for proper display. --- frontend/apps/filemanager/filemanager.lua | 1 + .../apps/reader/modules/readerhighlight.lua | 6 +++ frontend/apps/reader/modules/readerlink.lua | 7 ++-- .../apps/reader/modules/readerstyletweak.lua | 1 + .../apps/reader/modules/readerwikipedia.lua | 1 + frontend/ui/widget/dictquicklookup.lua | 4 ++ frontend/ui/widget/inputdialog.lua | 17 +++++++++ frontend/ui/widget/inputtext.lua | 23 ++++++++++++ frontend/ui/widget/menu.lua | 1 + frontend/ui/widget/multiinputdialog.lua | 9 ++++- frontend/ui/widget/scrolltextwidget.lua | 15 +++++++- frontend/ui/widget/textviewer.lua | 16 ++++++++ frontend/ui/wikipedia.lua | 9 ++++- plugins/docsettingtweak.koplugin/main.lua | 1 + plugins/newsdownloader.koplugin/main.lua | 1 + plugins/terminal.koplugin/main.lua | 1 + plugins/texteditor.koplugin/main.lua | 37 +++++++++++++++++++ 17 files changed, 142 insertions(+), 8 deletions(-) diff --git a/frontend/apps/filemanager/filemanager.lua b/frontend/apps/filemanager/filemanager.lua index 14decd523..513b90fab 100644 --- a/frontend/apps/filemanager/filemanager.lua +++ b/frontend/apps/filemanager/filemanager.lua @@ -109,6 +109,7 @@ function FileManager:init() self.path_text = TextWidget:new{ face = Font:getFace("xx_smallinfofont"), text = filemanagerutil.abbreviate(self.root_path), + para_direction_rtl = false, -- force LTR max_width = Screen:getWidth() - 2*Size.padding.small, truncate_left = true, } diff --git a/frontend/apps/reader/modules/readerhighlight.lua b/frontend/apps/reader/modules/readerhighlight.lua index 407ceb369..6538ca4ab 100644 --- a/frontend/apps/reader/modules/readerhighlight.lua +++ b/frontend/apps/reader/modules/readerhighlight.lua @@ -781,6 +781,8 @@ function ReaderHighlight:viewSelectionHTML(debug_view) text = css_text or _("Failed getting CSS content"), text_face = Font:getFace("smallinfont"), justified = false, + para_direction_rtl = false, + auto_para_direction = false, buttons_table = { {{ text = _("Prettify"), @@ -792,6 +794,8 @@ function ReaderHighlight:viewSelectionHTML(debug_view) text = prettifyCss(css_text), text_face = Font:getFace("smallinfont"), justified = false, + para_direction_rtl = false, + auto_para_direction = false, }) end, }}, @@ -838,6 +842,8 @@ function ReaderHighlight:viewSelectionHTML(debug_view) text = html, text_face = Font:getFace("smallinfont"), justified = false, + para_direction_rtl = false, + auto_para_direction = false, buttons_table = buttons_table, } UIManager:show(textviewer) diff --git a/frontend/apps/reader/modules/readerlink.lua b/frontend/apps/reader/modules/readerlink.lua index 5b76acb3d..4d997ff27 100644 --- a/frontend/apps/reader/modules/readerlink.lua +++ b/frontend/apps/reader/modules/readerlink.lua @@ -1062,12 +1062,13 @@ function ReaderLink:showAsFootnotePopup(link, neglect_current_location) -- then just ignore the whole stylesheet, including our own declarations -- we add at start) -- - -- flags = 0x0000 to get the simplest/purest HTML without CSS + -- flags = 0x0001 to get the simplest/purest HTML without CSS, and dir= + -- and lang= attributes grabbed from parent nodes local html if extStartXP and extEndXP then - html = self.ui.document:getHTMLFromXPointers(extStartXP, extEndXP, 0x0000) + html = self.ui.document:getHTMLFromXPointers(extStartXP, extEndXP, 0x0001) else - html = self.ui.document:getHTMLFromXPointer(target_xpointer, 0x0000, true) + html = self.ui.document:getHTMLFromXPointer(target_xpointer, 0x0001, true) -- from_final_parent = true to get a possibly more complete footnote end if not html then diff --git a/frontend/apps/reader/modules/readerstyletweak.lua b/frontend/apps/reader/modules/readerstyletweak.lua index f69df86bf..e9eb9fae2 100644 --- a/frontend/apps/reader/modules/readerstyletweak.lua +++ b/frontend/apps/reader/modules/readerstyletweak.lua @@ -97,6 +97,7 @@ function TweakInfoWidget:init() text = css, face = Font:getFace("infont", 16), width = self.width - 2*Size.padding.large, + para_direction_rtl = false, -- LTR } }) if self.is_global_default then diff --git a/frontend/apps/reader/modules/readerwikipedia.lua b/frontend/apps/reader/modules/readerwikipedia.lua index bbddd6ed8..889a606ac 100644 --- a/frontend/apps/reader/modules/readerwikipedia.lua +++ b/frontend/apps/reader/modules/readerwikipedia.lua @@ -488,6 +488,7 @@ function ReaderWikipedia:lookupWikipedia(word, box, get_fullpage, forced_lang) definition = definition, is_fullpage = get_fullpage, lang = lang, + rtl_lang = Wikipedia:isWikipediaLanguageRTL(lang), images = page.images, } table.insert(results, result) diff --git a/frontend/ui/widget/dictquicklookup.lua b/frontend/ui/widget/dictquicklookup.lua index 28c577f82..462c859f5 100644 --- a/frontend/ui/widget/dictquicklookup.lua +++ b/frontend/ui/widget/dictquicklookup.lua @@ -312,6 +312,9 @@ function DictQuickLookup:update() dialog = self, -- allow for disabling justification justified = G_reader_settings:nilOrTrue("dict_justify"), + lang = self.lang and self.lang:lower(), -- only available on wikipedia results + para_direction_rtl = self.rtl_lang, -- only available on wikipedia results + auto_para_direction = not self.is_wiki, -- only for dict results (we don't know their lang) image_alt_face = self.image_alt_face, images = self.images, } @@ -659,6 +662,7 @@ function DictQuickLookup:changeDictionary(index) self.is_html = self.results[index].is_html self.css = self.results[index].css self.lang = self.results[index].lang + self.rtl_lang = self.results[index].rtl_lang self.images = self.results[index].images if self.images and #self.images > 0 then -- We'll be giving some images to textboxwidget that will diff --git a/frontend/ui/widget/inputdialog.lua b/frontend/ui/widget/inputdialog.lua index 5cbf3e970..4f7dccf85 100644 --- a/frontend/ui/widget/inputdialog.lua +++ b/frontend/ui/widget/inputdialog.lua @@ -181,6 +181,14 @@ local InputDialog = InputContainer:new{ button_padding = Size.padding.default, border_size = Size.border.window, + -- See TextBoxWidget for details about these options + alignment = "left", + justified = false, + lang = nil, + para_direction_rtl = nil, + auto_para_direction = false, + alignment_strict = false, + -- for internal use _text_modified = false, -- previous known modified status _top_line_num = nil, @@ -307,6 +315,9 @@ function InputDialog:init() width = self.text_width, padding = self.input_padding, margin = self.input_margin, + lang = self.lang, -- these might influence height + para_direction_rtl = self.para_direction_rtl, + auto_para_direction = self.auto_para_direction, } local text_height = input_widget:getTextHeight() local line_height = input_widget:getLineHeight() @@ -351,6 +362,12 @@ function InputDialog:init() text = self.input, hint = self.input_hint, face = self.input_face, + alignment = self.alignment, + justified = self.justified, + lang = self.lang, + para_direction_rtl = self.para_direction_rtl, + auto_para_direction = self.auto_para_direction, + alignment_strict = self.alignment_strict, width = self.text_width, height = self.text_height or nil, padding = self.input_padding, diff --git a/frontend/ui/widget/inputtext.lua b/frontend/ui/widget/inputtext.lua index 9684e7d96..b9af9f5bd 100644 --- a/frontend/ui/widget/inputtext.lua +++ b/frontend/ui/widget/inputtext.lua @@ -42,6 +42,14 @@ local InputText = InputContainer:new{ margin = Size.margin.default, bordersize = Size.border.inputtext, + -- See TextBoxWidget for details about these options + alignment = "left", + justified = false, + lang = nil, + para_direction_rtl = nil, + auto_para_direction = false, + alignment_strict = false, + -- for internal use text_widget = nil, -- Text Widget for cursor movement, possibly a ScrollTextWidget charlist = nil, -- table of individual chars from input string @@ -308,6 +316,9 @@ function InputText:initTextBox(text, char_added) charlist = show_charlist, face = self.face, width = text_width, + lang = self.lang, -- these might influence height + para_direction_rtl = self.para_direction_rtl, + auto_para_direction = self.auto_para_direction, } self.height = text_widget:getTextHeight() self.scroll = true @@ -322,6 +333,12 @@ function InputText:initTextBox(text, char_added) editable = self.focused, face = self.face, fgcolor = fgcolor, + alignment = self.alignment, + justified = self.justified, + lang = self.lang, + para_direction_rtl = self.para_direction_rtl, + auto_para_direction = self.auto_para_direction, + alignment_strict = self.alignment_strict, width = self.width, height = self.height, dialog = self.parent, @@ -337,6 +354,12 @@ function InputText:initTextBox(text, char_added) editable = self.focused, face = self.face, fgcolor = fgcolor, + alignment = self.alignment, + justified = self.justified, + lang = self.lang, + para_direction_rtl = self.para_direction_rtl, + auto_para_direction = self.auto_para_direction, + alignment_strict = self.alignment_strict, width = self.width, height = self.height, dialog = self.parent, diff --git a/frontend/ui/widget/menu.lua b/frontend/ui/widget/menu.lua index 618a6bdff..18655d89c 100644 --- a/frontend/ui/widget/menu.lua +++ b/frontend/ui/widget/menu.lua @@ -611,6 +611,7 @@ function Menu:init() self.path_text = TextWidget:new{ face = Font:getFace("xx_smallinfofont"), text = self.path, + para_direction_rtl = false, -- force LTR max_width = self.dimen.w - 2*Size.padding.small, truncate_left = true, } diff --git a/frontend/ui/widget/multiinputdialog.lua b/frontend/ui/widget/multiinputdialog.lua index f83ea761d..af3a1f775 100644 --- a/frontend/ui/widget/multiinputdialog.lua +++ b/frontend/ui/widget/multiinputdialog.lua @@ -17,8 +17,6 @@ local Screen = Device.screen local input_field, input_description local MultiInputDialog = InputDialog:extend{ - field = {}, - field_hint = {}, fields = {}, description_padding = Size.padding.default, description_margin = Size.margin.small, @@ -50,6 +48,13 @@ function MultiInputDialog:init() parent = self, padding = field.padding or nil, margin = field.margin or nil, + -- Allow these to be specified per field if needed + alignment = field.alignment or self.alignment, + justified = field.justified or self.justified, + lang = field.lang or self.lang, + para_direction_rtl = field.para_direction_rtl or self.para_direction_rtl, + auto_para_direction = field.auto_para_direction or self.auto_para_direction, + alignment_strict = field.alignment_strict or self.alignment_strict, } if Device:hasDPad() then -- little hack to piggyback on the layout of the button_table to handle the new InputText diff --git a/frontend/ui/widget/scrolltextwidget.lua b/frontend/ui/widget/scrolltextwidget.lua index c729ebd2b..1be9f1f90 100644 --- a/frontend/ui/widget/scrolltextwidget.lua +++ b/frontend/ui/widget/scrolltextwidget.lua @@ -22,7 +22,6 @@ local ScrollTextWidget = InputContainer:new{ charpos = nil, top_line_num = nil, editable = false, - justified = false, scroll_callback = nil, -- called with (low, high) when view is scrolled scroll_by_pan = false, -- allow scrolling by lines with Pan face = nil, @@ -33,6 +32,13 @@ local ScrollTextWidget = InputContainer:new{ text_scroll_span = Screen:scaleBySize(12), dialog = nil, images = nil, + -- See TextBoxWidget for details about these options + alignment = "left", + justified = false, + lang = nil, + para_direction_rtl = nil, + auto_para_direction = false, + alignment_strict = false, } function ScrollTextWidget:init() @@ -43,13 +49,18 @@ function ScrollTextWidget:init() top_line_num = self.top_line_num, dialog = self.dialog, editable = self.editable, - justified = self.justified, face = self.face, image_alt_face = self.image_alt_face, fgcolor = self.fgcolor, width = self.width - self.scroll_bar_width - self.text_scroll_span, height = self.height, images = self.images, + alignment = self.alignment, + justified = self.justified, + lang = self.lang, + para_direction_rtl = self.para_direction_rtl, + auto_para_direction = self.auto_para_direction, + alignment_strict = self.alignment_strict, } local visible_line_count = self.text_widget:getVisLineCount() local total_line_count = self.text_widget:getAllLineCount() diff --git a/frontend/ui/widget/textviewer.lua b/frontend/ui/widget/textviewer.lua index ab5462810..43039046e 100644 --- a/frontend/ui/widget/textviewer.lua +++ b/frontend/ui/widget/textviewer.lua @@ -37,7 +37,18 @@ local TextViewer = InputContainer:new{ width = nil, height = nil, buttons_table = nil, + -- See TextBoxWidget for details about these options + -- We default to justified and auto_para_direction to adapt + -- to any kind of text we are given (book descriptions, + -- bookmarks' text, translation results...). + -- When used to display more technical text (HTML, CSS, + -- application logs...), it's best to reset them to false. + alignment = "left", justified = true, + lang = nil, + para_direction_rtl = nil, + auto_para_direction = true, + alignment_strict = false, title_face = Font:getFace("x_smalltfont"), text_face = Font:getFace("x_smallinfofont"), @@ -157,7 +168,12 @@ function TextViewer:init() width = self.width - 2*self.text_padding - 2*self.text_margin, height = textw_height - 2*self.text_padding -2*self.text_margin, dialog = self, + alignment = self.alignment, justified = self.justified, + lang = self.lang, + para_direction_rtl = self.para_direction_rtl, + auto_para_direction = self.auto_para_direction, + alignment_strict = self.alignment_strict, } self.textw = FrameContainer:new{ padding = self.text_padding, diff --git a/frontend/ui/wikipedia.lua b/frontend/ui/wikipedia.lua index 813476385..58e7c57f6 100644 --- a/frontend/ui/wikipedia.lua +++ b/frontend/ui/wikipedia.lua @@ -681,6 +681,13 @@ local rtl_wiki_code = { ks = "Kashmiri", } +function Wikipedia:isWikipediaLanguageRTL(lang) + if lang and rtl_wiki_code[lang:lower()] then + return true + end + return false +end + -- Create an epub file (with possibly images) function Wikipedia:createEpub(epub_path, page, lang, with_images) -- Use Trapper to display progress and ask questions through the UI. @@ -1298,7 +1305,7 @@ table { local see_online_version = T(_("See %1 for up-to-date content"), online_version_htmllink) -- Set dir= attribute on the HTML tag for RTL languages local html_dir = "" - if rtl_wiki_code[lang:lower()] then + if self:isWikipediaLanguageRTL(lang) then html_dir = ' dir="rtl"' end epub:add("OEBPS/content.html", string.format([[ diff --git a/plugins/docsettingtweak.koplugin/main.lua b/plugins/docsettingtweak.koplugin/main.lua index 7a6c27209..d8f8ab53f 100644 --- a/plugins/docsettingtweak.koplugin/main.lua +++ b/plugins/docsettingtweak.koplugin/main.lua @@ -51,6 +51,7 @@ function DocSettingTweak:editDirectoryDefaults() title = T(_("Directory Defaults: %1"),directory_defaults_path), input = defaults, input_type = "string", + para_direction_rtl = false, -- force LTR fullscreen = true, condensed = true, allow_newline = true, diff --git a/plugins/newsdownloader.koplugin/main.lua b/plugins/newsdownloader.koplugin/main.lua index 32d4c7991..40f6672d9 100644 --- a/plugins/newsdownloader.koplugin/main.lua +++ b/plugins/newsdownloader.koplugin/main.lua @@ -411,6 +411,7 @@ function NewsDownloader:changeFeedConfig() title = T(_("Config: %1"),feed_config_path), input = config, input_type = "string", + para_direction_rtl = false, -- force LTR fullscreen = true, condensed = true, allow_newline = true, diff --git a/plugins/terminal.koplugin/main.lua b/plugins/terminal.koplugin/main.lua index 62a3e4fe7..59dc82654 100644 --- a/plugins/terminal.koplugin/main.lua +++ b/plugins/terminal.koplugin/main.lua @@ -23,6 +23,7 @@ function Terminal:start() self.input = InputDialog:new{ title = _("Enter a command and press \"Execute\""), input = self.command, + para_direction_rtl = false, -- force LTR text_height = Screen:getHeight() * 0.4, input_type = "string", buttons = {{{ diff --git a/plugins/texteditor.koplugin/main.lua b/plugins/texteditor.koplugin/main.lua index e7afdff7f..1349c90ab 100644 --- a/plugins/texteditor.koplugin/main.lua +++ b/plugins/texteditor.koplugin/main.lua @@ -1,3 +1,4 @@ +local BD = require("ui/bidi") local ConfirmBox = require("ui/widget/confirmbox") local DataStorage = require("datastorage") local Font = require("ui/font") @@ -54,6 +55,8 @@ function TextEditor:loadSettings() if self.settings:readSetting("monospace_font") then self.monospace_font = self.settings:readSetting("monospace_font") end + self.auto_para_direction = self.settings:readSetting("auto_para_direction") or true + self.force_ltr_para_direction = self.settings:readSetting("force_ltr_para_direction") or false end function TextEditor:onFlushSettings() @@ -63,6 +66,8 @@ function TextEditor:onFlushSettings() self.settings:saveSetting("last_path", self.last_path) self.settings:saveSetting("font_face", self.font_face) self.settings:saveSetting("font_size", self.font_size) + self.settings:saveSetting("auto_para_direction", self.auto_para_direction) + self.settings:saveSetting("force_ltr_para_direction", self.force_ltr_para_direction) self.settings:flush() end end @@ -114,6 +119,32 @@ function TextEditor:getSubMenuItems() self.font_face = self.monospace_font end end, + separator = true, + }, + { + text = _("Auto paragraph direction"), + help_text = _([[ +Detect the direction of each paragraph in the text: align to the right paragraphs in languages such as Arabic and Hebrew…, while keeping other paragraphs aligned to the left. +If disabled, paragraphs align according to KOReader's language default direction.]]), + checked_func = function() + return self.auto_para_direction + end, + callback = function() + self.auto_para_direction = not self.auto_para_direction + end, + }, + { + text = _("Force paragraph direction LTR"), + help_text = _([[ +Force all text to be displayed Left-To-Right (LTR) and aligned to the left. +Enable this if you are mostly editing code, HTML, CSS…]]), + enabled_func = BD.rtlUIText, -- only useful for RTL users editing code + checked_func = function() + return BD.rtlUIText() and self.force_ltr_para_direction + end, + callback = function() + self.force_ltr_para_direction = not self.force_ltr_para_direction + end, }, }, separator = true, @@ -405,10 +436,16 @@ function TextEditor:editFile(file_path, readonly) local filename_without_suffix, filetype = util.splitFileNameSuffix(filename) -- luacheck: no unused local is_lua = filetype:lower() == "lua" local input + local para_direction_rtl = nil -- use UI language direction + if self.force_ltr_para_direction then + para_direction_rtl = false -- force LTR + end input = InputDialog:new{ title = filename, input = self:readFileContent(file_path), input_face = Font:getFace(self.font_face, self.font_size), + para_direction_rtl = para_direction_rtl, + auto_para_direction = self.auto_para_direction, fullscreen = true, condensed = true, allow_newline = true,