2
0
mirror of https://github.com/koreader/koreader synced 2024-11-16 06:12:56 +00:00
koreader/frontend/ui/widget/dictquicklookup.lua

922 lines
35 KiB
Lua
Raw Normal View History

2017-04-29 08:38:09 +00:00
local Blitbuffer = require("ffi/blitbuffer")
local Button = require("ui/widget/button")
local ButtonTable = require("ui/widget/buttontable")
2013-10-18 20:38:07 +00:00
local CenterContainer = require("ui/widget/container/centercontainer")
local CloseButton = require("ui/widget/closebutton")
local Device = require("device")
local Geom = require("ui/geometry")
local Event = require("ui/event")
local Font = require("ui/font")
2017-04-29 08:38:09 +00:00
local FrameContainer = require("ui/widget/container/framecontainer")
local GestureRange = require("ui/gesturerange")
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local LeftContainer = require("ui/widget/container/leftcontainer")
local LineWidget = require("ui/widget/linewidget")
local MovableContainer = require("ui/widget/container/movablecontainer")
2017-04-29 08:38:09 +00:00
local OverlapGroup = require("ui/widget/overlapgroup")
local ScrollHtmlWidget = require("ui/widget/scrollhtmlwidget")
2017-04-29 08:38:09 +00:00
local ScrollTextWidget = require("ui/widget/scrolltextwidget")
2017-09-13 14:56:20 +00:00
local Size = require("ui/size")
2017-04-29 08:38:09 +00:00
local TextWidget = require("ui/widget/textwidget")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger")
2017-04-29 08:38:09 +00:00
local util = require("util")
local _ = require("gettext")
2017-04-29 08:38:09 +00:00
local Screen = Device.screen
local T = require("ffi/util").template
2013-04-24 14:57:03 +00:00
--[[
Display quick lookup word definition
]]
2013-10-18 20:38:07 +00:00
local DictQuickLookup = InputContainer:new{
2014-03-13 13:52:43 +00:00
results = nil,
lookupword = nil,
dictionary = nil,
definition = nil,
displayword = nil,
images = nil,
is_wiki = false,
is_fullpage = false,
is_html = false,
2014-03-13 13:52:43 +00:00
dict_index = 1,
2017-04-29 08:38:09 +00:00
title_face = Font:getFace("x_smalltfont"),
2014-03-13 13:52:43 +00:00
content_face = Font:getFace("cfont", DDICT_FONT_SIZE),
image_alt_face = Font:getFace("cfont", DDICT_FONT_SIZE-4),
2014-03-13 13:52:43 +00:00
width = nil,
height = nil,
-- box of highlighted word, quick lookup window tries to not hide the word
word_box = nil,
2014-05-01 10:37:12 +00:00
2017-09-13 14:56:20 +00:00
title_padding = Size.padding.default,
title_margin = Size.margin.title,
word_padding = Size.padding.default,
word_margin = Size.margin.default,
-- alt padding/margin for wiki to compensate for reduced font size
wiki_word_padding = Screen:scaleBySize(7),
wiki_word_margin = Screen:scaleBySize(3),
definition_padding = Screen:scaleBySize(2),
definition_margin = Screen:scaleBySize(2),
button_padding = Screen:scaleBySize(14),
-- refresh_callback will be called before we trigger full refresh in onSwipe
refresh_callback = nil,
2018-01-15 22:51:43 +00:00
html_dictionary_link_tapped_callback = nil,
2013-04-24 14:57:03 +00:00
}
local highlight_strings = {
highlight =_("Highlight"),
unhighlight = _("Unhighlight"),
}
2013-04-24 14:57:03 +00:00
function DictQuickLookup:init()
2014-03-13 13:52:43 +00:00
self:changeToDefaultDict()
if Device:hasKeys() then
self.key_events = {
Close = { {"Back"}, doc = "close quick lookup" }
}
end
2014-03-13 13:52:43 +00:00
if Device:isTouchDevice() then
local range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
2014-03-13 13:52:43 +00:00
self.ges_events = {
TapCloseDict = {
GestureRange:new{
ges = "tap",
range = range,
2014-03-13 13:52:43 +00:00
},
},
Swipe = {
GestureRange:new{
ges = "swipe",
range = range,
2014-03-13 13:52:43 +00:00
},
},
-- This was for selection of a single word with simple hold
-- HoldWord = {
-- GestureRange:new{
-- ges = "hold",
-- range = function()
-- return self.region
-- end,
-- },
-- -- callback function when HoldWord is handled as args
-- args = function(word)
-- self.ui:handleEvent(
-- -- 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))
-- end
-- },
-- Allow selection of one or more words (see textboxwidget.lua) :
HoldStartText = {
GestureRange:new{
ges = "hold",
range = range,
},
},
HoldPanText = {
GestureRange:new{
ges = "hold",
range = range,
},
},
HoldReleaseText = {
GestureRange:new{
ges = "hold_release",
range = range,
},
-- callback function when HoldReleaseText is handled as args
args = function(text, hold_duration)
local lookup_target
if hold_duration < 3.0 then
-- do this lookup in the same domain (dict/wikipedia)
lookup_target = self.is_wiki and "LookupWikipedia" or "LookupWord"
else
-- but allow switching domain with a long hold
lookup_target = self.is_wiki and "LookupWord" or "LookupWikipedia"
end
if lookup_target == "LookupWikipedia" then
self:resyncWikiLanguages()
end
self.ui:handleEvent(
-- don't pass self.highlight to subsequent lookup, we want
-- the first to be the only one to unhighlight selection
-- when closed
Event:new(lookup_target, text)
)
end
},
-- These will be forwarded to MovableContainer after some checks
ForwardingTouch = { GestureRange:new{ ges = "touch", range = range, }, },
ForwardingPan = { GestureRange:new{ ges = "pan", range = range, }, },
ForwardingPanRelease = { GestureRange:new{ ges = "pan_release", range = range, }, },
2014-03-13 13:52:43 +00:00
}
end
2013-07-21 06:23:54 +00:00
end
2017-01-02 18:12:34 +00:00
-- Whether currently DictQuickLookup is working without a document.
function DictQuickLookup:isDocless()
return self.ui == nil or self.ui.highlight == nil
end
function DictQuickLookup:getHtmlDictionaryCss()
-- Using Noto Sans because Nimbus doesn't contain the IPA symbols.
-- 'line-height: 1.3' to have it similar to textboxwidget,
-- and follow user's choice on justification
local css_justify = G_reader_settings:nilOrTrue("dict_justify") and "text-align: justify;" or ""
local css = [[
@page {
margin: 0;
font-family: 'Noto Sans';
}
body {
margin: 0;
line-height: 1.3;
]]..css_justify..[[
}
]]
if self.css then
return css .. self.css
end
return css
end
2013-07-21 06:23:54 +00:00
function DictQuickLookup:update()
local orig_dimen = self.dict_frame and self.dict_frame.dimen or Geom:new{}
local orig_moved_offset = self.movable and self.movable:getMovedOffset()
-- Free our previous widget and subwidgets' resources (especially
-- definitions' TextBoxWidget bb, HtmlBoxWidget bb and MuPDF instance,
-- and scheduled image_update_action)
if self[1] then
self[1]:free()
end
-- calculate window dimension
self.align = "center"
self.region = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
if self.is_fullpage or G_reader_settings:isTrue("dict_largewindow") then
-- bigger window if fullpage being shown - this will let
-- some room anyway for footer display (time, battery...)
self.height = Screen:getHeight()
self.width = Screen:getWidth() - Screen:scaleBySize(40)
else
-- smaller window otherwise
-- try to not hide highlighted word
if self.word_box then
local box = self.word_box
if box.y + box.h/2 < Screen:getHeight()*0.3 then
self.region.y = box.y + box.h
self.region.h = Screen:getHeight() - box.y - box.h
self.align = "top"
elseif box.y + box.h/2 > Screen:getHeight()*0.7 then
self.region.y = 0
self.region.h = box.y
self.align = "bottom"
end
end
self.height = math.min(self.region.h*0.7, Screen:getHeight()*0.5)
end
2014-03-13 13:52:43 +00:00
-- dictionary title
local close_button = CloseButton:new{ window = self, padding_top = self.title_margin, }
local dict_title_text = TextWidget:new{
text = self.dictionary,
face = self.title_face,
bold = true,
width = self.width,
}
-- Some different UI tweaks for dict or wiki
local lookup_word_font_size, lookup_word_padding, lookup_word_margin
if self.is_wiki then
-- visual hint : dictionary title left adjusted, Wikipedia title centered
dict_title_text = CenterContainer:new{
dimen = Geom:new{
w = self.width,
h = dict_title_text:getSize().h,
},
dict_title_text
}
-- Wikipedia has longer titles, so use a smaller font
lookup_word_font_size = 18
lookup_word_padding = self.wiki_word_padding
lookup_word_margin = self.wiki_word_margin
-- Keep a copy of self.wiki_languages for use
-- by DictQuickLookup:resyncWikiLanguages()
self.wiki_languages_copy = self.wiki_languages and {unpack(self.wiki_languages)} or nil
else
-- Usual font size for dictionary
lookup_word_font_size = 22
lookup_word_padding = self.word_padding
lookup_word_margin = self.word_margin
end
2014-03-13 13:52:43 +00:00
self.dict_title = FrameContainer:new{
padding = self.title_padding,
margin = self.title_margin,
bordersize = 0,
dict_title_text
2014-03-13 13:52:43 +00:00
}
-- lookup word
local lookup_word = Button:new{
padding = lookup_word_padding,
margin = lookup_word_margin,
2014-03-13 13:52:43 +00:00
bordersize = 0,
max_width = self.width,
text = self.displayword,
text_font_face = "tfont",
text_font_size = lookup_word_font_size,
hold_callback = function() self:lookupInputWord(self.lookupword) end,
2014-03-13 13:52:43 +00:00
}
local text_widget
if self.is_html then
text_widget = ScrollHtmlWidget:new{
html_body = self.definition,
css = self:getHtmlDictionaryCss(),
default_font_size = Screen:scaleBySize(DDICT_FONT_SIZE),
width = self.width,
height = self.is_fullpage and self.height*0.75 or self.height*0.7,
dialog = self,
2018-01-15 22:51:43 +00:00
html_link_tapped_callback = function(link)
self.html_dictionary_link_tapped_callback(self.dictionary, link)
end,
}
else
text_widget = ScrollTextWidget:new{
2014-03-13 13:52:43 +00:00
text = self.definition,
face = self.content_face,
width = self.width,
-- get a bit more height for definition as wiki has one less button raw
height = self.is_fullpage and self.height*0.75 or self.height*0.7,
2014-03-13 13:52:43 +00:00
dialog = self,
-- allow for disabling justification
justified = G_reader_settings:nilOrTrue("dict_justify"),
image_alt_face = self.image_alt_face,
images = self.images,
}
end
-- word definition
self.definition_widget = FrameContainer:new{
padding = self.definition_padding,
margin = self.definition_margin,
bordersize = 0,
text_widget,
2014-05-01 10:37:12 +00:00
}
-- Different sets of buttons if fullpage or not
local buttons
if self.is_fullpage then
-- A save and a close button
buttons = {
{
{
text = _("Save as EPUB"),
callback = function()
local InfoMessage = require("ui/widget/infomessage")
local ConfirmBox = require("ui/widget/confirmbox")
-- if forced_lang was specified, it may not be in our wiki_languages,
-- but ReaderWikipedia will have put it in result.lang
local lang = self.lang or self.wiki_languages_copy[1]
-- Just to be safe (none of the invalid chars, except ':' for uninteresting
-- Portal: or File: wikipedia pages, should be in lookup_word)
local cleaned_lookupword = util.replaceInvalidChars(self.lookupword:gsub("_", " "))
local filename = cleaned_lookupword .. "."..string.upper(lang)..".epub"
-- Find a directory to save file into
local dir
if G_reader_settings:isTrue("wikipedia_save_in_book_dir") and not self:isDocless() then
local last_file = G_reader_settings:readSetting("lastfile")
if last_file then
dir = last_file:match("(.*)/")
end
end
if not dir then dir = G_reader_settings:readSetting("wikipedia_save_dir") end
if not dir then dir = G_reader_settings:readSetting("home_dir") end
if not dir then dir = require("apps/filemanager/filemanagerutil").getDefaultDir() end
if not dir or not util.pathExists(dir) then
UIManager:show(InfoMessage:new{
text = _("No directory to save article to could be found."),
})
return
end
local epub_path = dir .. "/" .. filename
UIManager:show(ConfirmBox:new{
text = T(_("Save as %1?"), filename),
ok_callback = function()
UIManager:scheduleIn(0.1, function()
local Wikipedia = require("ui/wikipedia")
Wikipedia:createEpubWithUI(epub_path, self.lookupword, lang, function(success)
if success then
UIManager:show(ConfirmBox:new{
text = T(_("Article saved to:\n%1\n\nWould you like to read the downloaded article now?"), epub_path),
ok_callback = function()
-- close all dict/wiki windows, without scheduleIn(highlight.clear())
self:onHoldClose(true)
-- close current ReaderUI in 1 sec, and create a new one
UIManager:scheduleIn(1.0, function()
local ReaderUI = require("apps/reader/readerui")
local reader = ReaderUI:_getRunningInstance()
if reader then
-- close Highlight menu if any still shown
if reader.highlight then
reader.highlight:onClose()
end
reader:onClose()
end
ReaderUI:showReader(epub_path)
end)
end,
})
else
UIManager:show(InfoMessage:new{
text = _("Saving Wikipedia article failed or canceled."),
})
end
end)
end)
end
})
end,
},
{
text = _("Close"),
callback = function()
UIManager:close(self)
end,
},
},
}
else
2014-03-13 13:52:43 +00:00
buttons = {
2014-05-01 10:37:12 +00:00
{
2014-03-13 13:52:43 +00:00
{
2017-09-13 14:56:20 +00:00
text = "◁◁",
2014-03-13 13:52:43 +00:00
enabled = self:isPrevDictAvaiable(),
callback = function()
self:changeToPrevDict()
end,
},
{
text = self:getHighlightText(),
enabled = self.highlight ~= nil,
callback = function()
if self:getHighlightText() == highlight_strings.highlight then
self.ui:handleEvent(Event:new("Highlight"))
else
self.ui:handleEvent(Event:new("Unhighlight"))
end
self:update()
end,
},
2014-03-13 13:52:43 +00:00
{
2017-09-13 14:56:20 +00:00
text = "▷▷",
2014-03-13 13:52:43 +00:00
enabled = self:isNextDictAvaiable(),
callback = function()
self:changeToNextDict()
end,
},
},
{
{
-- if dictionary result, do the same search on wikipedia
-- if already wiki, get the full page for the current result
text = self.is_wiki and _("Wikipedia full") or _("Wikipedia"),
2014-03-13 13:52:43 +00:00
callback = function()
UIManager:scheduleIn(0.1, function()
self:lookupWikipedia(self.is_wiki) -- will get_fullpage if is_wiki
end)
2014-03-13 13:52:43 +00:00
end,
},
-- Rotate thru available wikipedia languages (disabled if dictionary window)
-- (replace previous unimplemented "Add Note")
2014-03-13 13:52:43 +00:00
{
-- if more than one language, enable it and display "current lang > next lang"
-- otherwise, just display current lang
text = self.is_wiki and ( #self.wiki_languages > 1 and self.wiki_languages[1].." > "..self.wiki_languages[2] or self.wiki_languages[1] ) or _("Follow Link"),
enabled = (self.is_wiki and #self.wiki_languages > 1) or self.selected_link ~= nil,
2014-03-13 13:52:43 +00:00
callback = function()
if self.is_wiki then
self:resyncWikiLanguages(true) -- rotate & resync them
UIManager:close(self)
self:lookupWikipedia()
else
self:onClose()
self.ui.link:onGotoLink(self.selected_link)
end
end,
},
{
2017-01-02 18:12:34 +00:00
text = (self.is_wiki or self:isDocless()) and _("Close") or _("Search"),
callback = function()
if not self.is_wiki then
self.ui:handleEvent(Event:new("HighlightSearch"))
end
2014-11-05 04:28:11 +00:00
UIManager:close(self)
2014-03-13 13:52:43 +00:00
end,
},
},
}
end
local button_table = ButtonTable:new{
width = math.max(self.width, self.definition_widget:getSize().w),
button_font_face = "cfont",
button_font_size = 20,
buttons = buttons,
2014-03-13 13:52:43 +00:00
zero_sep = true,
2014-05-01 10:37:12 +00:00
show_parent = self,
2014-03-13 13:52:43 +00:00
}
local title_bar = LineWidget:new{
dimen = Geom:new{
w = button_table:getSize().w + self.button_padding,
2017-09-13 14:56:20 +00:00
h = Size.line.thick,
2014-03-13 13:52:43 +00:00
}
}
2014-05-01 10:37:12 +00:00
2014-03-13 13:52:43 +00:00
self.dict_bar = OverlapGroup:new{
dimen = {
w = button_table:getSize().w + self.button_padding,
h = self.dict_title:getSize().h
},
2014-03-13 13:52:43 +00:00
self.dict_title,
close_button,
2014-03-13 13:52:43 +00:00
}
-- Fix dict title max width now that we know the final width
dict_title_text.width = self.dict_bar.dimen.w - close_button:getSize().w
2014-05-01 10:37:12 +00:00
2014-03-13 13:52:43 +00:00
self.dict_frame = FrameContainer:new{
2017-09-13 14:56:20 +00:00
radius = Size.radius.window,
bordersize = Size.border.window,
2014-03-13 13:52:43 +00:00
padding = 0,
margin = 0,
background = Blitbuffer.COLOR_WHITE,
2014-03-13 13:52:43 +00:00
VerticalGroup:new{
align = "left",
self.dict_bar,
title_bar,
-- word
LeftContainer:new{
2014-03-13 13:52:43 +00:00
dimen = Geom:new{
w = title_bar:getSize().w,
h = lookup_word:getSize().h,
},
lookup_word,
},
-- definition
CenterContainer:new{
dimen = Geom:new{
w = title_bar:getSize().w,
h = self.definition_widget:getSize().h,
2014-03-13 13:52:43 +00:00
},
self.definition_widget,
2014-03-13 13:52:43 +00:00
},
-- buttons
CenterContainer:new{
dimen = Geom:new{
w = title_bar:getSize().w,
h = button_table:getSize().h,
},
button_table,
}
}
}
self.movable = MovableContainer:new{
-- We'll handle these events ourselves, and call appropriate
-- MovableContainer's methods when we didn't process the event
ignore_events = {
-- These have effects over the definition widget, and may
-- or may not be processed by it
"swipe", "hold", "hold_release", "hold_pan",
-- These do not have direct effect over the definition widget,
-- but may happen while selecting text: we need to check
-- a few things before forwarding them
"touch", "pan", "pan_release",
},
self.dict_frame,
}
self.movable:setMovedOffset(orig_moved_offset)
2014-03-13 13:52:43 +00:00
self[1] = WidgetContainer:new{
align = self.align,
dimen = self.region,
self.movable,
2014-03-13 13:52:43 +00:00
}
Enable HW dithering in a few key places (#4541) * Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4) * FileManager and co. (where appropriate, i.e., when covers are shown) * Book Status * Reader, where appropriate: * CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone). * Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices). * ScreenSaver * ImageViewer * Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it). (The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu). * Hunted down a few redundant repaints (unneeded setDirty("all") calls), either by switching the widget to nil when only a refresh was needed, and not a repaint, or by passing the appropritate widget to setDirty. (Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard). There were also a few instances of 'em right behind a widget close. * Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog. We unfortunately do need to do it when switching tabs, because of their variable heights. * On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes! * Fix another debug guard in Kobo sysfs_light * Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not. PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
UIManager:setDirty(self, function()
local update_region = self.dict_frame and self.dict_frame.dimen and self.dict_frame.dimen:combine(orig_dimen) or orig_dimen
logger.dbg("update dict region", update_region)
return "partial", update_region
end)
2013-07-21 06:23:54 +00:00
end
function DictQuickLookup:onCloseWidget()
-- Free our widget and subwidgets' resources (especially
-- definitions' TextBoxWidget bb, HtmlBoxWidget bb and MuPDF instance,
-- and scheduled image_update_action)
if self[1] then
self[1]:free()
end
if self.images_cleanup_needed then
logger.dbg("freeing lookup results images blitbuffers")
for _, r in ipairs(self.results) do
if r.images and #r.images > 0 then
for _, im in ipairs(r.images) do
if im.bb then im.bb:free() end
if im.hi_bb then im.hi_bb:free() end
end
end
end
end
-- NOTE: Drop region to make it a full-screen flash
UIManager:setDirty(nil, function()
return "flashui", nil
end)
return true
end
function DictQuickLookup:onShow()
UIManager:setDirty(self, function()
return "flashui", self.dict_frame.dimen
end)
return true
end
function DictQuickLookup:getHighlightedItem()
2017-01-02 18:12:34 +00:00
if self:isDocless() then return end
return self.ui.highlight:getHighlightBookmarkItem()
end
function DictQuickLookup:getHighlightText()
local item = self:getHighlightedItem()
if not item then
return highlight_strings.highlight, false
elseif self.ui.bookmark:isBookmarkAdded(item) then
return highlight_strings.unhighlight, false
else
return highlight_strings.highlight, true
end
end
2013-07-21 06:23:54 +00:00
function DictQuickLookup:isPrevDictAvaiable()
2014-03-13 13:52:43 +00:00
return self.dict_index > 1
2013-07-21 06:23:54 +00:00
end
function DictQuickLookup:isNextDictAvaiable()
2014-03-13 13:52:43 +00:00
return self.dict_index < #self.results
2013-07-21 06:23:54 +00:00
end
function DictQuickLookup:changeToPrevDict()
if self:isPrevDictAvaiable() then
self:changeDictionary(self.dict_index - 1)
elseif #self.results > 1 then -- restart at end if first reached
self:changeDictionary(#self.results)
end
2013-07-21 06:23:54 +00:00
end
function DictQuickLookup:changeToNextDict()
if self:isNextDictAvaiable() then
self:changeDictionary(self.dict_index + 1)
elseif #self.results > 1 then -- restart at first if end reached
self:changeDictionary(1)
end
2013-07-21 06:23:54 +00:00
end
function DictQuickLookup:changeDictionary(index)
if not self.results[index] then return end
2014-03-13 13:52:43 +00:00
self.dict_index = index
self.dictionary = self.results[index].dict
self.lookupword = self.results[index].word
self.definition = self.results[index].definition
self.is_fullpage = self.results[index].is_fullpage
self.is_html = self.results[index].is_html
self.css = self.results[index].css
self.lang = self.results[index].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
-- load and display them. We'll need to free these blitbuffers
-- when we're done.
self.images_cleanup_needed = true
end
if self.is_fullpage then
self.displayword = self.lookupword
else
-- add "dict_index / nbresults" to displayword, so we know where
-- we're at and what's yet to see
self.displayword = self.lookupword.." "..index.." / "..#self.results
-- add queried word to 1st result's definition, so we can see
-- what was the selected text and if we selected wrong
if index == 1 then
if self.is_html then
self.definition = self.definition.."<br/>_______<br/>"
else
self.definition = self.definition.."\n_______\n"
end
self.definition = self.definition..T(_("(query : %1)"), self.word)
end
end
2014-05-01 10:37:12 +00:00
2014-03-13 13:52:43 +00:00
self:update()
2013-07-21 06:23:54 +00:00
end
2014-05-01 10:37:12 +00:00
function DictQuickLookup:changeToDefaultDict()
2014-03-13 13:52:43 +00:00
if self.dictionary then
-- dictionaries that have definition of the first word(accurate word)
-- excluding Fuzzy queries.
local n_accurate_dicts = nil
local default_word = self.results[1].word
for i=1, #self.results do
if self.results[i].word == default_word then
n_accurate_dicts = i
else
break
end
end
-- change to dictionary specified by self.dictionary
for i=1, n_accurate_dicts do
if self.results[i].dict == self.dictionary then
self:changeDictionary(i)
break
end
-- cannot find definition in default dictionary
if i == n_accurate_dicts then
self:changeDictionary(1)
end
end
else
self:changeDictionary(1)
end
2013-04-24 14:57:03 +00:00
end
function DictQuickLookup:onAnyKeyPressed()
2014-03-13 13:52:43 +00:00
-- triggered by our defined key events
UIManager:close(self)
return true
2013-04-24 14:57:03 +00:00
end
2013-07-21 06:23:54 +00:00
function DictQuickLookup:onTapCloseDict(arg, ges_ev)
2014-03-13 13:52:43 +00:00
if ges_ev.pos:notIntersectWith(self.dict_frame.dimen) then
self:onClose()
return true
elseif not ges_ev.pos:notIntersectWith(self.dict_title.dimen) and not self.is_wiki then
2014-03-13 13:52:43 +00:00
self.ui:handleEvent(Event:new("UpdateDefaultDict", self.dictionary))
return true
end
-- Allow for changing dict with tap (tap event will be first
-- processed for scrolling definition by ScrollTextWidget, which
-- will pop it up for us here when it can't scroll anymore).
-- This allow for continuous reading of results' definitions with tap.
if ges_ev.pos.x < Screen:getWidth()/2 then
local prev_index = self.dict_index
self:changeToPrevDict()
if self.dict_index ~= prev_index then
-- Jump directly to bottom of previous dict definition
-- to keep "continuous reading with tap" consistent
self.definition_widget[1]:scrollToRatio(1) -- 1 = 100% = bottom
end
else
self:changeToNextDict()
end
2014-03-13 13:52:43 +00:00
return true
2013-04-24 14:57:03 +00:00
end
2013-10-18 20:38:07 +00:00
function DictQuickLookup:onClose()
2014-03-13 13:52:43 +00:00
UIManager:close(self)
for i = #self.window_list, 1, -1 do
local window = self.window_list[i]
if window == self then
table.remove(self.window_list, i)
end
end
if self.highlight then
-- delay unhighlight of selection, so we can see where we stopped when
-- back from our journey into dictionary or wikipedia
local clear_id = self.highlight:getClearId()
UIManager:scheduleIn(0.5, function()
self.highlight:clear(clear_id)
end)
end
return true
end
function DictQuickLookup:onHoldClose(no_clear)
self:onClose()
for i = #self.window_list, 1, -1 do
local window = self.window_list[i]
-- if one holds a highlight, let's clear it like in onClose()
if window.highlight and not no_clear then
local clear_id = window.highlight:getClearId()
UIManager:scheduleIn(0.5, function()
window.highlight:clear(clear_id)
end)
end
UIManager:close(window)
table.remove(self.window_list, i)
end
2014-03-13 13:52:43 +00:00
return true
end
function DictQuickLookup:onSwipe(arg, ges)
if ges.pos:intersectWith(self.definition_widget.dimen) then
-- if we want changeDict to still work with swipe outside window :
-- or not ges.pos:intersectWith(self.dict_frame.dimen) then
if ges.direction == "west" then
self:changeToNextDict()
elseif ges.direction == "east" then
self:changeToPrevDict()
else
if self.refresh_callback then self.refresh_callback() end
-- trigger a full-screen HQ flashing refresh
UIManager:setDirty(nil, "full")
-- a long diagonal swipe may also be used for taking a screenshot,
-- so let it propagate
return false
end
return true
end
-- Let our MovableContainer handle swipe outside of definition
return self.movable:onMovableSwipe(arg, ges)
end
function DictQuickLookup:onHoldStartText(_, ges)
-- Forward Hold events not processed by TextBoxWidget event handler
-- to our MovableContainer
return self.movable:onMovableHold(_, ges)
end
function DictQuickLookup:onHoldPanText(_, ges)
-- Forward Hold events not processed by TextBoxWidget event handler
-- to our MovableContainer
-- We only forward it if we did forward the Touch
if self.movable._touch_pre_pan_was_inside then
return self.movable:onMovableHoldPan(arg, ges)
end
end
function DictQuickLookup:onHoldReleaseText(_, ges)
-- Forward Hold events not processed by TextBoxWidget event handler
-- to our MovableContainer
return self.movable:onMovableHoldRelease(_, ges)
end
-- These 3 event processors are just used to forward these events
-- to our MovableContainer, under certain conditions, to avoid
-- unwanted moves of the window while we are selecting text in
-- the definition widget.
function DictQuickLookup:onForwardingTouch(arg, ges)
-- This Touch may be used as the Hold we don't get (for example,
-- when we start our Hold on the bottom buttons)
if not ges.pos:intersectWith(self.definition_widget.dimen) then
return self.movable:onMovableTouch(arg, ges)
else
-- Ensure this is unset, so we can use it to not forward HoldPan
self.movable._touch_pre_pan_was_inside = false
end
end
function DictQuickLookup:onForwardingPan(arg, ges)
-- We only forward it if we did forward the Touch or are currently moving
if self.movable._touch_pre_pan_was_inside or self.movable._moving then
return self.movable:onMovablePan(arg, ges)
end
end
function DictQuickLookup:onForwardingPanRelease(arg, ges)
-- We can forward onMovablePanRelease() does enough checks
return self.movable:onMovablePanRelease(arg, ges)
end
function DictQuickLookup:lookupInputWord(hint)
self:onClose()
self.input_dialog = InputDialog:new{
title = _("Input lookup word"),
input = hint,
input_hint = hint or "",
input_type = "text",
buttons = {
{
{
text = _("Cancel"),
callback = function()
self:closeInputDialog()
end,
},
{
text = _("Lookup"),
is_enter_default = true,
callback = function()
self:closeInputDialog()
self:inputLookup()
end,
},
}
},
}
UIManager:show(self.input_dialog)
self.input_dialog:onShowKeyboard()
end
function DictQuickLookup:inputLookup()
local word = self.input_dialog:getInputText()
if word and word ~= "" then
local event
if self.is_wiki then
event = "LookupWikipedia"
self:resyncWikiLanguages()
else
event = "LookupWord"
end
self.ui:handleEvent(Event:new(event, word))
end
end
function DictQuickLookup:closeInputDialog()
UIManager:close(self.input_dialog)
end
function DictQuickLookup:resyncWikiLanguages(rotate)
-- Resync the current language or rotate it from its state when
-- this window was created (we may have rotated it later in other
-- wikipedia windows that we closed and went back here, and its
-- state would not be what the wikipedia language button is showing.
if not self.wiki_languages_copy then
return
end
if rotate then
-- rotate our saved wiki_languages copy
local current_lang = table.remove(self.wiki_languages_copy, 1)
table.insert(self.wiki_languages_copy, current_lang)
end
-- re-set self.wiki_languages with original (possibly rotated) items
for i, lang in ipairs(self.wiki_languages_copy) do
self.wiki_languages[i] = lang
end
end
function DictQuickLookup:lookupWikipedia(get_fullpage)
local word
if get_fullpage then
-- we use the word of the displayed result's definition, which
-- is the exact title of the full wikipedia page
word = self.lookupword
else
-- we use the original word that was querried
word = self.word
end
self:resyncWikiLanguages()
-- strange : we need to pass false instead of nil if word_box is nil,
-- otherwise get_fullpage is not passed
self.ui:handleEvent(Event:new("LookupWikipedia", word, self.word_box and self.word_box or false, get_fullpage))
end
2013-10-18 20:38:07 +00:00
return DictQuickLookup