From fc81c7db2453f9752171d481459bf9bb5795916b Mon Sep 17 00:00:00 2001 From: poire-z Date: Thu, 11 May 2023 20:23:47 +0200 Subject: [PATCH] DictQuickLookup: add button to show list of results Add a left button to the title bar to show the list of results as a popup. Dictionary: tap or long-press on that button give different view of the results. Wikipedia: request 30 results instead of 20, so we can show 15, 10 or 6 of them per page of that popup. --- .../apps/reader/modules/readerwikipedia.lua | 2 +- frontend/ui/widget/dictquicklookup.lua | 264 ++++++++++++++++++ frontend/ui/wikipedia.lua | 2 +- 3 files changed, 266 insertions(+), 2 deletions(-) diff --git a/frontend/apps/reader/modules/readerwikipedia.lua b/frontend/apps/reader/modules/readerwikipedia.lua index f38651edf..4c2fa0c75 100644 --- a/frontend/apps/reader/modules/readerwikipedia.lua +++ b/frontend/apps/reader/modules/readerwikipedia.lua @@ -488,7 +488,7 @@ function ReaderWikipedia:lookupWikipedia(word, is_sane, box, get_fullpage, force pages = sorted_pages end for pageid, page in pairs(pages) do - local definition = page.extract or no_result_text + local definition = page.extract or (page.length and _("No introduction.")) or no_result_text if page.length then -- we get 'length' only for intro results -- let's append it to definition so we know diff --git a/frontend/ui/widget/dictquicklookup.lua b/frontend/ui/widget/dictquicklookup.lua index fb6d90fe0..c170e9f11 100644 --- a/frontend/ui/widget/dictquicklookup.lua +++ b/frontend/ui/widget/dictquicklookup.lua @@ -1,5 +1,6 @@ local BD = require("ui/bidi") local Blitbuffer = require("ffi/blitbuffer") +local ButtonDialog = require("ui/widget/buttondialog") local ButtonTable = require("ui/widget/buttontable") local CenterContainer = require("ui/widget/container/centercontainer") local Device = require("device") @@ -216,7 +217,22 @@ function DictQuickLookup:init() align = self.is_wiki and "center" or "left", show_parent = self, lang = self.lang_out, + left_icon = "appbar.menu", + left_icon_tap_callback = function() + if self.is_wiki then + self:showWikiResultsMenu() + else + self:showResultsMenu() + end + end, + left_icon_hold_callback = not self.is_wiki and function() self:showResultsAltMenu() end or nil, } + -- Scrollable offsets of the various showResults* menus and submenus, + -- so we can reopen them in the same state they were when closed. + self.menu_scrolled_offsets = {} + -- We'll also need to close any opened such menu when closing this DictQuickLookup + -- (needed if closing all DictQuickLookups via long-press on Close on the top one) + self.menu_opened = {} -- This padding and the resulting width apply to the content -- below the title: lookup word and definition @@ -1120,6 +1136,11 @@ function DictQuickLookup:onTap(arg, ges_ev) end function DictQuickLookup:onClose(no_clear) + for menu, _ in pairs(self.menu_opened) do + UIManager:close(menu) + end + self.menu_opened = {} + UIManager:close(self) if self.update_wiki_languages_on_close then @@ -1318,4 +1339,247 @@ function DictQuickLookup:lookupWikipedia(get_fullpage, word, is_sane, lang) self.ui:handleEvent(Event:new("LookupWikipedia", word, is_sane, self.word_boxes, get_fullpage, lang)) end +function DictQuickLookup:showResultsMenu() + -- Show one row: "| word | dict |" for each result + local width = math.floor(self.width * 0.75) + local right_width = math.floor(width * 0.5) + local font_size = 18 + local button_dialog + local buttons = {} + for idx, result in ipairs(self.results) do + -- Show in bold the currently displayed result + local bold = idx == self.dict_index + local row = { + { + text = result.word, + lang = result.ifo_lang and result.ifo_lang.lang_in or nil, + font_size = font_size, + font_bold = bold, + align = "left", + callback = function() + self.menu_scrolled_offsets["main"] = button_dialog:getScrolledOffset() + self.menu_opened[button_dialog] = nil + UIManager:close(button_dialog) + self:changeDictionary(idx) + end, + hold_callback = function() + -- Allow doing another lookup with this result word + self.ui:handleEvent(Event:new("LookupWord", result.word)) + end, + }, + { + text = result.dict, + lang = result.ifo_lang and result.ifo_lang.lang_out or nil, + font_size = font_size, + font_bold = bold, + width = right_width, + callback = function() + self.menu_scrolled_offsets["main"] = button_dialog:getScrolledOffset() + self.menu_opened[button_dialog] = nil + UIManager:close(button_dialog) + self:changeDictionary(idx) + end, + }, + } + table.insert(buttons, row) + end + button_dialog = ButtonDialog:new{ + width = width, + -- We don't provide shrink_unneeded_width=true as it's ugly with small words + buttons = buttons, + anchor = function() + return self.dict_title.left_button.image.dimen, true -- pop down + end, + tap_close_callback = function() + self.menu_scrolled_offsets["main"] = button_dialog:getScrolledOffset() + self.menu_opened[button_dialog] = nil + end + } + button_dialog:setScrolledOffset(self.menu_scrolled_offsets["main"]) + self.menu_opened[button_dialog] = true + UIManager:show(button_dialog) +end + +function DictQuickLookup:showResultsAltMenu() + -- Alternative listing with long-press: + -- Show one row: "| dict | word or N results |" for each dictionary returning results + local dicts = {} + local dict_results = {} + for idx, result in ipairs(self.results) do + local dict = result.dict + if not dict_results[dict] then + dict_results[dict] = { idx } + table.insert(dicts, dict) + else + table.insert(dict_results[dict], idx) + end + end + local max_width = math.floor(self.width * 0.75) + local right_width = math.floor(max_width * 0.25) + local font_size = 18 + local button_dialog + local buttons = {} + for dictnum, dict in ipairs(dicts) do + local results = dict_results[dict] + local first_result = self.results[results[1]] + -- Show in bold only the currently displayed result's dict + local bold = util.arrayContains(results, self.dict_index) + local row = {{ + text = dict, + lang = first_result.ifo_lang and first_result.ifo_lang.lang_out or nil, + font_size = font_size, + font_bold = bold, + align = "left", + callback = function() + self.menu_scrolled_offsets["alt"] = button_dialog:getScrolledOffset() + self.menu_opened[button_dialog] = nil + UIManager:close(button_dialog) + self:changeDictionary(results[1]) + end, + }} + -- Right button + local button_id = "button"..dictnum + local text, lang, avoid_text_truncation, is_single_result, hold_callback + if #results == 1 then + -- Show the headword, possibly truncated (otherwise, long words + -- would get displayed in a really small font size). + -- If truncated, we'll show it full in a popup + text = first_result.word + lang = first_result.ifo_lang and first_result.ifo_lang.lang_in or nil + avoid_text_truncation = false + is_single_result = true + hold_callback = function() + -- Allow doing another lookup with this result word + self.ui:handleEvent(Event:new("LookupWord", first_result.word)) + end + else + text = T(_("%1 results"), #results) + end + local callback = function() + local source_button = button_dialog:getButtonById(button_id) + if is_single_result and not source_button.label_widget:isTruncated() then + -- Not truncated: jump directly to the result + self.menu_scrolled_offsets["alt"] = button_dialog:getScrolledOffset() + self.menu_opened[button_dialog] = nil + UIManager:close(button_dialog) + self:changeDictionary(results[1]) + return + end + local button_dialog2 + local buttons2 = {} + local lang2 = first_result.ifo_lang and first_result.ifo_lang.lang_in or nil -- same for all results + for res=1, #results do + table.insert(buttons2, {{ + text = self.results[results[res]].word, + lang = lang2, + font_size = font_size, + font_bold = results[res] == self.dict_index, + callback = function() + self.menu_scrolled_offsets["alt_sub"..dictnum] = button_dialog2:getScrolledOffset() + self.menu_opened[button_dialog2] = nil + UIManager:close(button_dialog2) + self.menu_scrolled_offsets["alt"] = button_dialog:getScrolledOffset() + self.menu_opened[button_dialog] = nil + UIManager:close(button_dialog) + self:changeDictionary(results[res]) + end, + hold_callback = function() + -- Allow doing another lookup with this result word + self.ui:handleEvent(Event:new("LookupWord", self.results[results[res]].word)) + end, + }}) + end + button_dialog2 = ButtonDialog:new{ + width = right_width*2, -- larger, to have room for long words + buttons = buttons2, + anchor = function() + return source_button.dimen, true -- pop down + end, + tap_close_callback = function() + self.menu_scrolled_offsets["alt_sub"..dictnum] = button_dialog2:getScrolledOffset() + self.menu_opened[button_dialog2] = nil + end + } + button_dialog2:setScrolledOffset(self.menu_scrolled_offsets["alt_sub"..dictnum]) + self.menu_opened[button_dialog2] = true + UIManager:show(button_dialog2) + end + table.insert(row, { + text = text, + lang = lang, + avoid_text_truncation = avoid_text_truncation, + font_size = font_size, + font_bold = bold, + width = right_width, + callback = callback, + hold_callback = hold_callback, + id = button_id, + }) + table.insert(buttons, row) + end + button_dialog = ButtonDialog:new{ + width = max_width, + shrink_unneeded_width = true, + buttons = buttons, + anchor = function() + return self.dict_title.left_button.image.dimen, true -- pop down + end, + tap_close_callback = function() + self.menu_scrolled_offsets["alt"] = button_dialog:getScrolledOffset() + self.menu_opened[button_dialog] = nil + end + } + button_dialog:setScrolledOffset(self.menu_scrolled_offsets["alt"]) + self.menu_opened[button_dialog] = true + UIManager:show(button_dialog) +end + +function DictQuickLookup:showWikiResultsMenu() + -- Show one row with each result's article title + local max_width = math.floor(self.width * 0.75) + local font_size = 18 + local button_dialog + local buttons = {} + for idx, result in ipairs(self.results) do + local bold = idx == self.dict_index + local row = {{ + text = result.word, + lang = result.lang, + font_size = font_size, + font_bold = bold, + align = "left", + callback = function() + self.menu_scrolled_offsets["wiki"] = button_dialog:getScrolledOffset() + self.menu_opened[button_dialog] = nil + UIManager:close(button_dialog) + self:changeDictionary(idx) + end, + hold_callback = function() + -- Allow doing another lookup with this result title + self:lookupWikipedia(false, result.word) + end, + }} + table.insert(buttons, row) + end + button_dialog = ButtonDialog:new{ + width = max_width, + shrink_unneeded_width = true, + buttons = buttons, + -- We requested 30 results, so we will probably be scrolling. + -- If we do, ensure we use these values (they will all make full pages + -- if we get 30 results), depending on what the screen height allows. + rows_per_page = { 15, 10, 6 }, + anchor = function() + return self.dict_title.left_button.image.dimen, true -- pop down + end, + tap_close_callback = function() + self.menu_scrolled_offsets["wiki"] = button_dialog:getScrolledOffset() + self.menu_opened[button_dialog] = nil + end + } + button_dialog:setScrolledOffset(self.menu_scrolled_offsets["wiki"]) + self.menu_opened[button_dialog] = true + UIManager:show(button_dialog) +end + return DictQuickLookup diff --git a/frontend/ui/wikipedia.lua b/frontend/ui/wikipedia.lua index c3eba1789..9a74c21a2 100644 --- a/frontend/ui/wikipedia.lua +++ b/frontend/ui/wikipedia.lua @@ -30,7 +30,7 @@ local Wikipedia = { generator = "search", gsrnamespace = "0", -- gsrsearch = nil, -- text to lookup, will be added below - gsrlimit = 20, -- max nb of results to get + gsrlimit = 30, -- max nb of results to get exlimit = "max", prop = "extracts|info|pageimages", -- 'extracts' to get text, 'info' to get full page length format = "json",