diff --git a/frontend/dispatcher.lua b/frontend/dispatcher.lua index 41b3d5cbd..8554f7dd2 100644 --- a/frontend/dispatcher.lua +++ b/frontend/dispatcher.lua @@ -676,45 +676,50 @@ function Dispatcher:getArgFromValue(item, value) end -- Add the item to the end of the execution order. --- If item or the order is nil all items will be added. -function Dispatcher:_addToOrder(location, settings, item) - if location[settings] then - if not location[settings].settings then location[settings].settings = {} end - if not location[settings].settings.order or item == nil then - location[settings].settings.order = {} - for k in pairs(location[settings]) do +-- If order is nil all items will be added. +function Dispatcher._addToOrder(location, settings, item) + local actions = location[settings] + local count = Dispatcher:_itemsCount(actions) + if count == 2 then + local first_item + for k in pairs(actions) do + if k ~= "settings" and k~= item then + first_item = k + break + end + end + actions.settings = actions.settings or {} + actions.settings.order = { first_item, item } + elseif count > 2 then + local order = util.tableGetValue(actions, "settings", "order") + if order then + table.insert(location[settings].settings.order, item) + else -- old unordered actions + util.tableSetValue(actions, {}, "settings", "order") + for k in pairs(actions) do if settingsList[k] ~= nil then table.insert(location[settings].settings.order, k) end end - else - if not util.arrayContains(location[settings].settings.order, item) then - table.insert(location[settings].settings.order, item) - end end end end -- Remove the item from the execution order. --- If item is nil all items will be removed. --- If the resulting order is empty it will be nilled -function Dispatcher:_removeFromOrder(location, settings, item) - if location[settings] and location[settings].settings then - if location[settings].settings.order then - if item then - local k = util.arrayContains(location[settings].settings.order, item) - if k then table.remove(location[settings].settings.order, k) end - else - location[settings].settings.order = {} - end - if next(location[settings].settings.order) == nil then - location[settings].settings.order = nil - if next(location[settings].settings) == nil then - location[settings].settings = nil - end +-- If the resulting order is empty it will be nilled. +function Dispatcher._removeFromOrder(location, settings, item) + local actions = location[settings] + local order = util.tableGetValue(actions, "settings", "order") + if order then + local k = util.arrayContains(order, item) + if k then + table.remove(order, k) + if Dispatcher:_itemsCount(actions) < 2 then + util.tableRemoveValue(actions, "settings", "order") end end end + util.tableRemoveValue(actions, "settings", "quickmenu_separators", item) end -- Get a textual representation of the enabled actions to display in a menu item. @@ -734,37 +739,46 @@ function Dispatcher:menuTextFunc(settings) end -- Get a list of all enabled actions to display in a menu. -function Dispatcher:getDisplayList(settings) +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 if type(item) == "number" then item = v end - if settingsList[item] ~= nil and (settingsList[item].condition == nil or settingsList[item].condition == true) then - table.insert(item_table, {text = Dispatcher:getNameFromItem(item, settings), key = item}) + if settingsList[item] ~= nil and settingsList[item].condition ~= false then + table.insert(item_table, { + text = Dispatcher:getNameFromItem(item, settings), + key = item, + checked_func = is_check_mark and function() + return settings.settings.quickmenu_separators and settings.settings.quickmenu_separators[item] + end, + callback = is_check_mark and function() + if settings.settings.quickmenu_separators and settings.settings.quickmenu_separators[item] then + util.tableRemoveValue(settings.settings, "quickmenu_separators", item) + else + util.tableSetValue(settings.settings, true, "quickmenu_separators", item) + end + end, + }) end end return item_table end -- Display a SortWidget to sort the enable actions execution order. -function Dispatcher:_sortActions(caller, location, settings, touchmenu_instance) - local display_list = Dispatcher:getDisplayList(location[settings]) +function Dispatcher._sortActions(caller, actions) + local show_as_quickmenu = util.tableGetValue(actions, "settings", "show_as_quickmenu") + local display_list = Dispatcher.getDisplayList(actions, true) local SortWidget = require("ui/widget/sortwidget") - local sort_widget - sort_widget = SortWidget:new{ - title = _("Arrange actions"), + local sort_widget = SortWidget:new{ + title = show_as_quickmenu and _("Arrange actions and QuickMenu separators") or _("Arrange actions"), + underscore_checked_item = show_as_quickmenu, item_table = display_list, callback = function() - if location[settings] and next(location[settings]) ~= nil then - if not location[settings].settings then - location[settings].settings = {} - end - location[settings].settings.order = {} - for i, v in ipairs(sort_widget.item_table) do - location[settings].settings.order[i] = v.key - end + util.tableSetValue(actions, {}, "settings", "order") + for i, v in ipairs(display_list) do + actions.settings.order[i] = v.key end - if touchmenu_instance then touchmenu_instance:updateItems() end caller.updated = true end } @@ -778,10 +792,10 @@ function Dispatcher:_addItem(caller, menu, location, settings, section) location[settings] = {} end location[settings][k] = value - Dispatcher:_addToOrder(location, settings, k) + Dispatcher._addToOrder(location, settings, k) else location[settings][k] = nil - Dispatcher:_removeFromOrder(location, settings, k) + Dispatcher._removeFromOrder(location, settings, k) end caller.updated = true if touchmenu_instance then @@ -926,6 +940,21 @@ function Dispatcher:_addItem(caller, menu, location, settings, section) end end +function Dispatcher.removeActions(actions, do_remove) + if actions then + local count = Dispatcher:_itemsCount(actions) + if count == 1 then + do_remove() + elseif count > 1 then + local ConfirmBox = require("ui/widget/confirmbox") + UIManager:show(ConfirmBox:new{ + text = T(NC_("Dispatcher", "1 action will be removed.", "%1 actions will be removed.", count), count), + ok_callback = do_remove, + }) + end + end +end + --[[-- Add a submenu to edit which items are dispatched arguments are: @@ -941,19 +970,22 @@ function Dispatcher:addSubMenu(caller, menu, location, settings) menu.ignored_by_menu_search = true -- all those would be duplicated table.insert(menu, { text = _("Nothing"), - separator = true, + keep_menu_open = true, + no_refresh_on_check = true, checked_func = function() return location[settings] ~= nil and Dispatcher:_itemsCount(location[settings]) == 0 end, callback = function(touchmenu_instance) - local name = location[settings] and location[settings].settings and location[settings].settings.name - location[settings] = {} - if name then - location[settings].settings = { name = name } + local function do_remove() + local actions = location[settings] + local name = actions and actions.settings and actions.settings.name + location[settings] = name and { settings = { name = name } } or {} + caller.updated = true + touchmenu_instance:updateItems() end - caller.updated = true - if touchmenu_instance then touchmenu_instance:updateItems() end + Dispatcher.removeActions(location[settings], do_remove) end, + separator = true, }) local section_list = { {"general", _("General")}, @@ -983,7 +1015,7 @@ function Dispatcher:addSubMenu(caller, menu, location, settings) for k, _ in pairs(location[settings]) do if settingsList[k] ~= nil and settingsList[k][section[1]] == true then location[settings][k] = nil - Dispatcher:_removeFromOrder(location, settings, k) + Dispatcher._removeFromOrder(location, settings, k) caller.updated = true end end @@ -995,45 +1027,34 @@ function Dispatcher:addSubMenu(caller, menu, location, settings) end menu.max_per_page = #menu -- next items in page 2 table.insert(menu, { - text = _("Arrange actions"), - checked_func = function() - return location[settings] ~= nil - and location[settings].settings ~= nil - and location[settings].settings.order ~= nil + text_func = function() + return util.tableGetValue(location[settings], "settings", "show_as_quickmenu") + and _("Arrange actions and QuickMenu separators") or _("Arrange actions") + end, + enabled_func = function() + return location[settings] and Dispatcher:_itemsCount(location[settings]) > 1 or false end, callback = function(touchmenu_instance) - Dispatcher:_sortActions(caller, location, settings, touchmenu_instance) - end, - hold_callback = function(touchmenu_instance) - if location[settings] - and location[settings].settings - and location[settings].settings.order then - Dispatcher:_removeFromOrder(location, settings) - caller.updated = true - if touchmenu_instance then touchmenu_instance:updateItems() end - end + Dispatcher._sortActions(caller, location[settings]) end, + keep_menu_open = true, + separator = true, }) table.insert(menu, { text = _("Show as QuickMenu"), checked_func = function() - return location[settings] ~= nil - and location[settings].settings ~= nil - and location[settings].settings.show_as_quickmenu + return util.tableGetValue(location[settings], "settings", "show_as_quickmenu") end, callback = function() - if location[settings] then - if location[settings].settings then - if location[settings].settings.show_as_quickmenu then - location[settings].settings.show_as_quickmenu = nil - if next(location[settings].settings) == nil then - location[settings].settings = nil - end - else - location[settings].settings.show_as_quickmenu = true - end + local actions = location[settings] + if actions then + if util.tableGetValue(actions, "settings", "show_as_quickmenu") then + util.tableRemoveValue(actions, "settings", "show_as_quickmenu") + util.tableRemoveValue(actions, "settings", "quickmenu_separators") + util.tableRemoveValue(actions, "settings", "keep_open_on_apply") + util.tableRemoveValue(actions, "settings", "anchor_quickmenu") else - location[settings].settings = {["show_as_quickmenu"] = true} + util.tableSetValue(actions, true, "settings", "show_as_quickmenu") end caller.updated = true end @@ -1041,24 +1062,19 @@ function Dispatcher:addSubMenu(caller, menu, location, settings) }) table.insert(menu, { text = _("Keep QuickMenu open"), + enabled_func = function() + return util.tableGetValue(location[settings], "settings", "show_as_quickmenu") or false + end, checked_func = function() - return location[settings] ~= nil - and location[settings].settings ~= nil - and location[settings].settings.keep_open_on_apply + return util.tableGetValue(location[settings], "settings", "keep_open_on_apply") end, callback = function() - if location[settings] then - if location[settings].settings then - if location[settings].settings.keep_open_on_apply then - location[settings].settings.keep_open_on_apply = nil - if next(location[settings].settings) == nil then - location[settings].settings = nil - end - else - location[settings].settings.keep_open_on_apply = true - end + local actions = location[settings] + if actions then + if util.tableGetValue(actions, "settings", "keep_open_on_apply") then + util.tableRemoveValue(actions, "settings", "keep_open_on_apply") else - location[settings].settings = {["keep_open_on_apply"] = true} + util.tableSetValue(actions, true, "settings", "keep_open_on_apply") end caller.updated = true end @@ -1082,10 +1098,10 @@ function Dispatcher:isActionEnabled(action) return not disabled end -function Dispatcher:_showAsMenu(settings, exec_props) - local title = settings.settings.name or _("QuickMenu") +function Dispatcher._showAsMenu(settings, exec_props) + local title = settings.settings.name local keep_open_on_apply = settings.settings.keep_open_on_apply - local display_list = Dispatcher:getDisplayList(settings) + local display_list = Dispatcher.getDisplayList(settings) local quickmenu local buttons = {} if exec_props and exec_props.qm_show then @@ -1123,6 +1139,9 @@ function Dispatcher:_showAsMenu(settings, exec_props) end end, }}) + if settings.settings.quickmenu_separators and settings.settings.quickmenu_separators[v.key] then + table.insert(buttons, {}) + end end local ButtonDialog = require("ui/widget/buttondialog") quickmenu = ButtonDialog:new{ @@ -1148,12 +1167,16 @@ arguments are: function Dispatcher:execute(settings, exec_props) if ((exec_props == nil or exec_props.qm_show == nil) and settings.settings and settings.settings.show_as_quickmenu) or (exec_props and exec_props.qm_show) then - return Dispatcher:_showAsMenu(settings, exec_props) + return Dispatcher._showAsMenu(settings, exec_props) end local has_many = Dispatcher:_itemsCount(settings) > 1 if has_many then UIManager:broadcastEvent(Event:new("BatchedUpdate")) end + Notification:setNotifySource(Notification.SOURCE_DISPATCHER) + if settings.settings and settings.settings.notify then + 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 if type(k) == "number" then @@ -1161,10 +1184,6 @@ function Dispatcher:execute(settings, exec_props) v = settings[k] end if Dispatcher:isActionEnabled(settingsList[k]) then - Notification:setNotifySource(Notification.SOURCE_DISPATCHER) - if settings.settings and settings.settings.notify then - Notification:notify(T(_("Executing profile: %1"), settings.settings.name)) - end if settingsList[k].configurable then local value = v if type(v) ~= "number" then @@ -1174,7 +1193,6 @@ function Dispatcher:execute(settings, exec_props) end UIManager:sendEvent(Event:new("ConfigChange", settingsList[k].configurable.name, value)) end - local category = settingsList[k].category local event = settingsList[k].event if category == "none" then @@ -1195,8 +1213,8 @@ function Dispatcher:execute(settings, exec_props) UIManager:sendEvent(Event:new(event, arg)) end end - Notification:resetNotifySource() end + Notification:resetNotifySource() if has_many then UIManager:broadcastEvent(Event:new("BatchedUpdateDone")) end diff --git a/frontend/ui/widget/sortwidget.lua b/frontend/ui/widget/sortwidget.lua index b76f8b86b..13c64c1ca 100644 --- a/frontend/ui/widget/sortwidget.lua +++ b/frontend/ui/widget/sortwidget.lua @@ -83,10 +83,17 @@ function SortItemWidget:init() dimen = Geom:new{ w = checked_widget:getSize().w }, self.checkmark_widget, }, - TextWidget:new{ - text = self.item.text, - max_width = text_max_width, - face = self.item.face or self.face, + VerticalGroup:new{ + align = "left", + TextWidget:new{ + text = self.item.text, + max_width = text_max_width, + face = self.item.face or self.face, + }, + self.show_parent.underscore_checked_item and item_checked and LineWidget:new{ + dimen = Geom:new{ w = text_max_width, h = Size.line.thick }, + background = Blitbuffer.COLOR_DARK_GRAY, + }, }, }, }, diff --git a/frontend/ui/widget/touchmenu.lua b/frontend/ui/widget/touchmenu.lua index 50b40620d..0b3bd3ac2 100644 --- a/frontend/ui/widget/touchmenu.lua +++ b/frontend/ui/widget/touchmenu.lua @@ -921,7 +921,9 @@ function TouchMenu:onMenuSelect(item, tap_on_checkmark) -- must set keep_menu_open=true if that is wished) callback(self) if refresh then - self:updateItems() + if not item.no_refresh_on_check then + self:updateItems() + end elseif not item.keep_menu_open then self:closeMenu() end diff --git a/plugins/gestures.koplugin/main.lua b/plugins/gestures.koplugin/main.lua index 07a67b699..55210d790 100644 --- a/plugins/gestures.koplugin/main.lua +++ b/plugins/gestures.koplugin/main.lua @@ -4,7 +4,6 @@ local DataStorage = require("datastorage") local Device = require("device") local Dispatcher = require("dispatcher") local Event = require("ui/event") -local FFIUtil = require("ffi/util") local Geom = require("ui/geometry") local GestureDetector = require("device/gesturedetector") local GestureRange = require("ui/gesturerange") @@ -16,12 +15,13 @@ local Screen = require("device").screen local SpinWidget = require("ui/widget/spinwidget") local UIManager = require("ui/uimanager") local WidgetContainer = require("ui/widget/container/widgetcontainer") +local ffiUtil = require("ffi/util") local logger = require("logger") -local util = require("util") -local T = FFIUtil.template local time = require("ui/time") +local util = require("util") local _ = require("gettext") local C_ = _.pgettext +local T = ffiUtil.template if not Device:isTouchDevice() then return { disabled = true, } @@ -35,7 +35,7 @@ local Gestures = WidgetContainer:extend{ custom_multiswipes = nil, updated = false, } -local gestures_path = FFIUtil.joinPath(DataStorage:getSettingsDir(), "gestures.lua") +local gestures_path = ffiUtil.joinPath(DataStorage:getSettingsDir(), "gestures.lua") local gestures_list = { tap_top_left_corner = _("Top left"), @@ -138,7 +138,7 @@ function Gestures:isGestureAlwaysActive(ges, multiswipe_directions) end function Gestures:init() - local defaults_path = FFIUtil.joinPath(self.path, "defaults.lua") + 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 @@ -149,7 +149,7 @@ function Gestures:init() if not next(self.settings_data.data) then logger.warn("No gestures file or invalid gestures file found, copying defaults") self.settings_data:purge() - FFIUtil.copyFile(defaults_path, gestures_path) + ffiUtil.copyFile(defaults_path, gestures_path) self.settings_data = LuaSettings:open(gestures_path) end end @@ -224,74 +224,70 @@ function Gestures:genMenu(ges) table.insert(sub_items, { text = T(_("%1 (default)"), Dispatcher:menuTextFunc(self.defaults[ges])), keep_menu_open = true, - separator = true, + no_refresh_on_check = true, checked_func = function() return util.tableEquals(self.gestures[ges], self.defaults[ges]) end, - callback = function() - self.gestures[ges] = util.tableDeepCopy(self.defaults[ges]) - self.updated = true + callback = function(touchmenu_instance) + local function do_remove() + self.gestures[ges] = util.tableDeepCopy(self.defaults[ges]) + self.updated = true + touchmenu_instance:updateItems() + end + Dispatcher.removeActions(self.gestures[ges], do_remove) end, + separator = true, }) end table.insert(sub_items, { text = _("Pass through"), keep_menu_open = true, + no_refresh_on_check = true, checked_func = function() return self.gestures[ges] == nil end, - callback = function() - self.gestures[ges] = nil - self.updated = true + callback = function(touchmenu_instance) + local function do_remove() + self.gestures[ges] = nil + self.updated = true + touchmenu_instance:updateItems() + end + Dispatcher.removeActions(self.gestures[ges], do_remove) end, }) Dispatcher:addSubMenu(self, sub_items, self.gestures, ges) sub_items.max_per_page = nil -- restore default, settings in page 2 table.insert(sub_items, { text = _("Anchor QuickMenu to gesture position"), + enabled_func = function() + return util.tableGetValue(self.gestures, ges, "settings", "show_as_quickmenu") or false + end, checked_func = function() - return self.gestures[ges] ~= nil - and self.gestures[ges].settings ~= nil - and self.gestures[ges].settings.anchor_quickmenu + return util.tableGetValue(self.gestures, ges, "settings", "anchor_quickmenu") end, callback = function() if self.gestures[ges] then - if self.gestures[ges].settings then - if self.gestures[ges].settings.anchor_quickmenu then - self.gestures[ges].settings.anchor_quickmenu = nil - if next(self.gestures[ges].settings) == nil then - self.gestures[ges].settings = nil - end - else - self.gestures[ges].settings.anchor_quickmenu = true - end + if util.tableGetValue(self.gestures, ges, "settings", "anchor_quickmenu") then + util.tableRemoveValue(self.gestures, ges, "settings", "anchor_quickmenu") else - self.gestures[ges].settings = {["anchor_quickmenu"] = true} + util.tableSetValue(self.gestures, true, ges, "settings", "anchor_quickmenu") end self.updated = true end end, + separator = true, }) table.insert(sub_items, { text = _("Always active"), checked_func = function() - return self.gestures[ges] ~= nil - and self.gestures[ges].settings ~= nil - and self.gestures[ges].settings.always_active + return util.tableGetValue(self.gestures, ges, "settings", "always_active") end, callback = function() if self.gestures[ges] then - if self.gestures[ges].settings then - if self.gestures[ges].settings.always_active then - self.gestures[ges].settings.always_active = nil - if next(self.gestures[ges].settings) == nil then - self.gestures[ges].settings = nil - end - else - self.gestures[ges].settings.always_active = true - end + if util.tableGetValue(self.gestures, ges, "settings", "always_active") then + util.tableRemoveValue(self.gestures, ges, "settings", "always_active") else - self.gestures[ges].settings = {["always_active"] = true} + util.tableSetValue(self.gestures, true, ges, "settings", "always_active") end self.updated = true end @@ -471,7 +467,7 @@ function Gestures:genCustomMultiswipeSubmenu() 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 + for item in ffiUtil.orderedPairs(self.custom_multiswipes) do local hold_callback = function(touchmenu_instance) UIManager:show(ConfirmBox:new{ text = T(_("Remove custom multiswipe %1?"), self:friendlyMultiswipeName(item)), diff --git a/plugins/profiles.koplugin/main.lua b/plugins/profiles.koplugin/main.lua index 13d0e51a3..b09774e58 100644 --- a/plugins/profiles.koplugin/main.lua +++ b/plugins/profiles.koplugin/main.lua @@ -207,7 +207,7 @@ function Profiles:getSubMenuItems() }, { text_func = function() - return T(_("Edit actions: (%1)"), Dispatcher:menuTextFunc(v)) + return T(_("Edit actions: (%1)"), Dispatcher:menuTextFunc(self.data[k])) end, sub_item_table_func = function() local edit_actions_sub_items = {} @@ -259,7 +259,6 @@ function Profiles:getSubMenuItems() { text = _("Delete"), keep_menu_open = true, - separator = true, callback = function(touchmenu_instance) UIManager:show(ConfirmBox:new{ text = _("Do you want to delete this profile?"), @@ -278,6 +277,7 @@ function Profiles:getSubMenuItems() end, }) end, + separator = true, }, } table.insert(sub_item_table, { @@ -545,6 +545,7 @@ function Profiles:genAutoExecPathChangedMenuItem(text, event, profile_name, sepa local value = util.tableGetValue(self.autoexec, event, profile_name, conditions[i][2]) return value and txt .. ": " .. value or txt end, + no_refresh_on_check = true, checked_func = function() return util.tableGetValue(self.autoexec, event, profile_name, conditions[i][2]) end, @@ -672,6 +673,7 @@ function Profiles:genAutoExecDocConditionalMenuItem(text, event, profile_name, s local txt = util.tableGetValue(self.autoexec, event, profile_name, condition, prop) return txt and title .. " " .. txt or title:sub(1, -2) end, + no_refresh_on_check = true, checked_func = function() return util.tableGetValue(self.autoexec, event, profile_name, condition, prop) and true end, @@ -741,6 +743,7 @@ function Profiles:genAutoExecDocConditionalMenuItem(text, event, profile_name, s enabled_func = function() return not util.tableGetValue(self.autoexec, event_always, profile_name) end, + no_refresh_on_check = true, checked_func = function() return util.tableGetValue(self.autoexec, event, profile_name, conditions[3][2]) and true end, @@ -805,6 +808,7 @@ function Profiles:genAutoExecDocConditionalMenuItem(text, event, profile_name, s enabled_func = function() return not util.tableGetValue(self.autoexec, event_always, profile_name) end, + no_refresh_on_check = true, checked_func = function() return util.tableGetValue(self.autoexec, event, profile_name, conditions[4][2]) and true end,