Advertisement
constantin-net

menu_mod

Dec 28th, 2024
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 24.69 KB | None | 0 0
  1. --------------------------------------------------------------------------------
  2. --- A menu for awful :: MOD (add shape arg, item shape, icon margins)
  3. --
  4. -- @author Damien Leone <damien.leone@gmail.com>
  5. -- @author Julien Danjou <julien@danjou.info>
  6. -- @author dodo
  7. -- @copyright 2008, 2011 Damien Leone, Julien Danjou, dodo
  8. -- @module awful.menu
  9. --------------------------------------------------------------------------------
  10.  
  11. local wibox = require("wibox")
  12. local gears = require("gears")
  13. local button = require("awful.button")
  14. local gstring = require("gears.string")
  15. local gtable = require("gears.table")
  16. local spawn = require("awful.spawn")
  17. local tags = require("awful.tag")
  18. local keygrabber = require("awful.keygrabber")
  19. local client_iterate = require("awful.client").iterate
  20. local beautiful = require("beautiful")
  21. local dpi = require("beautiful").xresources.apply_dpi
  22. local object = require("gears.object")
  23. local surface = require("gears.surface")
  24. local protected_call = require("gears.protected_call")
  25. local cairo = require("lgi").cairo
  26. local setmetatable = setmetatable
  27. local tonumber = tonumber
  28. local string = string
  29. local ipairs = ipairs
  30. local pairs = pairs
  31. local print = print
  32. local table = table
  33. local type = type
  34. local math = math
  35. local capi = {
  36.     screen = screen,
  37.     mouse = mouse,
  38.     client = client }
  39. local screen = require("awful.screen")
  40.  
  41.  
  42. local menu = { mt = {} }
  43.  
  44.  
  45. local table_update = function (t, set)
  46.     for k, v in pairs(set) do
  47.         t[k] = v
  48.     end
  49.     return t
  50. end
  51.  
  52. --- The icon used for sub-menus.
  53. -- @beautiful beautiful.menu_submenu_icon
  54.  
  55. --- The menu text font.
  56. -- @beautiful beautiful.menu_font
  57. -- @param string
  58. -- @see string
  59.  
  60. --- The item height.
  61. -- @beautiful beautiful.menu_height
  62. -- @tparam[opt=16] number menu_height
  63.  
  64. --- The default menu width.
  65. -- @beautiful beautiful.menu_width
  66. -- @tparam[opt=100] number menu_width
  67.  
  68. --- The menu item border color.
  69. -- @beautiful beautiful.menu_border_color
  70. -- @tparam[opt=0] number menu_border_color
  71.  
  72. --- The menu item border width.
  73. -- @beautiful beautiful.menu_border_width
  74. -- @tparam[opt=0] number menu_border_width
  75.  
  76. --- The default focused item foreground (text) color.
  77. -- @beautiful beautiful.menu_fg_focus
  78. -- @param color
  79. -- @see gears.color
  80.  
  81. --- The default focused item background color.
  82. -- @beautiful beautiful.menu_bg_focus
  83. -- @param color
  84. -- @see gears.color
  85.  
  86. --- The default foreground (text) color.
  87. -- @beautiful beautiful.menu_fg_normal
  88. -- @param color
  89. -- @see gears.color
  90.  
  91. --- The default background color.
  92. -- @beautiful beautiful.menu_bg_normal
  93. -- @param color
  94. -- @see gears.color
  95.  
  96. --- The default sub-menu indicator if no menu_submenu_icon is provided.
  97. -- @beautiful beautiful.menu_submenu
  98. -- @tparam[opt="▶"] string menu_submenu The sub-menu text.
  99. -- @see beautiful.menu_submenu_icon
  100.  
  101. --- Key bindings for menu navigation.
  102. -- Keys are: up, down, exec, enter, back, close. Value are table with a list of valid
  103. -- keys for the action, i.e. menu_keys.up =  { "j", "k" } will bind 'j' and 'k'
  104. -- key to up action. This is common to all created menu.
  105. -- @class table
  106. -- @name menu_keys
  107. menu.menu_keys = { up = { "Up", "k" },
  108.               down = { "Down", "j" },
  109.               back = { "Left", "h" },
  110.               exec = { "Return" },
  111.               enter = { "Right", "l" },
  112.               close = { "Escape" } }
  113.  
  114.  
  115. local function load_theme(a, b)
  116.     a = a or {}
  117.     b = b or {}
  118.     local ret = {}
  119.     local fallback = beautiful.get()
  120.     if a.reset      then b = fallback end
  121.     if a == "reset" then a = fallback end
  122.     ret.border = a.border_color or b.menu_border_color or b.border_normal or
  123.                  fallback.menu_border_color or fallback.border_normal
  124.     ret.border_width= a.border_width or b.menu_border_width or b.border_width or
  125.                       fallback.menu_border_width or fallback.border_width or dpi(0)
  126.     ret.fg_focus = a.fg_focus or b.menu_fg_focus or b.fg_focus or
  127.                    fallback.menu_fg_focus or fallback.fg_focus
  128.     ret.bg_focus = a.bg_focus or b.menu_bg_focus or b.bg_focus or
  129.                    fallback.menu_bg_focus or fallback.bg_focus
  130.     ret.fg_normal = a.fg_normal or b.menu_fg_normal or b.fg_normal or
  131.                     fallback.menu_fg_normal or fallback.fg_normal
  132.     ret.bg_normal = a.bg_normal or b.menu_bg_normal or b.bg_normal or
  133.                     fallback.menu_bg_normal or fallback.bg_normal
  134.     ret.submenu_icon= a.submenu_icon or b.menu_submenu_icon or b.submenu_icon or
  135.                       fallback.menu_submenu_icon or fallback.submenu_icon
  136.     ret.submenu = a.submenu or b.menu_submenu or b.submenu or
  137.                       fallback.menu_submenu or fallback.submenu or "▶"
  138.     ret.height = a.height or b.menu_height or b.height or
  139.                  fallback.menu_height or dpi(16)
  140.     ret.width = a.width or b.menu_width or b.width or
  141.                 fallback.menu_width or dpi(100)
  142.     ret.shape = a.shape or b.menu_shape or b.shape or -- mod
  143.                 fallback.menu_shape or gears.shape.rectangular
  144.     ret.font = a.font or b.font or fallback.menu_font or fallback.font
  145.     for _, prop in ipairs({"width", "height", "menu_width"}) do
  146.         if type(ret[prop]) ~= "number" then ret[prop] = tonumber(ret[prop]) end
  147.     end
  148.     return ret
  149. end
  150.  
  151.  
  152. local function item_position(_menu, child)
  153.     local a, b = "height", "width"
  154.     local dir = _menu.layout.dir or "y"
  155.     if dir == "x" then  a, b = b, a  end
  156.  
  157.     local in_dir, other = 0, _menu[b]
  158.     local num = gtable.hasitem(_menu.child, child)
  159.     if num then
  160.         for i = 0, num - 1 do
  161.             local item = _menu.items[i]
  162.             if item then
  163.                 other = math.max(other, item[b])
  164.                 in_dir = in_dir + item[a]
  165.             end
  166.         end
  167.     end
  168.     local w, h = other, in_dir
  169.     if dir == "x" then  w, h = h, w  end
  170.     return w, h
  171. end
  172.  
  173.  
  174. local function set_coords(_menu, s, m_coords)
  175.     local s_geometry = s.workarea
  176.     local screen_w = s_geometry.x + s_geometry.width
  177.     local screen_h = s_geometry.y + s_geometry.height
  178.  
  179.     _menu.width = _menu.wibox.width
  180.     _menu.height = _menu.wibox.height
  181.  
  182.     _menu.x = _menu.wibox.x
  183.     _menu.y = _menu.wibox.y
  184.  
  185.     if _menu.parent then
  186.         local w, h = item_position(_menu.parent, _menu)
  187.         w = w + _menu.parent.theme.border_width
  188.  
  189.         _menu.y = _menu.parent.y + h + _menu.height > screen_h and
  190.                  screen_h - _menu.height or _menu.parent.y + h
  191.         _menu.x = _menu.parent.x + w + _menu.width > screen_w and
  192.                  _menu.parent.x - _menu.width or _menu.parent.x + w
  193.     else
  194.         if m_coords == nil then
  195.             m_coords = capi.mouse.coords()
  196.             m_coords.x = m_coords.x + 1
  197.             m_coords.y = m_coords.y + 1
  198.         end
  199.         _menu.y = m_coords.y < s_geometry.y and s_geometry.y or m_coords.y
  200.         _menu.x = m_coords.x < s_geometry.x and s_geometry.x or m_coords.x
  201.  
  202.         _menu.y = _menu.y + _menu.height > screen_h and
  203.                  screen_h - _menu.height or _menu.y
  204.         _menu.x = _menu.x + _menu.width  > screen_w and
  205.                  screen_w - _menu.width  or _menu.x
  206.     end
  207.  
  208.     _menu.wibox.x = _menu.x
  209.     _menu.wibox.y = _menu.y
  210. end
  211.  
  212.  
  213. local function set_size(_menu)
  214.     local in_dir, other, a, b = 0, 0, "height", "width"
  215.     local dir = _menu.layout.dir or "y"
  216.     if dir == "x" then  a, b = b, a  end
  217.     for _, item in ipairs(_menu.items) do
  218.         other = math.max(other, item[b])
  219.         in_dir = in_dir + item[a]
  220.     end
  221.     _menu[a], _menu[b] = in_dir, other
  222.     if in_dir > 0 and other > 0 then
  223.         _menu.wibox[a] = in_dir
  224.         _menu.wibox[b] = other
  225.         return true
  226.     end
  227.     return false
  228. end
  229.  
  230.  
  231. local function check_access_key(_menu, key)
  232.    for i, item in ipairs(_menu.items) do
  233.       if item.akey == key then
  234.             _menu:item_enter(i)
  235.             _menu:exec(i, { exec = true })
  236.             return
  237.       end
  238.    end
  239.    if _menu.parent then
  240.       check_access_key(_menu.parent, key)
  241.    end
  242. end
  243.  
  244.  
  245. local function grabber(_menu, _, key, event)
  246.     if event ~= "press" then return end
  247.  
  248.     local sel = _menu.sel or 0
  249.     if gtable.hasitem(menu.menu_keys.up, key) then
  250.         local sel_new = sel-1 < 1 and #_menu.items or sel-1
  251.         _menu:item_enter(sel_new)
  252.     elseif gtable.hasitem(menu.menu_keys.down, key) then
  253.         local sel_new = sel+1 > #_menu.items and 1 or sel+1
  254.         _menu:item_enter(sel_new)
  255.     elseif sel > 0 and gtable.hasitem(menu.menu_keys.enter, key) then
  256.         _menu:exec(sel)
  257.     elseif sel > 0 and gtable.hasitem(menu.menu_keys.exec, key) then
  258.         _menu:exec(sel, { exec = true })
  259.     elseif gtable.hasitem(menu.menu_keys.back, key) then
  260.         _menu:hide()
  261.     elseif gtable.hasitem(menu.menu_keys.close, key) then
  262.         menu.get_root(_menu):hide()
  263.     else
  264.         check_access_key(_menu, key)
  265.     end
  266. end
  267.  
  268.  
  269. function menu:exec(num, opts)
  270.     opts = opts or {}
  271.     local item = self.items[num]
  272.     if not item then return end
  273.     local cmd = item.cmd
  274.     if type(cmd) == "table" then
  275.         local action = cmd.cmd
  276.         if #cmd == 0 then
  277.             if opts.exec and action and type(action) == "function" then
  278.                 action()
  279.             end
  280.             return
  281.         end
  282.         if not self.child[num] then
  283.             self.child[num] = menu.new(cmd, self)
  284.         end
  285.         local can_invoke_action = opts.exec and
  286.             action and type(action) == "function" and
  287.             (not opts.mouse or (opts.mouse and (self.auto_expand or
  288.             (self.active_child == self.child[num] and
  289.             self.active_child.wibox.visible))))
  290.         if can_invoke_action then
  291.             local visible = action(self.child[num], item)
  292.             if not visible then
  293.                 menu.get_root(self):hide()
  294.                 return
  295.             else
  296.                 self.child[num]:update()
  297.             end
  298.         end
  299.         if self.active_child and self.active_child ~= self.child[num] then
  300.             self.active_child:hide()
  301.         end
  302.         self.active_child = self.child[num]
  303.         if not self.active_child.wibox.visible then
  304.             self.active_child:show()
  305.         end
  306.     elseif type(cmd) == "string" then
  307.         menu.get_root(self):hide()
  308.         spawn(cmd)
  309.     elseif type(cmd) == "function" then
  310.         local visible, action = cmd(item, self)
  311.         if not visible then
  312.             menu.get_root(self):hide()
  313.         else
  314.             self:update()
  315.             if self.items[num] then
  316.                 self:item_enter(num, opts)
  317.             end
  318.         end
  319.         if action and type(action) == "function" then
  320.             action()
  321.         end
  322.     end
  323. end
  324.  
  325. function menu:item_enter(num, opts)
  326.     opts = opts or {}
  327.     local item = self.items[num]
  328.     if num == nil or self.sel == num or not item then
  329.         return
  330.     elseif self.sel then
  331.         self:item_leave(self.sel)
  332.     end
  333.     --print("sel", num, menu.sel, item.theme.bg_focus)
  334.     item._background:set_fg(item.theme.fg_focus)
  335.     item._background:set_bg(item.theme.bg_focus)
  336.     self.sel = num
  337.  
  338.     if self.auto_expand and opts.hover then
  339.         if self.active_child then
  340.             self.active_child:hide()
  341.             self.active_child = nil
  342.         end
  343.  
  344.         if type(item.cmd) == "table" then
  345.             self:exec(num, opts)
  346.         end
  347.     end
  348. end
  349.  
  350.  
  351. function menu:item_leave(num)
  352.     --print("leave", num)
  353.     local item = self.items[num]
  354.     if item then
  355.         item._background:set_fg(item.theme.fg_normal)
  356.         item._background:set_bg(item.theme.bg_normal)
  357.     end
  358. end
  359.  
  360.  
  361. --- Show a menu.
  362. -- @param args The arguments
  363. -- @param args.coords Menu position defaulting to mouse.coords()
  364. function menu:show(args)
  365.     args = args or {}
  366.     local coords = args.coords or nil
  367.     local s = capi.screen[screen.focused()]
  368.  
  369.     if not set_size(self) then return end
  370.     set_coords(self, s, coords)
  371.  
  372.     keygrabber.run(self._keygrabber)
  373.     self.wibox.visible = true
  374. end
  375.  
  376. --- Hide a menu popup.
  377. function menu:hide()
  378.     -- Remove items from screen
  379.     for i = 1, #self.items do
  380.         self:item_leave(i)
  381.     end
  382.     if self.active_child then
  383.         self.active_child:hide()
  384.         self.active_child = nil
  385.     end
  386.     self.sel = nil
  387.  
  388.     keygrabber.stop(self._keygrabber)
  389.     self.wibox.visible = false
  390. end
  391.  
  392. --- Toggle menu visibility.
  393. -- @param args The arguments
  394. -- @param args.coords Menu position {x,y}
  395. function menu:toggle(args)
  396.     if self.wibox.visible then
  397.         self:hide()
  398.     else
  399.         self:show(args)
  400.     end
  401. end
  402.  
  403. --- Update menu content
  404. function menu:update()
  405.     if self.wibox.visible then
  406.         self:show({ coords = { x = self.x, y = self.y } })
  407.     end
  408. end
  409.  
  410.  
  411. --- Get the elder parent so for example when you kill
  412. -- it, it will destroy the whole family.
  413. function menu:get_root()
  414.     return self.parent and menu.get_root(self.parent) or self
  415. end
  416.  
  417. --- Add a new menu entry.
  418. -- args.* params needed for the menu entry constructor.
  419. -- @param args The item params
  420. -- @param args.new (Default: awful.menu.entry) The menu entry constructor.
  421. -- @param[opt] args.theme The menu entry theme.
  422. -- @param[opt] index The index where the new entry will inserted.
  423. function menu:add(args, index)
  424.     if not args then return end
  425.     local theme = load_theme(args.theme or {}, self.theme)
  426.     args.theme = theme
  427.     args.new = args.new or menu.entry
  428.     local item = protected_call(args.new, self, args)
  429.     if (not item) or (not item.widget) then
  430.         print("Error while checking menu entry: no property widget found.")
  431.         return
  432.     end
  433.     item.parent = self
  434.     item.theme = item.theme or theme
  435.     item.width = item.width or theme.width
  436.     item.height = item.height or theme.height
  437.     wibox.widget.base.check_widget(item.widget)
  438.     item._background = wibox.container.background()
  439.     item._background:set_shape(gears.shape.rounded_rect) --mod
  440.     item._background:set_shape_border_width(3) --mod
  441.     item._background:set_shape_border_color(item.theme.bg_normal) --mod
  442.     item._background:set_widget(item.widget)
  443.     item._background:set_fg(item.theme.fg_normal)
  444.     item._background:set_bg(item.theme.bg_normal)
  445.  
  446.  
  447.     -- Create bindings
  448.     item._background:buttons(gtable.join(
  449.         button({}, 3, function () self:hide() end),
  450.         button({}, 1, function ()
  451.             local num = gtable.hasitem(self.items, item)
  452.             self:item_enter(num, { mouse = true })
  453.             self:exec(num, { exec = true, mouse = true })
  454.         end )))
  455.  
  456.  
  457.     item._mouse = function ()
  458.         local num = gtable.hasitem(self.items, item)
  459.         self:item_enter(num, { hover = true, mouse = true })
  460.     end
  461.     item.widget:connect_signal("mouse::enter", item._mouse)
  462.  
  463.     if index then
  464.         self.layout:reset()
  465.         table.insert(self.items, index, item)
  466.         for _, i in ipairs(self.items) do
  467.             self.layout:add(i._background)
  468.         end
  469.     else
  470.         table.insert(self.items, item)
  471.         self.layout:add(item._background)
  472.     end
  473.     if self.wibox then
  474.         set_size(self)
  475.     end
  476.     return item
  477. end
  478.  
  479. --- Delete menu entry at given position
  480. -- @param num The position in the table of the menu entry to be deleted; can be also the menu entry itself
  481. function menu:delete(num)
  482.     if type(num) == "table" then
  483.         num = gtable.hasitem(self.items, num)
  484.     end
  485.     local item = self.items[num]
  486.     if not item then return end
  487.     item.widget:disconnect_signal("mouse::enter", item._mouse)
  488.     item.widget:set_visible(false)
  489.     table.remove(self.items, num)
  490.     if self.sel == num then
  491.         self:item_leave(self.sel)
  492.         self.sel = nil
  493.     end
  494.     self.layout:reset()
  495.     for _, i in ipairs(self.items) do
  496.         self.layout:add(i._background)
  497.     end
  498.     if self.child[num] then
  499.          self.child[num]:hide()
  500.         if self.active_child == self.child[num] then
  501.             self.active_child = nil
  502.         end
  503.         table.remove(self.child, num)
  504.     end
  505.     if self.wibox then
  506.         set_size(self)
  507.     end
  508. end
  509.  
  510. --------------------------------------------------------------------------------
  511.  
  512. --- Build a popup menu with running clients and show it.
  513. -- @tparam[opt] table args Menu table, see `new()` for more information.
  514. -- @tparam[opt] table item_args Table that will be merged into each item, see
  515. --   `new()` for more information.
  516. -- @tparam[opt] func filter A function taking a client as an argument and
  517. --   returning `true` or `false` to indicate whether the client should be
  518. --   included in the menu.
  519. -- @return The menu.
  520. function menu.clients(args, item_args, filter)
  521.     local cls_t = {}
  522.     for c in client_iterate(filter or function() return true end) do
  523.         cls_t[#cls_t + 1] = {
  524.             c.name or "",
  525.             function ()
  526.                 if not c.valid then return end
  527.                 if not c:isvisible() then
  528.                     tags.viewmore(c:tags(), c.screen)
  529.                 end
  530.                 c:emit_signal("request::activate", "menu.clients", {raise=true})
  531.             end,
  532.             c.icon }
  533.         if item_args then
  534.             if type(item_args) == "function" then
  535.                 gtable.merge(cls_t[#cls_t], item_args(c))
  536.             else
  537.                 gtable.merge(cls_t[#cls_t], item_args)
  538.             end
  539.         end
  540.     end
  541.     args = args or {}
  542.     args.items = args.items or {}
  543.     gtable.merge(args.items, cls_t)
  544.  
  545.     local m = menu.new(args)
  546.     m:show(args)
  547.     return m
  548. end
  549.  
  550. local clients_menu = nil
  551.  
  552. --- Use menu.clients to build and open the client menu if it isn't already open.
  553. -- Close the client menu if it is already open.
  554. -- See `awful.menu.clients` for more information.
  555. -- @tparam[opt] table args Menu table, see `new()` for more information.
  556. -- @tparam[opt] table item_args Table that will be merged into each item, see
  557. --   `new()` for more information.
  558. -- @tparam[opt] func filter A function taking a client as an argument and
  559. --   returning `true` or `false` to indicate whether the client should be
  560. --   included in the menu.
  561. -- @return The menu.
  562. function menu.client_list(args, item_args, filter)
  563.     if clients_menu and clients_menu.wibox.visible then
  564.         clients_menu:hide()
  565.         clients_menu = nil
  566.     else
  567.         clients_menu = menu.clients(args, item_args, filter)
  568.     end
  569.     return clients_menu
  570. end
  571.  
  572. --------------------------------------------------------------------------------
  573.  
  574. --- Default awful.menu.entry constructor
  575. -- @param parent The parent menu (TODO: This is apparently unused)
  576. -- @param args the item params
  577. -- @return table with 'widget', 'cmd', 'akey' and all the properties the user wants to change
  578. function menu.entry(parent, args) -- luacheck: no unused args
  579.     args = args or {}
  580.     args.text = args[1] or args.text or ""
  581.     args.cmd = args[2] or args.cmd
  582.     args.icon = args[3] or args.icon
  583.     local ret = {}
  584.     -- Create the item label widget
  585.     local label = wibox.widget.textbox()
  586.     local key = ''
  587.     label:set_font(args.theme.font)
  588.     label:set_markup(string.gsub(
  589.         gstring.xml_escape(args.text), "&amp;(%w)",
  590.         function (l)
  591.             key = string.lower(l)
  592.             return "<u>" .. l .. "</u>"
  593.         end, 1))
  594.     -- Set icon if needed
  595.     local icon, iconbox
  596.     local margin = wibox.container.margin()
  597.     margin:set_widget(label)
  598.     if args.icon then
  599.         icon = surface.load(args.icon)
  600.     end
  601.     if icon then
  602.         local iw = icon:get_width()
  603.         local ih = icon:get_height()
  604.         if iw > args.theme.width or ih > args.theme.height then
  605.             local w, h
  606.             if ((args.theme.height / ih) * iw) > args.theme.width then
  607.                 w, h = args.theme.height, (args.theme.height / iw) * ih
  608.             else
  609.                 w, h = (args.theme.height / ih) * iw, args.theme.height
  610.             end
  611.             -- We need to scale the image to size w x h
  612.             local img = cairo.ImageSurface(cairo.Format.ARGB32, w, h)
  613.             local cr = cairo.Context(img)
  614.             cr:scale(w / iw, h / ih)
  615.             cr:set_source_surface(icon, 0, 0)
  616.             cr:paint()
  617.             icon = img
  618.         end
  619.         iconbox = wibox.widget.imagebox()
  620.         if iconbox:set_image(icon) then
  621.             margin:set_left(dpi(2))
  622.         else
  623.             iconbox = nil
  624.         end
  625.     end
  626.     if not iconbox then
  627.         margin:set_left(args.theme.height + dpi(2))
  628.     end
  629.     -- Create the submenu icon widget
  630.     local submenu
  631.     if type(args.cmd) == "table" then
  632.         if args.theme.submenu_icon then
  633.             submenu = wibox.widget.imagebox()
  634.             submenu:set_image(args.theme.submenu_icon)
  635.         else
  636.             submenu = wibox.widget.textbox()
  637.             submenu:set_font(args.theme.font)
  638.             submenu:set_text(args.theme.submenu)
  639.         end
  640.     end
  641.     -- Add widgets to the wibox
  642.     local left = wibox.layout.fixed.horizontal()
  643.     if iconbox then
  644.         local margin_iconbox = wibox.widget { --mod
  645.             iconbox,
  646.             margins = dpi(5),
  647.             widget = wibox.container.margin,
  648.         }
  649.         left:add(margin_iconbox)
  650.     end
  651.     -- This contains the label
  652.     left:add(margin)
  653.  
  654.     local layout = wibox.layout.align.horizontal()
  655.     layout:set_left(left)
  656.     if submenu then
  657.         layout:set_right(submenu)
  658.     end
  659.  
  660.     return table_update(ret, {
  661.         label = label,
  662.         sep = submenu,
  663.         icon = iconbox,
  664.         widget = layout,
  665.         cmd = args.cmd,
  666.         akey = key,
  667.     })
  668. end
  669.  
  670. --------------------------------------------------------------------------------
  671.  
  672. --- Create a menu popup.
  673. -- @param args Table containing the menu informations.
  674. --
  675. -- * Key items: Table containing the displayed items. Each element is a table by default (when element 'new' is
  676. --   awful.menu.entry) containing: item name, triggered action (submenu table or function), item icon (optional).
  677. -- * Keys theme.[fg|bg]_[focus|normal], theme.border_color, theme.border_width, theme.submenu_icon, theme.height
  678. --   and theme.width override the default display for your menu and/or of your menu entry, each of them are optional.
  679. -- * Key auto_expand controls the submenu auto expand behaviour by setting it to true (default) or false.
  680. --
  681. -- @param parent Specify the parent menu if we want to open a submenu, this value should never be set by the user.
  682. -- @usage -- The following function builds and shows a menu of clients that match
  683. -- -- a particular rule.
  684. -- -- Bound to a key, it can be used to select from dozens of terminals open on
  685. -- -- several tags.
  686. -- -- When using @{rules.match_any} instead of @{rules.match},
  687. -- -- a menu of clients with different classes could be build.
  688. --
  689. -- function terminal_menu ()
  690. --   terms = {}
  691. --   for i, c in pairs(client.get()) do
  692. --     if awful.rules.match(c, {class = "URxvt"}) then
  693. --       terms[i] =
  694. --         {c.name,
  695. --          function()
  696. --            c.first_tag:view_only()
  697. --            client.focus = c
  698. --          end,
  699. --          c.icon
  700. --         }
  701. --     end
  702. --   end
  703. --   awful.menu(terms):show()
  704. -- end
  705. function menu.new(args, parent)
  706.     args = args or {}
  707.     args.layout = args.layout or wibox.layout.flex.vertical
  708.     local _menu = table_update(object(), {
  709.         item_enter = menu.item_enter,
  710.         item_leave = menu.item_leave,
  711.         get_root = menu.get_root,
  712.         delete = menu.delete,
  713.         update = menu.update,
  714.         toggle = menu.toggle,
  715.         hide = menu.hide,
  716.         show = menu.show,
  717.         exec = menu.exec,
  718.         add = menu.add,
  719.         child = {},
  720.         items = {},
  721.         parent = parent,
  722.         layout = args.layout(),
  723.         theme = load_theme(args.theme or {}, parent and parent.theme) })
  724.  
  725.     if parent then
  726.         _menu.auto_expand = parent.auto_expand
  727.     elseif args.auto_expand ~= nil then
  728.         _menu.auto_expand = args.auto_expand
  729.     else
  730.         _menu.auto_expand = true
  731.     end
  732.  
  733.     -- Create items
  734.     for _, v in ipairs(args) do  _menu:add(v)  end
  735.     if args.items then
  736.         for _, v in pairs(args.items) do  _menu:add(v)  end
  737.     end
  738.  
  739.     _menu._keygrabber = function (...)
  740.         grabber(_menu, ...)
  741.     end
  742.  
  743.     _menu.wibox = wibox({
  744.         ontop = true,
  745.         fg = _menu.theme.fg_normal,
  746.         bg = _menu.theme.bg_normal,
  747.         border_color = _menu.theme.border,
  748.         border_width = _menu.theme.border_width,
  749.         shape = _menu.theme.shape, -- mod
  750.         type = "popup_menu" })
  751.     _menu.wibox.visible = false
  752.     _menu.wibox:set_widget(_menu.layout)
  753.     set_size(_menu)
  754.  
  755.     _menu.x = _menu.wibox.x
  756.     _menu.y = _menu.wibox.y
  757.     return _menu
  758. end
  759.  
  760. function menu.mt:__call(...)
  761.     return menu.new(...)
  762. end
  763.  
  764. return setmetatable(menu, menu.mt)
  765.  
  766. -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
  767.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement