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.
reviewable/pr10188/r1
poire-z 1 year ago
parent f063155166
commit 945a1cc76f

@ -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

Loading…
Cancel
Save