mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
TextViewer: add support for long-press on text
As done in DictQuickLookup (more event handlers are needed to cohabitate well with MovableContainer). By default, selected word or text is copied to clipboard. Also provide indexes to any long-press callback, as we'll need them for View HTML.
This commit is contained in:
@@ -2012,7 +2012,10 @@ function TextBoxWidget:onHoldReleaseText(callback, ges)
|
||||
|
||||
logger.dbg("onHoldReleaseText (duration:", time.format_time(hold_duration), ") :",
|
||||
sel_start_idx, ">", sel_end_idx, "=", selected_text)
|
||||
callback(selected_text, hold_duration)
|
||||
-- We give index in the charlist (unicode chars), and provide a function
|
||||
-- to convert these indices as in the utf8 text, to be used by caller
|
||||
-- only if needed, as it may be expensive.
|
||||
callback(selected_text, hold_duration, sel_start_idx, sel_end_idx, function(idx) return self:getSourceIndex(idx) end)
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -2029,7 +2032,7 @@ function TextBoxWidget:onHoldReleaseText(callback, ges)
|
||||
|
||||
local selected_text = table.concat(self.charlist, "", sel_start_idx, sel_end_idx)
|
||||
logger.dbg("onHoldReleaseText (duration:", time.format_time(hold_duration), ") :", sel_start_idx, ">", sel_end_idx, "=", selected_text)
|
||||
callback(selected_text, hold_duration)
|
||||
callback(selected_text, hold_duration, sel_start_idx, sel_end_idx, function(idx) return self:getSourceIndex(idx) end)
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -2085,4 +2088,14 @@ function TextBoxWidget:_findWordEdge(x, y, side)
|
||||
return edge_idx
|
||||
end
|
||||
|
||||
function TextBoxWidget:getSourceIndex(char_idx)
|
||||
if self._xtext then
|
||||
local utf8 = self._xtext:getText(1, char_idx)
|
||||
return #utf8
|
||||
else
|
||||
local utf8 = table.concat(self.charlist, "", 1, char_idx)
|
||||
return #utf8
|
||||
end
|
||||
end
|
||||
|
||||
return TextBoxWidget
|
||||
|
||||
@@ -86,37 +86,57 @@ function TextViewer:init()
|
||||
end
|
||||
|
||||
if Device:isTouchDevice() then
|
||||
local range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
self.ges_events = {
|
||||
TapClose = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
range = range,
|
||||
},
|
||||
},
|
||||
Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
range = range,
|
||||
},
|
||||
},
|
||||
MultiSwipe = {
|
||||
GestureRange:new{
|
||||
ges = "multiswipe",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
range = range,
|
||||
},
|
||||
},
|
||||
-- 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, start_idx, end_idx, to_source_index_func)
|
||||
self:handleTextSelection(text, hold_duration, start_idx, end_idx, to_source_index_func)
|
||||
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, }, },
|
||||
}
|
||||
end
|
||||
|
||||
@@ -271,7 +291,17 @@ function TextViewer:init()
|
||||
}
|
||||
}
|
||||
self.movable = MovableContainer:new{
|
||||
ignore_events = {"swipe"},
|
||||
-- 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 text widget, and may
|
||||
-- or may not be processed by it
|
||||
"swipe", "hold", "hold_release", "hold_pan",
|
||||
-- These do not have direct effect over the text widget,
|
||||
-- but may happen while selecting text: we need to check
|
||||
-- a few things before forwarding them
|
||||
"touch", "pan", "pan_release",
|
||||
},
|
||||
self.frame,
|
||||
}
|
||||
self[1] = WidgetContainer:new{
|
||||
@@ -338,6 +368,58 @@ function TextViewer:onSwipe(arg, ges)
|
||||
return self.movable:onMovableSwipe(arg, ges)
|
||||
end
|
||||
|
||||
-- The following handlers are similar to the ones in DictQuickLookup:
|
||||
-- we just forward to our MoveableContainer the events that our
|
||||
-- TextBoxWidget has not handled with text selection.
|
||||
function TextViewer:onHoldStartText(_, ges)
|
||||
-- Forward Hold events not processed by TextBoxWidget event handler
|
||||
-- to our MovableContainer
|
||||
return self.movable:onMovableHold(_, ges)
|
||||
end
|
||||
|
||||
function TextViewer: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 TextViewer: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 TextViewer: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.textw.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 TextViewer: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 TextViewer:onForwardingPanRelease(arg, ges)
|
||||
-- We can forward onMovablePanRelease() does enough checks
|
||||
return self.movable:onMovablePanRelease(arg, ges)
|
||||
end
|
||||
|
||||
|
||||
function TextViewer:findDialog()
|
||||
local input_dialog
|
||||
input_dialog = InputDialog:new{
|
||||
@@ -422,4 +504,18 @@ function TextViewer:findCallback(input_dialog)
|
||||
end
|
||||
end
|
||||
|
||||
function TextViewer:handleTextSelection(text, hold_duration, start_idx, end_idx, to_source_index_func)
|
||||
if self.text_selection_callback then
|
||||
self.text_selection_callback(text, hold_duration, start_idx, end_idx, to_source_index_func)
|
||||
return
|
||||
end
|
||||
if Device:hasClipboard() then
|
||||
Device.input.setClipboardText(text)
|
||||
UIManager:show(Notification:new{
|
||||
text = start_idx == end_idx and _("Word copied to clipboard.")
|
||||
or _("Selection copied to clipboard."),
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return TextViewer
|
||||
|
||||
Reference in New Issue
Block a user