]> git.madduck.net Git - etc/awesome.git/commitdiff

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Merge pull request #377 from sim590/menu-iterator
authorLuca CPZ <1777696+lcpz@users.noreply.github.com>
Sat, 17 Feb 2018 11:19:53 +0000 (12:19 +0100)
committerGitHub <noreply@github.com>
Sat, 17 Feb 2018 11:19:53 +0000 (12:19 +0100)
menu_iterator: naughty.notify based menu utility

helpers.lua
util/menu_iterator.lua [new file with mode: 0644]

index 6073dddfc435b1b79c5ab81b65912ca8e7e8684f..313579f8a3d28368b4918faf5e0a32f4b9ca9e37 100644 (file)
@@ -179,6 +179,29 @@ function helpers.spairs(t)
     end
 end
 
+-- create trivial partition of a set. The trivial partition set is the simplest
+-- partition of a set. For e.g., the trivial partition set of {a, b, c}, is
+-- simply {{a}, {b}, {c}}.
+function helpers.trivial_partition_set(set)
+    local ss = {}
+    for _,e in pairs(set) do
+        ss[#ss+1] = {e}
+    end
+    return ss
+end
+
+-- creates the powerset of a given set
+function helpers.powerset(s)
+    if not s then return {} end
+    local t = {{}}
+    for i = 1, #s do
+        for j = 1, #t do
+            t[#t+1] = {s[i],unpack(t[j])}
+        end
+    end
+    return t
+end
+
 -- }}}
 
 return helpers
diff --git a/util/menu_iterator.lua b/util/menu_iterator.lua
new file mode 100644 (file)
index 0000000..913482a
--- /dev/null
@@ -0,0 +1,139 @@
+--[[
+
+     Licensed under GNU General Public License v2
+      * (c) 2017, Simon Désaulniers <sim.desaulniers@gmail.com>
+      * (c) 2017, Uli Schlachter
+      * (c) 2017, Jeferson Siqueira <jefersonlsiq@gmail.com>
+
+--]]
+
+-- Menu iterator using naughty.notify
+
+local naughty = require("naughty")
+local util = require("lain.util")
+
+local state = { cid = nil }
+
+local function naughty_destroy_callback(reason)
+    if reason == naughty.notificationClosedReason.expired or
+        reason == naughty.notificationClosedReason.dismissedByUser then
+        local actions = state.index and state.menu[state.index - 1][2]
+        if actions then
+            for _,action in pairs(actions) do
+                -- don't try to call nil callbacks
+                if action then action() end
+            end
+            state.index = nil
+        end
+    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
+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
+
+    -- Build the list of choices
+    if not state.index then
+        state.menu = menu
+        state.index = 1
+    end
+
+    -- Select one and display the appropriate notification
+    local label, action
+    local next  = state.menu[state.index]
+    state.index = state.index + 1
+
+    if not next then
+        label = "Cancel"
+        state.index = nil
+    else
+        label, _ = unpack(next)
+    end
+    state.cid = naughty.notify({
+        text = label,
+        icon = icon,
+        timeout = timeout,
+        screen = mouse.screen,
+        replaces_id = state.cid,
+        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)
+--
+-- The following describes the function arguments:
+-- * 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).
+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 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]}})
+    end
+
+    local m = {}
+    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
+                    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
+                    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.)
+            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 }
+        end
+    end
+
+    return m
+end
+
+return {
+    iterate = iterate,
+    menu    = menu
+}