mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
readerhighlight: remove selected_word and use selected_text everywhere
There were two ways of specifing selected text for a highlight depending on whether it was a "single word" or text selected using hold-and-pan. In addition to being a bit more complicated than is necessary, with the addition of the language support plugin system (where the "single word" selected might be expanded), it makes more sense to simply use the same logic and table structure for both cases. The dictionary lookup special case (hold-without-pan triggering a dictionary lookup by default) still works as before. In addition, this patch fixes a minor inefficiency during dictionary quick lookup -- before this patch, the highlight would be re-selected because the quick lookup window is run concurrently and tries to fetch ReaderHighlight.selected_text but this is set to nil immediately after triggering the lookup. This is unnecessary because :clear() will be called anyway when the quick pop-up closes, and so clearing this can be left until then. Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
This commit is contained in:
committed by
Frans de Jonge
parent
3ffb4c1692
commit
7a0e3d5e68
@@ -398,8 +398,8 @@ function ReaderDictionary:addToMainMenu(menu_items)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderDictionary:onLookupWord(word, is_sane, box, highlight, link)
|
||||
logger.dbg("dict lookup word:", word, box)
|
||||
function ReaderDictionary:onLookupWord(word, is_sane, boxes, highlight, link)
|
||||
logger.dbg("dict lookup word:", word, boxes)
|
||||
-- escape quotes and other funny characters in word
|
||||
word = self:cleanSelection(word, is_sane)
|
||||
logger.dbg("dict stripped word:", word)
|
||||
@@ -408,7 +408,7 @@ function ReaderDictionary:onLookupWord(word, is_sane, box, highlight, link)
|
||||
|
||||
-- Wrapped through Trapper, as we may be using Trapper:dismissablePopen() in it
|
||||
Trapper:wrap(function()
|
||||
self:stardictLookup(word, self.enabled_dict_names, not self.disable_fuzzy_search, box, link)
|
||||
self:stardictLookup(word, self.enabled_dict_names, not self.disable_fuzzy_search, boxes, link)
|
||||
end)
|
||||
return true
|
||||
end
|
||||
@@ -447,7 +447,7 @@ function ReaderDictionary:onHtmlDictionaryLinkTapped(dictionary, link)
|
||||
|
||||
-- Wrapped through Trapper, as we may be using Trapper:dismissablePopen() in it
|
||||
Trapper:wrap(function()
|
||||
self:stardictLookup(word, {dictionary}, false, link_box, nil)
|
||||
self:stardictLookup(word, {dictionary}, false, {link_box}, nil)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -815,7 +815,7 @@ function ReaderDictionary:startSdcv(word, dict_names, fuzzy_search)
|
||||
return final_results
|
||||
end
|
||||
|
||||
function ReaderDictionary:stardictLookup(word, dict_names, fuzzy_search, box, link)
|
||||
function ReaderDictionary:stardictLookup(word, dict_names, fuzzy_search, boxes, link)
|
||||
if word == "" then
|
||||
return
|
||||
end
|
||||
@@ -859,7 +859,7 @@ function ReaderDictionary:stardictLookup(word, dict_names, fuzzy_search, box, li
|
||||
lookup_cancelled = false,
|
||||
}
|
||||
}
|
||||
self:showDict(word, nope, box, link)
|
||||
self:showDict(word, nope, boxes, link)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -877,10 +877,10 @@ function ReaderDictionary:stardictLookup(word, dict_names, fuzzy_search, box, li
|
||||
return
|
||||
end
|
||||
|
||||
self:showDict(word, tidyMarkup(results), box, link)
|
||||
self:showDict(word, tidyMarkup(results), boxes, link)
|
||||
end
|
||||
|
||||
function ReaderDictionary:showDict(word, results, box, link)
|
||||
function ReaderDictionary:showDict(word, results, boxes, link)
|
||||
if results and results[1] then
|
||||
logger.dbg("showing quick lookup window", word, results)
|
||||
self.dict_window = DictQuickLookup:new{
|
||||
@@ -893,7 +893,7 @@ function ReaderDictionary:showDict(word, results, box, link)
|
||||
-- selected link, if any
|
||||
selected_link = link,
|
||||
results = results,
|
||||
word_box = box,
|
||||
word_boxes = boxes,
|
||||
preferred_dictionaries = self.preferred_dictionaries,
|
||||
-- differentiate between dict and wiki
|
||||
is_wiki = self.is_wiki,
|
||||
|
||||
@@ -2,6 +2,7 @@ local BD = require("ui/bidi")
|
||||
local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local Device = require("device")
|
||||
local Event = require("ui/event")
|
||||
local Geom = require("ui/geometry")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local Notification = require("ui/widget/notification")
|
||||
@@ -436,6 +437,7 @@ function ReaderHighlight:clear(clear_id)
|
||||
self.restore_page_mode_func()
|
||||
self.restore_page_mode_func = nil
|
||||
end
|
||||
self.is_word_selection = false
|
||||
self.selected_text_start_xpointer = nil
|
||||
if self.hold_pos then
|
||||
self.hold_pos = nil
|
||||
@@ -844,7 +846,16 @@ function ReaderHighlight:onHold(arg, ges)
|
||||
local ok, word = pcall(self.ui.document.getWordFromPosition, self.ui.document, self.hold_pos)
|
||||
if ok and word then
|
||||
logger.dbg("selected word:", word)
|
||||
self.selected_word = word
|
||||
-- Convert "word selection" table to "text selection" table because we
|
||||
-- use text selections throughout readerhighlight.
|
||||
self.is_word_selection = true
|
||||
self.selected_text = {
|
||||
text = word.word or "",
|
||||
pos0 = word.pos0 or word.pos,
|
||||
pos1 = word.pos1 or word.pos,
|
||||
sboxes = word.sbox and { word.sbox },
|
||||
pboxes = word.pbox and { word.pbox },
|
||||
}
|
||||
local link = self.ui.link:getLinkFromGes(ges)
|
||||
self.selected_link = nil
|
||||
if link then
|
||||
@@ -852,15 +863,13 @@ function ReaderHighlight:onHold(arg, ges)
|
||||
self.selected_link = link
|
||||
end
|
||||
if self.ui.document.info.has_pages then
|
||||
local boxes = {}
|
||||
table.insert(boxes, self.selected_word.sbox)
|
||||
self.view.highlight.temp[self.hold_pos.page] = boxes
|
||||
self.view.highlight.temp[self.hold_pos.page] = self.selected_text.sboxes
|
||||
-- Unfortunately, getWordFromPosition() may not return good coordinates,
|
||||
-- so refresh the whole page
|
||||
UIManager:setDirty(self.dialog, "ui")
|
||||
else
|
||||
-- With crengine, getWordFromPosition() does return good coordinates
|
||||
UIManager:setDirty(self.dialog, "ui", self.selected_word.sbox)
|
||||
-- With crengine, getWordFromPosition() does return good coordinates.
|
||||
UIManager:setDirty(self.dialog, "ui", Geom.boundingBox(self.selected_text.sboxes))
|
||||
end
|
||||
self:_resetHoldTimer()
|
||||
if word.pos0 then
|
||||
@@ -992,6 +1001,7 @@ function ReaderHighlight:onHoldPan(_, ges)
|
||||
|
||||
local old_text = self.selected_text and self.selected_text.text
|
||||
self.selected_text = self.ui.document:getTextFromPositions(self.hold_pos, self.holdpan_pos)
|
||||
self.is_word_selection = false
|
||||
|
||||
if self.selected_text and self.selected_text.pos0 then
|
||||
if not self.selected_text_start_xpointer then
|
||||
@@ -1015,13 +1025,6 @@ function ReaderHighlight:onHoldPan(_, ges)
|
||||
logger.dbg("selected text:", self.selected_text)
|
||||
if self.selected_text then
|
||||
self.view.highlight.temp[self.hold_pos.page] = self.selected_text.sboxes
|
||||
-- remove selected word if hold moves out of word box
|
||||
if not self.selected_text.sboxes or #self.selected_text.sboxes == 0 then
|
||||
self.selected_word = nil
|
||||
elseif self.selected_word and not self.selected_word.sbox:contains(self.selected_text.sboxes[1]) or
|
||||
#self.selected_text.sboxes > 1 then
|
||||
self.selected_word = nil
|
||||
end
|
||||
end
|
||||
UIManager:setDirty(self.dialog, "ui")
|
||||
end
|
||||
@@ -1035,18 +1038,36 @@ You can download language data files for version 3.04 from https://tesseract-ocr
|
||||
|
||||
Copy the language data files for Tesseract 3.04 (e.g., eng.traineddata for English and spa.traineddata for Spanish) into koreader/data/tessdata]])
|
||||
|
||||
function ReaderHighlight:lookup(selected_word, selected_link)
|
||||
function ReaderHighlight:lookup(selected_text, selected_link)
|
||||
-- convert sboxes to word boxes
|
||||
local word_boxes = {}
|
||||
for i, sbox in ipairs(selected_text.sboxes) do
|
||||
word_boxes[i] = self.view:pageToScreenTransform(self.hold_pos.page, sbox)
|
||||
end
|
||||
|
||||
-- if we extracted text directly
|
||||
if selected_word.word and self.hold_pos then
|
||||
local word_box = self.view:pageToScreenTransform(self.hold_pos.page, selected_word.sbox)
|
||||
self.ui:handleEvent(Event:new("LookupWord", selected_word.word, false, word_box, self, selected_link))
|
||||
if selected_text.text and self.hold_pos then
|
||||
self.ui:handleEvent(Event:new("LookupWord", selected_text.text, false, word_boxes, self, selected_link))
|
||||
-- or we will do OCR
|
||||
elseif selected_word.sbox and self.hold_pos then
|
||||
local word = self.ui.document:getOCRWord(self.hold_pos.page, selected_word)
|
||||
logger.dbg("OCRed word:", word)
|
||||
if word and word ~= "" then
|
||||
local word_box = self.view:pageToScreenTransform(self.hold_pos.page, selected_word.sbox)
|
||||
self.ui:handleEvent(Event:new("LookupWord", word, false, word_box, self, selected_link))
|
||||
elseif selected_text.sboxes and self.hold_pos then
|
||||
local text = self.ui.document:getOCRText(self.hold_pos.page, selected_text.sboxes)
|
||||
if not text then
|
||||
-- getOCRText is not implemented in some document backends, but
|
||||
-- getOCRWord is implemented everywhere. As such, fall back to
|
||||
-- getOCRWord.
|
||||
text = ""
|
||||
for _, sbox in ipairs(selected_text.sboxes) do
|
||||
local word = self.ui.document:getOCRWord(self.hold_pos.page, { sbox = sbox })
|
||||
logger.dbg("OCRed word:", word)
|
||||
-- @fixme This might produce incorrect results on RTL text.
|
||||
if word and word ~= "" then
|
||||
text = text .. word
|
||||
end
|
||||
end
|
||||
end
|
||||
logger.dbg("OCRed text:", text)
|
||||
if text and text ~= "" then
|
||||
self.ui:handleEvent(Event:new("LookupWord", text, false, word_boxes, self, selected_link))
|
||||
else
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = info_message_ocr_text,
|
||||
@@ -1227,15 +1248,15 @@ function ReaderHighlight:onHoldRelease()
|
||||
end
|
||||
self.hold_last_tv = nil
|
||||
end
|
||||
if self.selected_word then -- single-word selection
|
||||
if self.is_word_selection then -- single-word selection
|
||||
if long_final_hold or G_reader_settings:isTrue("highlight_action_on_single_word") then
|
||||
-- Force a 0-distance pan to have a self.selected_text with this word,
|
||||
-- which will enable the highlight menu or action instead of dict lookup
|
||||
self:onHoldPan(nil, {pos=self.hold_ges_pos})
|
||||
self.is_word_selection = false
|
||||
end
|
||||
end
|
||||
|
||||
if self.selected_text then
|
||||
if self.is_word_selection then
|
||||
self:lookup(self.selected_text, self.selected_link)
|
||||
else
|
||||
local default_highlight_action = G_reader_settings:readSetting("default_highlight_action", "ask")
|
||||
if long_final_hold or default_highlight_action == "ask" then
|
||||
-- bypass default action and show popup if long final hold
|
||||
@@ -1257,9 +1278,6 @@ function ReaderHighlight:onHoldRelease()
|
||||
-- No self:onClose() to not remove the selected text
|
||||
-- which will have been the first search result
|
||||
end
|
||||
elseif self.selected_word then
|
||||
self:lookup(self.selected_word, self.selected_link)
|
||||
self.selected_word = nil
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -50,8 +50,8 @@ local DictQuickLookup = InputContainer:new{
|
||||
dict_index = 1,
|
||||
width = nil,
|
||||
height = nil,
|
||||
-- box of highlighted word, quick lookup window tries to not hide the word
|
||||
word_box = nil,
|
||||
-- sboxes containing highlighted text, quick lookup window tries to not hide the word
|
||||
word_boxes = nil,
|
||||
|
||||
-- refresh_callback will be called before we trigger full refresh in onSwipe
|
||||
refresh_callback = nil,
|
||||
@@ -130,7 +130,7 @@ function DictQuickLookup:init()
|
||||
-- -- don't pass self.highlight to subsequent lookup, we want
|
||||
-- -- the first to be the only one to unhighlight selection
|
||||
-- -- when closed
|
||||
-- Event:new("LookupWord", word, self.word_box))
|
||||
-- Event:new("LookupWord", word, true, {self.word_box}))
|
||||
-- end
|
||||
-- },
|
||||
-- Allow selection of one or more words (see textboxwidget.lua) :
|
||||
@@ -619,16 +619,32 @@ function DictQuickLookup:init()
|
||||
local nb_lines = Math.round(self.definition_height / self.definition_line_height)
|
||||
self.definition_height = nb_lines * self.definition_line_height
|
||||
self.height = self.definition_height + others_height
|
||||
if self.word_box then
|
||||
if self.word_boxes and #self.word_boxes > 0 then
|
||||
-- Try to not hide the highlighted word. We don't want to always
|
||||
-- get near it if we can stay center, so that more context around
|
||||
-- the word is still visible with the dict result.
|
||||
-- But if we were to be drawn over the word, move a bit if possible.
|
||||
local box = self.word_box
|
||||
-- Don't stick to the box, ensure a minimal padding between box and window
|
||||
local box_dict_padding = Size.padding.small
|
||||
local word_box_top = box.y - box_dict_padding
|
||||
local word_box_bottom = box.y + box.h + box_dict_padding
|
||||
|
||||
-- In most cases boxes will be a single sbox, but handle multiple
|
||||
-- sboxes by taking the top and bottom y values.
|
||||
local word_box_top
|
||||
local word_box_bottom
|
||||
for _, box in ipairs(self.word_boxes) do
|
||||
local box_top = box.y
|
||||
local box_bottom = box.y + box.h
|
||||
if not word_box_top or word_box_top > box_top then
|
||||
word_box_top = box_top
|
||||
end
|
||||
if not word_box_bottom or word_box_bottom < box_bottom then
|
||||
word_box_bottom = box_bottom
|
||||
end
|
||||
end
|
||||
|
||||
-- Don't stick to the box, ensure a minimal padding between box and
|
||||
-- window.
|
||||
word_box_top = word_box_top - Size.padding.small
|
||||
word_box_bottom = word_box_bottom + Size.padding.small
|
||||
|
||||
local half_visible_height = (avail_height - self.height) / 2
|
||||
if word_box_bottom > half_visible_height and word_box_top <= half_visible_height + self.height then
|
||||
-- word would be covered by our centered window
|
||||
|
||||
Reference in New Issue
Block a user