From b2895731f1fe82f3392587d9afa70541acb2a45a Mon Sep 17 00:00:00 2001 From: hius07 <62179190+hius07@users.noreply.github.com> Date: Mon, 23 Jun 2025 12:18:54 +0300 Subject: [PATCH] Gesture overview (#13909) --- frontend/dispatcher.lua | 8 +- .../ui/elements/filemanager_menu_order.lua | 1 + frontend/ui/elements/reader_menu_order.lua | 1 + frontend/ui/widget/keyvaluepage.lua | 4 + plugins/gestures.koplugin/main.lua | 214 +++++++++++++++--- 5 files changed, 196 insertions(+), 32 deletions(-) diff --git a/frontend/dispatcher.lua b/frontend/dispatcher.lua index d5f266474..760d09740 100644 --- a/frontend/dispatcher.lua +++ b/frontend/dispatcher.lua @@ -52,6 +52,7 @@ local Dispatcher = { -- See above for description. local settingsList = { -- General + gesture_overview = {category="none", event="ShowGestureOverview", title=_("Gesture overview"), general=true}, filemanager = {category="none", event="Home", title=_("File browser"), general=true}, open_previous_document = {category="none", event="OpenLastDoc", title=_("Open previous document"), general=true}, history = {category="none", event="ShowHist", title=_("History"), general=true}, @@ -294,6 +295,7 @@ local settingsList = { -- array for item order in menu local dispatcher_menu_order = { -- General + "gesture_overview", "filemanager", "open_previous_document", "history", @@ -631,7 +633,7 @@ function Dispatcher:removeAction(name) return true end -local function iter_func(settings) +function Dispatcher.iter_func(settings) local order = util.tableGetValue(settings, "settings", "order") if order and #order > 1 then return ipairs(order) @@ -765,7 +767,7 @@ function Dispatcher.getDisplayList(settings, for_sorting) local item_table = {} if not settings then return item_table end local is_check_mark = for_sorting and settings.settings and settings.settings.show_as_quickmenu - for item, v in iter_func(settings) do + for item, v in Dispatcher.iter_func(settings) do if type(item) == "number" then item = v end if settingsList[item] ~= nil and settingsList[item].condition ~= false then table.insert(item_table, { @@ -1198,7 +1200,7 @@ function Dispatcher:execute(settings, exec_props) Notification:notify(T(_("Executing profile: %1"), settings.settings.name)) end local gesture = exec_props and exec_props.gesture - for k, v in iter_func(settings) do + for k, v in Dispatcher.iter_func(settings) do if type(k) == "number" then k = v v = settings[k] diff --git a/frontend/ui/elements/filemanager_menu_order.lua b/frontend/ui/elements/filemanager_menu_order.lua index 338deb238..e1fb11150 100644 --- a/frontend/ui/elements/filemanager_menu_order.lua +++ b/frontend/ui/elements/filemanager_menu_order.lua @@ -109,6 +109,7 @@ local order = { }, taps_and_gestures = { "gesture_manager", + "gesture_overview", "gesture_intervals", "----------------------------", "ignore_hold_corners", diff --git a/frontend/ui/elements/reader_menu_order.lua b/frontend/ui/elements/reader_menu_order.lua index b168125f0..ba2e52ed2 100644 --- a/frontend/ui/elements/reader_menu_order.lua +++ b/frontend/ui/elements/reader_menu_order.lua @@ -158,6 +158,7 @@ local order = { }, taps_and_gestures = { "gesture_manager", + "gesture_overview", "gesture_intervals", "----------------------------", "ignore_hold_corners", diff --git a/frontend/ui/widget/keyvaluepage.lua b/frontend/ui/widget/keyvaluepage.lua index a96f2b232..7e0c041dc 100644 --- a/frontend/ui/widget/keyvaluepage.lua +++ b/frontend/ui/widget/keyvaluepage.lua @@ -88,6 +88,9 @@ function KeyValueItem:init() local key_w = math.floor(frame_internal_width * ratio - middle_padding) local value_w = math.floor(frame_internal_width * (1-ratio)) + if self.key_bold == false then + self.key_font_name = self.value_font_name + end local key_widget = TextWidget:new{ text = self.key, max_width = available_width, @@ -678,6 +681,7 @@ function KeyValuePage:_populateItems() width = self.item_width, width_ratio = width_ratio, font_size = self.items_font_size, + key_bold = entry.key_bold, key = entry[1], value = entry[2], value_lang = self.values_lang, diff --git a/plugins/gestures.koplugin/main.lua b/plugins/gestures.koplugin/main.lua index 4731eec76..199b36b2c 100644 --- a/plugins/gestures.koplugin/main.lua +++ b/plugins/gestures.koplugin/main.lua @@ -1,7 +1,11 @@ +local Device = require("device") +if not Device:isTouchDevice() then + return { disabled = true } +end + local BD = require("ui/bidi") local ConfirmBox = require("ui/widget/confirmbox") local DataStorage = require("datastorage") -local Device = require("device") local Dispatcher = require("dispatcher") local Event = require("ui/event") local Geom = require("ui/geometry") @@ -23,10 +27,6 @@ local _ = require("gettext") local C_ = _.pgettext local T = ffiUtil.template -if not Device:isTouchDevice() then - return { disabled = true, } -end - local Gestures = WidgetContainer:extend{ name = "gestures", settings_data = nil, @@ -34,9 +34,81 @@ local Gestures = WidgetContainer:extend{ defaults = nil, custom_multiswipes = nil, updated = false, + has_multitouch = Device:hasMultitouch(), } local gestures_path = ffiUtil.joinPath(DataStorage:getSettingsDir(), "gestures.lua") +local section_titles = { + tap_corner = _("Tap corner"), + hold_corner = _("Long-press on corner"), + one_finger_swipe = _("One-finger swipe"), + double_tap = _("Double tap"), + two_finger_tap = _("Two-finger tap corner"), + two_finger_swipe = _("Two-finger swipe"), + spread_and_pinch = _("Spread and pinch"), + two_finger_rotation = _("Two-finger rotation"), + multiswipes = _("Multiswipes"), + custom_multiswipes = _("Custom multiswipes"), +} + +local section_items = { + tap_corner = { + "tap_top_left_corner", + "tap_top_right_corner", + "tap_left_bottom_corner", + "tap_right_bottom_corner", + }, + hold_corner = { + "hold_top_left_corner", + "hold_top_right_corner", + "hold_bottom_left_corner", + "hold_bottom_right_corner", + }, + one_finger_swipe = { + "short_diagonal_swipe", + "one_finger_swipe_left_edge_down", + "one_finger_swipe_left_edge_up", + "one_finger_swipe_right_edge_down", + "one_finger_swipe_right_edge_up", + "one_finger_swipe_top_edge_right", + "one_finger_swipe_top_edge_left", + "one_finger_swipe_bottom_edge_right", + "one_finger_swipe_bottom_edge_left", + }, + double_tap = { + "double_tap_left_side", + "double_tap_right_side", + "double_tap_top_left_corner", + "double_tap_top_right_corner", + "double_tap_bottom_left_corner", + "double_tap_bottom_right_corner", + }, + two_finger_tap = { + "two_finger_tap_top_left_corner", + "two_finger_tap_top_right_corner", + "two_finger_tap_bottom_left_corner", + "two_finger_tap_bottom_right_corner", + }, + two_finger_swipe = { + "two_finger_swipe_east", + "two_finger_swipe_west", + "two_finger_swipe_south", + "two_finger_swipe_north", + "two_finger_swipe_northeast", + "two_finger_swipe_northwest", + "two_finger_swipe_southeast", + "two_finger_swipe_southwest", + }, + spread_and_pinch = { + "spread_gesture", + "pinch_gesture", + }, + two_finger_rotation = { + "rotate_cw", + "rotate_ccw", + }, +} + local gestures_list = { tap_top_left_corner = _("Top left"), tap_top_right_corner = _("Top right"), @@ -141,7 +213,7 @@ function Gestures:init() local defaults_path = ffiUtil.joinPath(self.path, "defaults.lua") self.ignore_hold_corners = G_reader_settings:isTrue("ignore_hold_corners") self.multiswipes_enabled = G_reader_settings:isTrue("multiswipes_enabled") - self.is_docless = self.ui == nil or self.ui.document == nil + self.is_docless = self.ui.document == nil self.ges_mode = self.is_docless and "gesture_fm" or "gesture_reader" self.defaults = LuaSettings:open(defaults_path).data[self.ges_mode] if not self.settings_data then @@ -321,8 +393,7 @@ function Gestures:genSubItemTable(gestures) return sub_item_table end -function Gestures:genMultiswipeMenu() - local sub_item_table = {} +function Gestures:genMultiswipeMenu(get_list) -- { multiswipe name, separator } local multiswipe_list = { {"multiswipe_west_east",}, @@ -361,6 +432,10 @@ function Gestures:genMultiswipeMenu() {"multiswipe_southeast_southwest_northwest",}, {"multiswipe_southeast_northeast_northwest",}, } + if get_list then + return multiswipe_list + end + local sub_item_table = {} for _, item in ipairs(multiswipe_list) do table.insert(sub_item_table, self:genSubItem(item[1], item[2])) end @@ -465,7 +540,7 @@ function Gestures:genCustomMultiswipeSubmenu() self:multiswipeRecorder(touchmenu_instance) end, help_text = _("The number of possible multiswipe gestures is theoretically infinite. With the multiswipe recorder you can easily record your own."), - } + }, } for item in ffiUtil.orderedPairs(self.custom_multiswipes) do local hold_callback = function(touchmenu_instance) @@ -499,6 +574,78 @@ function Gestures:genCustomMultiswipeSubmenu() return submenu end +function Gestures:onShowGestureOverview() + local KeyValuePage = require("ui/widget/keyvaluepage") + local nothing = Dispatcher:menuTextFunc({}) + local kv_pairs = {} + local function add_section(section_id, items) + items = items or section_items[section_id] + local pos = #kv_pairs + 1 + local added + for _, ges_name in ipairs(items) do + if section_id == "multiswipes" then + ges_name = ges_name[1] + end + local gest = self.gestures[ges_name] + if gest then + local value = Dispatcher:menuTextFunc(gest) + if value ~= nothing then + local key = gestures_list[ges_name] or self:friendlyMultiswipeName(ges_name) + local callback + if Dispatcher:_itemsCount(gest) > 1 then -- multi-action gesture + local text = {} + for item, v in Dispatcher.iter_func(gest) do + if type(item) == "number" then item = v end + if gest[item] ~= nil then + table.insert(text, " " .. Dispatcher:getNameFromItem(item, gest)) + end + end + callback = function() + UIManager:show(InfoMessage:new{ + text = table.concat(text, "\n"), + show_icon = false, + }) + end + end + table.insert(kv_pairs, { key, value, callback = callback, key_bold = false }) + added = true + end + end + end + if added then + table.insert(kv_pairs, pos, { section_titles[section_id], " " }) + kv_pairs[#kv_pairs].separator = true + end + end + add_section("tap_corner") + add_section("hold_corner") + add_section("one_finger_swipe") + if not self.is_docless and self.ui.disable_double_tap ~= true then + add_section("double_tap") + end + if self.has_multitouch then + add_section("two_finger_tap") + add_section("two_finger_swipe") + add_section("spread_and_pinch") + add_section("two_finger_rotation") + end + if self.multiswipes_enabled then + add_section("multiswipes", self:genMultiswipeMenu(true)) + if next(self.custom_multiswipes) then + local items = {} + for item in ffiUtil.orderedPairs(self.custom_multiswipes) do + table.insert(items, item) + end + add_section("custom_multiswipes", items) + end + end + UIManager:show(KeyValuePage:new{ + title = self.is_docless and _("Gestures in file browser") or _("Gestures in reader"), + value_overflow_align = "right", + kv_pairs = kv_pairs, + }) +end + function Gestures:addIntervals(menu_items) menu_items.gesture_intervals = { text = _("Gesture intervals"), @@ -702,6 +849,7 @@ function Gestures:addToMainMenu(menu_items) menu_items.gesture_manager = { text = _("Gesture manager"), sub_item_table = { + max_per_page = 11, { text = _("Turn on multiswipes"), checked_func = function() return self.multiswipes_enabled end, @@ -712,57 +860,65 @@ function Gestures:addToMainMenu(menu_items) help_text = multiswipes_info_text, }, { - text = _("Multiswipes"), + text = section_titles.multiswipes, sub_item_table = self:genMultiswipeMenu(), enabled_func = function() return self.multiswipes_enabled end, }, { - text = _("Custom multiswipes"), + text = section_titles.custom_multiswipes, sub_item_table = self:genCustomMultiswipeSubmenu(), enabled_func = function() return self.multiswipes_enabled end, separator = true, }, { - text = _("Tap corner"), - sub_item_table = self:genSubItemTable({"tap_top_left_corner", "tap_top_right_corner", "tap_left_bottom_corner", "tap_right_bottom_corner"}), + text = section_titles.tap_corner, + sub_item_table = self:genSubItemTable(section_items.tap_corner), }, { - text = _("Long-press on corner"), - sub_item_table = self:genSubItemTable({"hold_top_left_corner", "hold_top_right_corner", "hold_bottom_left_corner", "hold_bottom_right_corner"}), + text = section_titles.hold_corner, + sub_item_table = self:genSubItemTable(section_items.hold_corner), }, { - text = _("One-finger swipe"), - sub_item_table = self:genSubItemTable({"short_diagonal_swipe", "one_finger_swipe_left_edge_down", "one_finger_swipe_left_edge_up", "one_finger_swipe_right_edge_down", "one_finger_swipe_right_edge_up", "one_finger_swipe_top_edge_right", "one_finger_swipe_top_edge_left", "one_finger_swipe_bottom_edge_right", "one_finger_swipe_bottom_edge_left"}), + text = section_titles.one_finger_swipe, + sub_item_table = self:genSubItemTable(section_items.one_finger_swipe), }, { - text = _("Double tap"), + text = section_titles.double_tap, enabled_func = function() - return self.ges_mode == "gesture_reader" and self.ui.disable_double_tap ~= true + return not self.is_docless and self.ui.disable_double_tap ~= true end, - sub_item_table = self:genSubItemTable({"double_tap_left_side", "double_tap_right_side", "double_tap_top_left_corner", "double_tap_top_right_corner", "double_tap_bottom_left_corner", "double_tap_bottom_right_corner"}), + sub_item_table = self:genSubItemTable(section_items.double_tap), }, }, } - if Device:hasMultitouch() then + if self.has_multitouch then table.insert(menu_items.gesture_manager.sub_item_table, { - text = _("Two-finger tap corner"), - sub_item_table = self:genSubItemTable({"two_finger_tap_top_left_corner", "two_finger_tap_top_right_corner", "two_finger_tap_bottom_left_corner", "two_finger_tap_bottom_right_corner"}), + text = section_titles.two_finger_tap, + sub_item_table = self:genSubItemTable(section_items.two_finger_tap), }) table.insert(menu_items.gesture_manager.sub_item_table, { - text = _("Two-finger swipe"), - sub_item_table = self:genSubItemTable({"two_finger_swipe_east", "two_finger_swipe_west", "two_finger_swipe_south", "two_finger_swipe_north", "two_finger_swipe_northeast", "two_finger_swipe_northwest", "two_finger_swipe_southeast", "two_finger_swipe_southwest"}), + text = section_titles.two_finger_swipe, + sub_item_table = self:genSubItemTable(section_items.two_finger_swipe), }) table.insert(menu_items.gesture_manager.sub_item_table, { - text = _("Spread and pinch"), - sub_item_table = self:genSubItemTable({"spread_gesture", "pinch_gesture"}), + text = section_titles.spread_and_pinch, + sub_item_table = self:genSubItemTable(section_items.spread_and_pinch), }) table.insert(menu_items.gesture_manager.sub_item_table, { - text = _("Two-finger rotation"), - sub_item_table = self:genSubItemTable({"rotate_cw", "rotate_ccw"}), + text = section_titles.two_finger_rotation, + sub_item_table = self:genSubItemTable(section_items.two_finger_rotation), }) end + menu_items.gesture_overview = { + text = _("Gesture overview"), + keep_menu_open = true, + callback = function() + self:onShowGestureOverview() + end, + } + self:addIntervals(menu_items) end