Non-touch: highlight support (#8877)

readerhighlight: non-touch support
focusmanager: fix same type container share same selected field
radiobuttonwidget: non touch support
sortwidget: non touch support
openwithdialog: fix layout contains textinput, checkboxes added to layout twice
This commit is contained in:
Philip Chan
2022-03-12 19:16:50 +08:00
committed by GitHub
parent a6d6ba3606
commit 4f849c23ab
7 changed files with 282 additions and 65 deletions

View File

@@ -13,6 +13,7 @@ local UIManager = require("ui/uimanager")
local dbg = require("dbg")
local logger = require("logger")
local util = require("util")
local Size = require("ui/size")
local ffiUtil = require("ffi/util")
local _ = require("gettext")
local C_ = _.pgettext
@@ -47,6 +48,28 @@ end
function ReaderHighlight:init()
self.select_mode = false -- extended highlighting
self._start_indicator_highlight = false
self._current_indicator_pos = nil
self._previous_indicator_pos = nil
if Device:hasDPad() then
-- Used for text selection with dpad/keys
local QUICK_INDICTOR_MOVE = true
self.key_events.StopHighlightIndicator = { {Device.input.group.Back}, doc = "Stop non-touch highlight", args = true } -- true: clear highlight selection
self.key_events.UpHighlightIndicator = { {"Up"}, doc = "move indicator up", event = "MoveHighlightIndicator", args = {0, -1} }
self.key_events.DownHighlightIndicator = { {"Down"}, doc = "move indicator down", event = "MoveHighlightIndicator", args = {0, 1} }
-- let FewKeys device can move indicator left
self.key_events.LeftHighlightIndicator = { {"Left"}, doc = "move indicator left", event = "MoveHighlightIndicator", args = {-1, 0} }
self.key_events.RightHighlightIndicator = { {"Right"}, doc = "move indicator right", event = "MoveHighlightIndicator", args = {1, 0} }
self.key_events.HighlightPress = { {"Press"}, doc = "highlight start or end" }
if Device:hasKeys() then
self.key_events.QuicklyUpHighlightIndicator = { {"Shift", "Up"}, doc = "quick move indicator up", event = "MoveHighlightIndicator", args = {0, -1, QUICK_INDICTOR_MOVE} }
self.key_events.QuicklyDownHighlightIndicator = { {"Shift", "Down"}, doc = "quick move indicator down", event = "MoveHighlightIndicator", args = {0, 1, QUICK_INDICTOR_MOVE} }
self.key_events.QuicklyLeftHighlightIndicator = { {"Shift", "Left"}, doc = "quick move indicator left", event = "MoveHighlightIndicator", args = {-1, 0, QUICK_INDICTOR_MOVE} }
self.key_events.QuicklyRightHighlightIndicator = { {"Shift", "Right"}, doc = "quick move indicator right", event = "MoveHighlightIndicator", args = {1, 0, QUICK_INDICTOR_MOVE} }
self.key_events.StartHighlightIndicator = { {"H"}, doc = "start non-touch highlight" }
end
end
self._highlight_buttons = {
-- highlight and add_note are for the document itself,
@@ -295,6 +318,14 @@ local long_press_action = {
function ReaderHighlight:addToMainMenu(menu_items)
-- insert table to main reader menu
if Device:hasDPad() then
menu_items.start_content_selection = {
text = _("Start content selection"),
callback = function()
self:onStartHighlightIndicator()
end,
}
end
menu_items.highlight_options = {
text = _("Highlight style"),
sub_item_table = {},
@@ -361,14 +392,35 @@ function ReaderHighlight:addToMainMenu(menu_items)
end
menu_items.translation_settings = Translator:genSettingsMenu()
if not Device:isTouchDevice() then
-- Menu items below aren't needed.
return
end
menu_items.long_press = {
text = _("Long-press on text"),
sub_item_table = {
{
text = _("Highlight long-press interval"),
keep_menu_open = true,
callback = function()
local SpinWidget = require("ui/widget/spinwidget")
local items = SpinWidget:new{
title_text = _("Highlight long-press interval"),
info_text = _([[
If a touch is not released in this interval, it is considered a long-press. On document text, single word selection will not be triggered.
The interval value is in seconds and can range from 3 to 20 seconds.]]),
width = math.floor(Screen:getWidth() * 0.75),
value = G_reader_settings:readSetting("highlight_long_hold_threshold", 3),
value_min = 3,
value_max = 20,
value_step = 1,
value_hold_step = 5,
ok_text = _("Set interval"),
default_value = 3,
callback = function(spin)
G_reader_settings:saveSetting("highlight_long_hold_threshold", spin.value)
end
}
UIManager:show(items)
end,
},
{
text = _("Dictionary on single word selection"),
checked_func = function()
@@ -397,6 +449,12 @@ function ReaderHighlight:addToMainMenu(menu_items)
end,
})
end
-- long_press menu is under taps_and_gestures menu which is not available for non touch device
-- Clone long_press menu and change label making much meaning for non touch devices
if Device:hasDPad() then
menu_items.selection_text = util.tableDeepCopy(menu_items.long_press)
menu_items.selection_text.text = _("Select on text")
end
end
function ReaderHighlight:genPanelZoomMenu()
@@ -907,6 +965,7 @@ function ReaderHighlight:onHold(arg, ges)
fullscreen = true,
}
UIManager:show(imgviewer)
self:onStopHighlightIndicator()
return true
end
@@ -1365,7 +1424,8 @@ function ReaderHighlight:onHoldRelease()
local long_final_hold = false
if self.hold_last_tv then
local hold_duration = TimeVal:now() - self.hold_last_tv
if hold_duration > TimeVal:new{ sec = 3, usec = 0 } then
local long_hold_threshold = G_reader_settings:readSetting("highlight_long_hold_threshold", 3)
if hold_duration > TimeVal:new{ sec = long_hold_threshold, usec = 0 } then
-- We stayed 3 seconds before release without updating selection
long_final_hold = true
end
@@ -1806,4 +1866,125 @@ function ReaderHighlight:onClose()
self:clear()
end
function ReaderHighlight:onHighlightPress()
if self._current_indicator_pos then
if not self._start_indicator_highlight then
-- try a tap at current indicator position to open any existing highlight
if not self:onTap(nil, self:_createHighlightGesture("tap")) then
-- no existing highlight at current indicator position: start hold
self._start_indicator_highlight = true
self:onHold(nil, self:_createHighlightGesture("hold"))
if self.selected_text and self.selected_text.sboxes and #self.selected_text.sboxes then
local pos = self.selected_text.sboxes[1]
-- set hold_pos to center of selected_test to make center selection more stable, not jitted at edge
self.hold_pos = self.view:screenToPageTransform({
x = pos.x + pos.w / 2,
y = pos.y + pos.h / 2
})
-- move indicator to center selected text making succeed same row selection much accurate.
UIManager:setDirty(self.dialog, "ui", self._current_indicator_pos)
self._current_indicator_pos.x = pos.x + pos.w / 2 - self._current_indicator_pos.w / 2
self._current_indicator_pos.y = pos.y + pos.h / 2 - self._current_indicator_pos.h / 2
UIManager:setDirty(self.dialog, "ui", self._current_indicator_pos)
end
else
self:onStopHighlightIndicator(true) -- need_clear_selection=true
end
else
self:onHoldRelease(nil, self:_createHighlightGesture("hold_release"))
self:onStopHighlightIndicator()
end
return true
end
return false
end
function ReaderHighlight:onStartHighlightIndicator()
if self.view.visible_area and not self._current_indicator_pos then
-- set start position to centor of page
local rect = self._previous_indicator_pos
if not rect then
rect = Geom:new()
rect.x = self.view.visible_area.w / 2
rect.y = self.view.visible_area.h / 2
rect.w = Size.item.height_default
rect.h = rect.w
end
self._current_indicator_pos = rect
self.view.highlight.indicator = rect
UIManager:setDirty(self.dialog, "ui", rect)
return true
end
return false
end
function ReaderHighlight:onStopHighlightIndicator(need_clear_selection)
if self._current_indicator_pos then
local rect = self._current_indicator_pos
self._previous_indicator_pos = rect
self._start_indicator_highlight = false
self._current_indicator_pos = nil
self.view.highlight.indicator = nil
UIManager:setDirty(self.dialog, "ui", rect)
if need_clear_selection then
self:clear()
end
return true
end
return false
end
function ReaderHighlight:onMoveHighlightIndicator(args)
if self.view.visible_area and self._current_indicator_pos then
local dx, dy, quick_move = unpack(args)
local step_distance = self.view.visible_area.w / 5 -- quick move distance: fifth of visible_area
local y_step_distance = self.view.visible_area.h / 5
if step_distance > y_step_distance then
-- take the smaller, make all direction move distance much predictable
step_distance = y_step_distance
end
if not quick_move then
step_distance = step_distance / 4 -- twentieth of visible_area
end
local rect = self._current_indicator_pos:copy()
rect.x = rect.x + step_distance * dx
rect.y = rect.y + step_distance * dy
if rect.x < 0 then
rect.x = 0
end
if rect.x + rect.w > self.view.visible_area.w then
rect.x = self.view.visible_area.w - rect.w
end
if rect.y < 0 then
rect.y = 0
end
if rect.y + rect.h > self.view.visible_area.h then
rect.y = self.view.visible_area.h - rect.h
end
UIManager:setDirty(self.dialog, "ui", self._current_indicator_pos)
self._current_indicator_pos = rect
self.view.highlight.indicator = rect
UIManager:setDirty(self.dialog, "ui", rect)
if self._start_indicator_highlight then
self:onHoldPan(nil, self:_createHighlightGesture("hold_pan"))
end
return true
end
return false
end
function ReaderHighlight:_createHighlightGesture(gesture)
local point = self._current_indicator_pos:copy()
point.x = point.x + point.w / 2
point.y = point.y + point.h / 2
point.w = 0
point.h = 0
return {
ges = gesture,
pos = point,
time = TimeVal:realtime(),
}
end
return ReaderHighlight