--]]
--- Menu iterator using naughty.notify
+-- Menu iterator with Naughty notifications
+-- lain.util.menu_iterator
local naughty = require("naughty")
-local util = require("lain.util")
+local util = require("lain.util")
+local atable = require("awful.util").table
+local assert = assert
+local pairs = pairs
+local tconcat = table.concat
+local unpack = unpack
local state = { cid = nil }
local function naughty_destroy_callback(reason)
- if reason == naughty.notificationClosedReason.expired or
- reason == naughty.notificationClosedReason.dismissedByUser then
+ local closed = naughty.notificationClosedReason
+ if reason == closed.expired or reason == closed.dismissedByUser then
local actions = state.index and state.menu[state.index - 1][2]
if actions then
for _,action in pairs(actions) do
end
end
--- Iterates over a list of pairs {label, {callbacks}}. After timeout, the last
--- visited choice associated callbacks are executed.
--- * menu: a list of pairs {label, {callbacks}
--- * timeout: time to wait before confirming menu selection
--- * icon: icon to display left to the choiced label
+-- Iterates over a menu.
+-- After the timeout, callbacks associated to the last visited choice are
+-- executed. Inputs:
+-- * menu: a list of {label, {callbacks}} pairs
+-- * timeout: time to wait before confirming the menu selection
+-- * icon: icon to display in the notification of the chosen label
local function iterate(menu, timeout, icon)
- timeout = timeout or 4 -- default timeout for each menu entry
- icon = icon or nil -- icon to display on the menu
+ local timeout = timeout or 4 -- default timeout for each menu entry
+ local icon = icon or nil -- icon to display on the menu
-- Build the list of choices
if not state.index then
end
-- Select one and display the appropriate notification
- local label, action
- local next = state.menu[state.index]
+ local label
+ local next = state.menu[state.index]
state.index = state.index + 1
if not next then
else
label, _ = unpack(next)
end
+
state.cid = naughty.notify({
- text = label,
- icon = icon,
- timeout = timeout,
- screen = mouse.screen,
+ text = label,
+ icon = icon,
+ timeout = timeout,
+ screen = mouse.screen,
replaces_id = state.cid,
- destroy = naughty_destroy_callback
+ destroy = naughty_destroy_callback
}).id
end
--- Generates a menu compatible with the iterate function argument and suitable
--- for the following cases:
--- * all possible choices individually.
--- * all possible choices are all the possible subsets of the set of individual
--- choices (the powerset)
+-- Generates a menu compatible with the first argument of `iterate` function and
+-- suitable for the following cases:
+-- * all possible choices individually (partition of singletons);
+-- * all possible subsets of the set of choices (powerset).
--
--- The following describes the function arguments:
+-- Inputs:
-- * args: an array containing the following members:
--- * choices: the list of choices from which to generate the menu
--- * name: the displayed name of the menu (in the form "name: choices")
--- * selected_cb: the callback to execute for each selected choice. Takes
--- the choice as a string argument. The function
--- menu_iterator.naughty_destroy_callback will handle nil
--- callbacks. It is then fine to pass nil callbacks.
--- * rejected_cb: the callback to execute for each rejected choice (in the
--- set of possible choices, but not selected). Takes the
--- choice as a string argument. The function
--- menu_iterator.naughty_destroy_callback will handle nil
--- callbacks. It is then fine to pass nil callbacks.
--- * extra_choices: an array of pairs { choice_text, cb } for extra choices to
--- be added to the menu. The function
--- menu_iterator.naughty_destroy_callback will handle nil
--- callbacks. It is then fine to pass nil callbacks.
--- * combination: the combination of choice to generate. Possible choices
--- are "powerset" and "single" (the default).
+-- * choices: Array of choices (string) on which the menu will be
+-- generated.
+-- * name: Displayed name of the menu (in the form "name: choices").
+-- * selected_cb: Callback to execute for each selected choice. Takes
+-- the choice as a string argument. Can be `nil` (no action
+-- to execute).
+-- * rejected_cb: Callback to execute for each rejected choice (possible
+-- choices which are not selected). Takes the choice as a
+-- string argument. Can be `nil` (no action to execute).
+-- * extra_choices: An array of extra { choice_str, callback_fun } pairs to be
+-- added to the menu. Each callback_fun can be `nil`.
+-- * combination: The combination of choices to generate. Possible values:
+-- "powerset" and "single" (default).
+-- Output:
+-- * m: menu to be iterated over.
local function menu(args)
- local choices = assert(args.choices or args[1])
- local name = assert(args.name or args[2])
- local selected_cb = args.selected_cb
- local rejected_cb = args.rejected_cb
+ local choices = assert(args.choices or args[1])
+ local name = assert(args.name or args[2])
+ local selected_cb = args.selected_cb
+ local rejected_cb = args.rejected_cb
local extra_choices = args.extra_choices or {}
local ch_combinations = args.combination == "powerset" and helpers.powerset(choices) or helpers.trivial_partition_set(choices)
+
for _,c in pairs(extra_choices) do
- ch_combinations = awful.util.table.join(ch_combinations, {{c[1]}})
+ ch_combinations = atable.join(ch_combinations, {{c[1]}})
end
- local m = {}
+ local m = {} -- the menu
+
for _,c in pairs(ch_combinations) do
if #c > 0 then
local cbs = {}
+
-- selected choices
for _,ch in pairs(c) do
- if awful.util.table.hasitem(choices, ch) then
+ if atable.hasitem(choices, ch) then
cbs[#cbs + 1] = selected_cb and function() selected_cb(ch) end or nil
end
end
-- rejected choices
for _,ch in pairs(choices) do
- if not awful.util.table.hasitem(c, ch) and awful.util.table.hasitem(choices, ch) then
+ if not atable.hasitem(c, ch) and atable.hasitem(choices, ch) then
cbs[#cbs + 1] = rejected_cb and function() rejected_cb(ch) end or nil
end
end
- -- add user extra choices (like the choice "None" for e.g.)
+ -- add user extra choices (like the choice "None" for example)
for _,x in pairs(extra_choices) do
if x[1] == c[1] then
cbs[#cbs + 1] = x[2]
end
end
- m[#m + 1] = { name .. ": " .. table.concat(c, " + "), cbs }
+ m[#m + 1] = { name .. ": " .. tconcat(c, " + "), cbs }
end
end
return m
end
-return {
- iterate = iterate,
- menu = menu
-}
+return { iterate = iterate, menu = menu }