local CreOptions = require("ui/data/creoptions") local Device = require("device") local Event = require("ui/event") local Screen = require("device").screen local UIManager = require("ui/uimanager") local T = require("ffi/util").template local _ = require("gettext") local Dispatcher = { initialized = false, } --[[-- contains a list of a dispatchable settings each setting contains: category: one of none: a direct event call arg: a event that expects a gesture object or an argument absolutenumber: event that sets a number incrementalnumber: event that increments a number & accepts a gesture object string: event with a list of arguments to chose from event: what to call. title: for use in ui. section: under which menu to display (currently: device, filemanager, rolling, paging) and optionally min/max: for number default args: allowed values for string. toggle: display name for args separator: put a separator after in the menu list --]]-- local settingsList = { -- Device settings show_frontlight_dialog = { category="none", event="ShowFlDialog", title=_("Show frontlight dialog"), device=true, condition=Device:hasFrontlight(),}, toggle_frontlight = { category="none", event="ToggleFrontlight", title=_("Toggle frontlight"), device=true, condition=Device:hasFrontlight(),}, increase_frontlight = { category="incrementalnumber", event="IncreaseFlIntensity", min=1, max=Device:getPowerDevice().fl_max, title=_("Increase frontlight brightness"), device=true, condition=Device:hasFrontlight(),}, decrease_frontlight = { category="incrementalnumber", event="DecreaseFlIntensity", min=1, max=Device:getPowerDevice().fl_max, title=_("Decrease frontlight brightness"), device=true, condition=Device:hasFrontlight(),}, increase_frontlight_warmth = { category="incrementalnumber", event="IncreaseFlWarmth", min=1, max=Device:getPowerDevice().fl_warmth_max, title=_("Increase frontlight warmth"), device=true, condition=Device:hasNaturalLight(),}, decrease_frontlight_warmth = { category="incrementalnumber", event="DecreaseFlWarmth", min=1, max=Device:getPowerDevice().fl_warmth_max, title=_("Decrease frontlight warmth"), device=true, condition=Device:hasNaturalLight(),}, toggle_gsensor = { category="none", event="ToggleGSensor", title=_("Toggle accelerometer"), device=true, condition=Device:canToggleGSensor(),}, wifi_on = { category="none", event="InfoWifiOn", title=_("Turn on Wi-Fi"), device=true, condition=Device:hasWifiToggle(),}, wifi_off = { category="none", event="InfoWifiOff", title=_("Turn off Wi-Fi"), device=true, condition=Device:hasWifiToggle(),}, toggle_wifi = { category="none", event="ToggleWifi", title=_("Toggle Wi-Fi"), device=true, condition=Device:hasWifiToggle(),}, reading_progress = { category="none", event="ShowReaderProgress", title=_("Reading progress"), device=true,}, stats_calendar_view = { category="none", event="ShowCalendarView", title=_("Statistics calendar view"), device=true,}, history = { category="none", event="ShowHist", title=_("History"), device=true,}, open_previous_document = { category="none", event="OpenLastDoc", title=_("Open previous document"), device=true,}, filemanager = { category="none", event="Home", title=_("File browser"), device=true,}, dictionary_lookup = { category="none", event="ShowDictionaryLookup", title=_("Dictionary lookup"), device=true,}, wikipedia_lookup = { category="none", event="ShowWikipediaLookup", title=_("Wikipedia lookup"), device=true,}, fulltext_search = { category="none", event="ShowFulltextSearchInput", title=_("Fulltext search"), device=true,}, file_search = { category="none", event="ShowFileSearch", title=_("File search"), device=true,}, full_refresh = { category="none", event="FullRefresh", title=_("Full screen refresh"), device=true,}, night_mode = { category="none", event="ToggleNightMode", title=_("Toggle night mode"), device=true,}, set_night_mode = { category="string", event="SetNightMode", title=_("Set night mode"), device=true, args={true, false}, toggle={_("On"), _("Off")},}, suspend = { category="none", event="SuspendEvent", title=_("Suspend"), device=true,}, exit = { category="none", event="Exit", title=_("Exit KOReader"), device=true,}, restart = { category="none", event="Restart", title=_("Restart KOReader"), device=true, condition=Device:canRestart(),}, reboot = { category="none", event="Reboot", title=_("Reboot the device"), device=true, condition=Device:canReboot(),}, poweroff = { category="none", event="PowerOff", title=_("Power off"), device=true, condition=Device:canPowerOff(),}, show_menu = { category="none", event="ShowMenu", title=_("Show menu"), device=true,}, toggle_hold_corners = { category="none", event="IgnoreHoldCorners", title=_("Toggle hold corners"), device=true,}, toggle_rotation = { category="none", event="ToggleRotation", title=_("Toggle rotation"), device=true,}, wallabag_download = { category="none", event="SynchronizeWallabag", title=_("Wallabag retrieval"), device=true,}, calibre_search = { category="none", event="CalibreSearch", title=_("Search in calibre metadata"), device=true,}, calibre_browse_tags = { category="none", event="CalibreBrowseTags", title=_("Browse all calibre tags"), device=true,}, calibre_browse_series = { category="none", event="CalibreBrowseSeries", title=_("Browse all calibre series"), device=true,}, favorites = { category="arg", event="ShowColl", arg="favorites", title=_("Favorites"), device=true,}, -- filemanager settings folder_up = { category="none", event="FolderUp", title=_("Folder up"), filemanager=true}, show_plus_menu = { category="none", event="ShowPlusMenu", title=_("Show plus menu"), filemanager=true}, folder_shortcuts = { category="none", event="ShowFolderShortcutsDialog", title=_("Folder shortcuts"), filemanager=true}, -- reader settings prev_chapter = { category="none", event="GotoPrevChapter", title=_("Previous chapter"), rolling=true, paging=true,}, next_chapter = { category="none", event="GotoNextChapter", title=_("Next chapter"), rolling=true, paging=true,}, first_page = { category="none", event="GoToBeginning", title=_("First page"), rolling=true, paging=true,}, last_page = { category="none", event="GoToEnd", title=_("Last page"), rolling=true, paging=true,}, prev_bookmark = { category="none", event="GotoPreviousBookmarkFromPage", title=_("Previous bookmark"), rolling=true, paging=true,}, next_bookmark = { category="none", event="GotoNextBookmarkFromPage", title=_("Next bookmark"), rolling=true, paging=true,}, go_to = { category="none", event="ShowGotoDialog", title=_("Go to"), rolling=true, paging=true,}, skim = { category="none", event="ShowSkimtoDialog", title=_("Skim"), rolling=true, paging=true,}, back = { category="none", event="Back", title=_("Back"), rolling=true, paging=true,}, previous_location = { category="arg", event="GoBackLink", arg=true, title=_("Back to previous location"), rolling=true, paging=true,}, latest_bookmark = { category="none", event="GoToLatestBookmark", title=_("Go to latest bookmark"), rolling=true, paging=true,}, follow_nearest_link = { category="arg", event="GoToPageLink", arg={pos={x=0,y=0}}, title=_("Follow nearest link"), rolling=true, paging=true,}, follow_nearest_internal_link = { category="arg", event="GoToInternalPageLink", arg={pos={x=0,y=0}}, title=_("Follow nearest internal link"), rolling=true, paging=true,}, clear_location_history = { category="arg", event="ClearLocationStack", arg=true, title=_("Clear location history"), rolling=true, paging=true,}, toc = { category="none", event="ShowToc", title=_("Table of contents"), rolling=true, paging=true,}, bookmarks = { category="none", event="ShowBookmark", title=_("Bookmarks"), rolling=true, paging=true,}, book_statistics = { category="none", event="ShowBookStats", title=_("Book statistics"), rolling=true, paging=true,}, book_status = { category="none", event="ShowBookStatus", title=_("Book status"), rolling=true, paging=true,}, book_info = { category="none", event="ShowBookInfo", title=_("Book information"), rolling=true, paging=true,}, book_description = { category="none", event="ShowBookDescription", title=_("Book description"), rolling=true, paging=true,}, book_cover = { category="none", event="ShowBookCover", title=_("Book cover"), rolling=true, paging=true,}, show_config_menu = { category="none", event="ShowConfigMenu", title=_("Show bottom menu"), rolling=true, paging=true,}, toggle_bookmark = { category="none", event="ToggleBookmark", title=_("Toggle bookmark"), rolling=true, paging=true,}, toggle_inverse_reading_order = { category="none", event="ToggleReadingOrder", title=_("Toggle page turn direction"), rolling=true, paging=true,}, cycle_highlight_action = { category="none", event="CycleHighlightAction", title=_("Cycle highlight action"), rolling=true, paging=true,}, cycle_highlight_style = { category="none", event="CycleHighlightStyle", title=_("Cycle highlight style"), rolling=true, paging=true,}, kosync_push_progress = { category="none", event="KOSyncPushProgress", title=_("Push progress from this device"), rolling=true, paging=true,}, kosync_pull_progress = { category="none", event="KOSyncPullProgress", title=_("Pull progress from other devices"), rolling=true, paging=true,}, page_jmp = { category="absolutenumber", event="GotoViewRel", min=-100, max=100, title=_("Go X pages"), rolling=true, paging=true,}, -- rolling reader settings increase_font = { category="incrementalnumber", event="IncreaseFontSize", min=1, max=255, title=_("Increase font size"), rolling=true,}, decrease_font = { category="incrementalnumber", event="DecreaseFontSize", min=1, max=255, title=_("Decrease font size"), rolling=true,}, -- paging reader settings toggle_page_flipping = { category="none", event="TogglePageFlipping", title=_("Toggle page flipping"), paging=true,}, toggle_reflow = { category="none", event="ToggleReflow", title=_("Toggle reflow"), paging=true,}, zoom = { category="string", event="SetZoomMode", title=_("Zoom to"), args={"contentwidth", "contentheight", "pagewidth", "pageheight", "column", "content", "page"}, toggle={"content width", "content height", "page width", "page height", "column", "content", "page"}, paging=true,}, -- parsed from CreOptions -- the rest of the table elements are built from their counterparts in CreOptions rotation_mode = {category="string", device=true}, visible_pages = {category="string", rolling=true}, h_page_margins = {category="string", rolling=true}, sync_t_b_page_margins = {category="string", rolling=true}, t_page_margin = {category="absolutenumber", rolling=true}, b_page_margin = {category="absolutenumber", rolling=true}, view_mode = {category="string", rolling=true}, block_rendering_mode = {category="string", rolling=true}, render_dpi = {category="string", rolling=true}, line_spacing = {category="absolutenumber", rolling=true}, font_size = {category="absolutenumber", title="Font Size", rolling=true}, font_weight = {category="string", rolling=true}, --font_gamma = {category="string", rolling=true}, font_hinting = {category="string", rolling=true}, font_kerning = {category="string", rolling=true}, status_line = {category="string", rolling=true}, embedded_css = {category="string", rolling=true}, embedded_fonts = {category="string", rolling=true}, smooth_scaling = {category="string", rolling=true}, nightmode_images = {category="string", rolling=true}, } -- array for item order in menu local dispatcher_menu_order = { -- device "reading_progress", "history", "open_previous_document", "favorites", "filemanager", "stats_calendar_view", "dictionary_lookup", "wikipedia_lookup", "fulltext_search", "file_search", "full_refresh", "night_mode", "set_night_mode", "suspend", "exit", "restart", "reboot", "poweroff", "show_menu", "show_config_menu", "show_frontlight_dialog", "toggle_frontlight", "increase_frontlight", "decrease_frontlight", "increase_frontlight_warmth", "decrease_frontlight_warmth", "toggle_hold_corners", "toggle_gsensor", "toggle_rotation", "wifi_on", "wifi_off", "toggle_wifi", "wallabag_download", "calibre_search", "calibre_browse_tags", "calibre_browse_series", "rotation_mode", -- filemanager "folder_up", "show_plus_menu", "folder_shortcuts", -- reader "page_jmp", "prev_chapter", "next_chapter", "first_page", "last_page", "prev_bookmark", "next_bookmark", "go_to", "skim", "back", "previous_location", "latest_bookmark", "follow_nearest_link", "follow_nearest_internal_link", "clear_location_history", "toc", "bookmarks", "book_statistics", "book_status", "book_info", "book_description", "book_cover", "increase_font", "decrease_font", "font_size", --"font_gamma", "font_weight", "font_hinting", "font_kerning", "toggle_bookmark", "toggle_page_flipping", "toggle_reflow", "toggle_inverse_reading_order", "zoom", "cycle_highlight_action", "cycle_highlight_style", "kosync_push_progress", "kosync_pull_progress", "visible_pages", "h_page_margins", "sync_t_b_page_margins", "t_page_margin", "b_page_margin", "view_mode", "block_rendering_mode", "render_dpi", "line_spacing", "status_line", "embedded_css", "embedded_fonts", "smooth_scaling", "nightmode_images", } --[[-- add settings from CreOptions / KoptOptions --]]-- function Dispatcher:init() local parseoptions = function(base, i) for y=1,#base[i].options do local option = base[i].options[y] if settingsList[option.name] ~= nil then if settingsList[option.name].event == nil then settingsList[option.name].event = option.event end if settingsList[option.name].title == nil then settingsList[option.name].title = option.name_text end if settingsList[option.name].category == "string" then if settingsList[option.name].toggle == nil then settingsList[option.name].toggle = option.toggle or option.labels if settingsList[option.name].toggle == nil then settingsList[option.name].toggle = {} for z=1,#option.values do if type(option.values[z]) == "table" then settingsList[option.name].toggle[z] = option.values[z][1] end end end end if settingsList[option.name].args == nil then settingsList[option.name].args = option.args or option.values end elseif settingsList[option.name].category == "absolutenumber" then if settingsList[option.name].min == nil then settingsList[option.name].min = option.args[1] end if settingsList[option.name].max == nil then settingsList[option.name].max = option.args[#option.args] end if settingsList[option.name].default == nil then settingsList[option.name].default = option.default_value end end end end end for i=1,#CreOptions do parseoptions(CreOptions, i) end Dispatcher.initialized = true end function Dispatcher.addItem(caller, menu, location, settings, section) for _, k in ipairs(dispatcher_menu_order) do if settingsList[k][section] == true and (settingsList[k].condition == nil or settingsList[k].condition) then if settingsList[k].category == "none" or settingsList[k].category == "arg" then table.insert(menu, { text = settingsList[k].title, checked_func = function() return caller[location][settings] ~= nil and caller[location][settings][k] ~= nil end, callback = function(touchmenu_instance) if caller[location][settings] ~= nil and caller[location][settings][k] then caller[location][settings][k] = nil else caller[location][settings][k] = true end if touchmenu_instance then touchmenu_instance:updateItems() end end, separator = settingsList[k].separator, }) elseif settingsList[k].category == "absolutenumber" then table.insert(menu, { text_func = function() return T(settingsList[k].title, caller[location][settings][k] or "") end, checked_func = function() return caller[location][settings] ~= nil and caller[location][settings][k] ~= nil end, callback = function(touchmenu_instance) local SpinWidget = require("ui/widget/spinwidget") local items = SpinWidget:new{ width = Screen:getWidth() * 0.6, value = caller[location][settings][k] or settingsList[k].default or 0, value_min = settingsList[k].min, value_step = 1, value_hold_step = 2, value_max = settingsList[k].max, default_value = 0, title_text = T(settingsList[k].title, caller[location][settings][k] or ""), callback = function(spin) caller[location][settings][k] = spin.value if touchmenu_instance then touchmenu_instance:updateItems() end end } UIManager:show(items) end, hold_callback = function(touchmenu_instance) caller[location][settings][k] = nil if touchmenu_instance then touchmenu_instance:updateItems() end end, separator = settingsList[k].separator, }) elseif settingsList[k].category == "incrementalnumber" then table.insert(menu, { text_func = function() return T(settingsList[k].title, caller[location][settings][k] or "") end, checked_func = function() return caller[location][settings] ~= nil and caller[location][settings][k] ~= nil end, callback = function(touchmenu_instance) local _ = require("gettext") local SpinWidget = require("ui/widget/spinwidget") local items = SpinWidget:new{ width = Screen:getWidth() * 0.6, value = caller[location][settings][k] or 0, value_min = settingsList[k].min, value_step = 1, value_hold_step = 2, value_max = settingsList[k].max, default_value = 0, title_text = T(settingsList[k].title, caller[location][settings][k] or ""), info_text = _([[If called by a gesture the amount of the gesture will be used]]), callback = function(spin) caller[location][settings][k] = spin.value if touchmenu_instance then touchmenu_instance:updateItems() end end } UIManager:show(items) end, hold_callback = function(touchmenu_instance) caller[location][settings][k] = nil if touchmenu_instance then touchmenu_instance:updateItems() end end, separator = settingsList[k].separator, }) elseif settingsList[k].category == "string" then local sub_item_table = {} for i=1,#settingsList[k].args do table.insert(sub_item_table, { text = tostring(settingsList[k].toggle[i]), checked_func = function() return caller[location][settings] ~= nil and caller[location][settings][k] ~= nil and caller[location][settings][k] == settingsList[k].args[i] end, callback = function() caller[location][settings][k] = settingsList[k].args[i] end, }) end table.insert(menu, { text_func = function() return T(settingsList[k].title, caller[location][settings][k]) end, checked_func = function() return caller[location][settings] ~= nil and caller[location][settings][k] ~= nil end, sub_item_table = sub_item_table, keep_menu_open = true, hold_callback = function(touchmenu_instance) caller[location][settings][k] = nil if touchmenu_instance then touchmenu_instance:updateItems() end end, separator = settingsList[k].separator, }) end end end end --[[-- Add a submenu to edit which items are dispatched arguments are: 1) the caller 2) the table representing the submenu (can be empty) 3) the name of the parent of the settings table (must be a child of self) 4) the name of the settings table example usage: Dispatcher.addSubMenu(self, sub_items, "profiles", "profile1") Must be executed in the context of the caller to add items to the callers menu. therefore declared as Dispatcher.addSubMenu(caller, menu, location, settings) but should be called as Dispatcher.addSubMenu(self, menu, location, settings) --]]-- function Dispatcher.addSubMenu(caller, menu, location, settings) if not Dispatcher.initialized then Dispatcher:init() end table.insert(menu, { text = _("None"), separator = true, checked_func = function() return next(caller[location][settings]) == nil end, callback = function(touchmenu_instance) caller[location][settings] = {} if touchmenu_instance then touchmenu_instance:updateItems() end end, }) local section_list = { {"device", _("Device")}, {"filemanager", _("File browser")}, {"rolling", _("Reflowable documents (epub, fb2, txt…)")}, {"paging", _("Fixed layout documents (pdf, djvu, pics…)")}, } for _, section in ipairs(section_list) do local submenu = {} -- pass caller's context Dispatcher.addItem(caller, submenu, location, settings, section[1]) table.insert(menu, { text = section[2], sub_item_table = submenu, }) end end function Dispatcher:execute(settings, gesture) for k, v in pairs(settings) do if settingsList[k].conditions == nil or settingsList[k].conditions == true then if settingsList[k].category == "none" then self.ui:handleEvent(Event:new(settingsList[k].event)) end if settingsList[k].category == "absolutenumber" or settingsList[k].category == "string" then self.ui:handleEvent(Event:new(settingsList[k].event, v)) end -- the event can accept a gesture object or an argument if settingsList[k].category == "arg" then local arg = gesture or settingsList[k].arg self.ui:handleEvent(Event:new(settingsList[k].event, arg)) end -- the event can accept a gesture object or a number if settingsList[k].category == "incrementalnumber" then local arg = gesture or v self.ui:handleEvent(Event:new(settingsList[k].event, arg)) end end end end return Dispatcher