From e7f705bf1095145d522234a357269e60e868e79a Mon Sep 17 00:00:00 2001 From: poire-z Date: Mon, 5 Mar 2018 21:27:55 +0100 Subject: [PATCH] Fix some issues with movable dict window (#3722) Some Hold and move (hold on title and move away from it) would not work. Pan (=swipe with hold at end) while selecting text would move the window (it now does nothing: proper text selection still needs Hold on word at start). Also increase hold duration from 2s to 3s (for switching lookup between dict/wikipedia) to be consistent with the 3s duration in readerhighlight. --- .../ui/widget/container/movablecontainer.lua | 2 +- frontend/ui/widget/dictquicklookup.lua | 96 +++++++++++++++---- frontend/ui/widget/htmlboxwidget.lua | 13 ++- frontend/ui/widget/textboxwidget.lua | 18 +++- 4 files changed, 107 insertions(+), 22 deletions(-) diff --git a/frontend/ui/widget/container/movablecontainer.lua b/frontend/ui/widget/container/movablecontainer.lua index 439fba779..d0c73966b 100644 --- a/frontend/ui/widget/container/movablecontainer.lua +++ b/frontend/ui/widget/container/movablecontainer.lua @@ -40,7 +40,7 @@ local MovableContainer = InputContainer:new{ _moved_offset_y = 0, -- Internal state between events _touch_pre_pan_was_inside = false, - _moving = true, + _moving = false, _move_relative_x = nil, _move_relative_y = nil, -- Original painting position from outer widget diff --git a/frontend/ui/widget/dictquicklookup.lua b/frontend/ui/widget/dictquicklookup.lua index 81c1660a3..11ff09177 100644 --- a/frontend/ui/widget/dictquicklookup.lua +++ b/frontend/ui/widget/dictquicklookup.lua @@ -63,6 +63,7 @@ local DictQuickLookup = InputContainer:new{ -- refresh_callback will be called before we trigger full refresh in onSwipe refresh_callback = nil, html_dictionary_link_tapped_callback = nil, + text_selection_in_progress = false, } local highlight_strings = { @@ -78,25 +79,22 @@ function DictQuickLookup:init() } end if Device:isTouchDevice() then + local range = Geom:new{ + x = 0, y = 0, + w = Screen:getWidth(), + h = Screen:getHeight(), + } self.ges_events = { TapCloseDict = { 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, }, }, -- This was for selection of a single word with simple hold @@ -120,22 +118,25 @@ function DictQuickLookup:init() HoldStartText = { GestureRange:new{ ges = "hold", - range = function() - return self.region - end, + range = range, }, + -- callback function when HoldStartText is handled as args + args = function(selecting) + -- store the fact we are selecting text in definition, + -- so we don't forward any event to MovableContainer + self.text_selection_in_progress = selecting + end }, HoldReleaseText = { GestureRange:new{ ges = "hold_release", - range = function() - return self.region - end, + range = range, }, -- callback function when HoldReleaseText is handled as args args = function(text, hold_duration) + self.text_selection_in_progress = false local lookup_target - if hold_duration < 2.0 then + 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 @@ -153,6 +154,12 @@ function DictQuickLookup:init() ) end }, + -- These will be forwarded to MovableContainer if we are not currently + -- selecting text in the definition widget + ForwardingTouch = { GestureRange:new{ ges = "touch", range = range, }, }, + ForwardingHoldPan = { GestureRange:new{ ges = "hold_pan", range = range, }, }, + ForwardingPan = { GestureRange:new{ ges = "pan", range = range, }, }, + ForwardingPanRelease = { GestureRange:new{ ges = "pan_release", range = range, }, }, } end end @@ -523,7 +530,16 @@ function DictQuickLookup:update() 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 = {"swipe", "hold", "hold_release"}, + ignore_events = { + -- These have effects over the definition widget, and may + -- or may not be processed by it + "swipe", "hold", "hold_release", + -- These do not have direct effect over the definition widget, + -- but may happen while selecting text: we need to check + -- we're not doing text selection and a few other things + -- before forwarding them + "touch", "pan", "pan_release", "hold_pan", + }, self.dict_frame, } self.movable:setMovedOffset(orig_moved_offset) @@ -769,17 +785,61 @@ function DictQuickLookup:onSwipe(arg, ges) end function DictQuickLookup:onHoldStartText(_, ges) + -- Event was not processed by definition widget: we are not selecting + self.text_selection_in_progress = false -- Forward Hold events not processed by TextBoxWidget event handler -- to our MovableContainer return self.movable:onMovableHold(_, ges) end function DictQuickLookup:onHoldReleaseText(_, ges) + -- Event was not processed by definition widget: we are not selecting + self.text_selection_in_progress = false -- Forward Hold events not processed by TextBoxWidget event handler -- to our MovableContainer return self.movable:onMovableHoldRelease(_, ges) end +-- These 4 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:onForwardingHoldPan(arg, ges) + if not self.text_selection_in_progress then -- don't forward it as we are selecting + -- 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 +end + +function DictQuickLookup:onForwardingPan(arg, ges) + if not self.text_selection_in_progress then -- don't forward it as we are selecting + -- 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 +end + +function DictQuickLookup:onForwardingPanRelease(arg, ges) + if not self.text_selection_in_progress then -- don't forward it as we are selecting + -- We can forward onMovablePanRelease() does enough checks + return self.movable:onMovablePanRelease(arg, ges) + end +end + function DictQuickLookup:lookupInputWord(hint) self:onClose() self.input_dialog = InputDialog:new{ diff --git a/frontend/ui/widget/htmlboxwidget.lua b/frontend/ui/widget/htmlboxwidget.lua index 6bc2be5b3..3ce7c107f 100644 --- a/frontend/ui/widget/htmlboxwidget.lua +++ b/frontend/ui/widget/htmlboxwidget.lua @@ -148,10 +148,21 @@ function HtmlBoxWidget:getPosFromAbsPos(abs_pos) return pos end -function HtmlBoxWidget:onHoldStartText(_, ges) +function HtmlBoxWidget:onHoldStartText(callback, ges) self.hold_start_pos = self:getPosFromAbsPos(ges.pos) + + if not self.hold_start_pos then + if callback then + callback(false) -- let know we are not selecting + end + return false -- let event be processed by other widgets + end + self.hold_start_tv = TimeVal.now() + if callback then + callback(true) -- let know we are selecting + end return true end diff --git a/frontend/ui/widget/textboxwidget.lua b/frontend/ui/widget/textboxwidget.lua index 756901d48..e03113eb1 100644 --- a/frontend/ui/widget/textboxwidget.lua +++ b/frontend/ui/widget/textboxwidget.lua @@ -762,11 +762,25 @@ end local FIND_START = 1 local FIND_END = 2 -function TextBoxWidget:onHoldStartText(_, ges) - -- just store hold start position and timestamp, will be used on release +function TextBoxWidget:onHoldStartText(callback, ges) + -- store hold start position and timestamp, will be used on release self.hold_start_x = ges.pos.x - self.dimen.x self.hold_start_y = ges.pos.y - self.dimen.y + + -- check coordinates are actually inside our area + if self.hold_start_x < 0 or self.hold_start_x > self.dimen.w or + self.hold_start_y < 0 or self.hold_start_y > self.dimen.h then + self.hold_start_tv = nil -- don't process coming HoldRelease event + if callback then + callback(false) -- let know we are not selecting + end + return false -- let event be processed by other widgets + end + self.hold_start_tv = TimeVal.now() + if callback then + callback(true) -- let know we are selecting + end return true end