diff --git a/lib/awful/menu.lua.in b/lib/awful/menu.lua.in index de9891d4..b27d42d5 100644 --- a/lib/awful/menu.lua.in +++ b/lib/awful/menu.lua.in @@ -1,34 +1,53 @@ ---------------------------------------------------------------------------- +-------------------------------------------------------------------------------- -- @author Damien Leone <damien.leone@gmail.com> -- @author Julien Danjou <julien@danjou.info> --- @copyright 2008 Damien Leone, Julien Danjou +-- @author dodo +-- @copyright 2008, 2011 Damien Leone, Julien Danjou, dodo -- @release @AWESOME_VERSION@ ---------------------------------------------------------------------------- +-------------------------------------------------------------------------------- --- Grab environment we need -local pairs = pairs -local table = table -local string = string -local type = type -local setmetatable = setmetatable -local tonumber = tonumber -local capi = -{ - screen = screen, - mouse = mouse, - client = client, - keygrabber = keygrabber, - oocairo = oocairo -} local wibox = require("wibox") local button = require("awful.button") local util = require("awful.util") local tags = require("awful.tag") -local awbeautiful = require("beautiful") +local beautiful = require("beautiful") +local object = require("gears.object") +local setmetatable = setmetatable +local tonumber = tonumber +local string = string +local ipairs = ipairs +local pairs = pairs +local pcall = pcall +local print = print +local table = table +local type = type +local math = math +local capi = { + timer = timer, + screen = screen, + mouse = mouse, + client = client, + keygrabber = keygrabber, + oocairo = oocairo } + ---- Creation of menus. module("awful.menu") + +local table_update = function (t, set) + for k, v in pairs(set) do + t[k] = v + end + return t +end + +local table_merge = function (t, set) + for _, v in ipairs(set) do + table.insert(t, v) + end +end + + local cur_menu --- Key bindings for menu navigation. @@ -43,33 +62,256 @@ menu_keys = { up = { "Up" }, back = { "Left" }, close = { "Escape" } } -local function load_theme(custom) - local theme = {} - local beautiful - beautiful = awbeautiful.get() - - theme.fg_focus = custom.fg_focus or beautiful.menu_fg_focus or beautiful.fg_focus - theme.bg_focus = custom.bg_focus or beautiful.menu_bg_focus or beautiful.bg_focus - theme.fg_normal = custom.fg_normal or beautiful.menu_fg_normal or beautiful.fg_normal - theme.bg_normal = custom.bg_normal or beautiful.menu_bg_normal or beautiful.bg_normal - - theme.submenu_icon = custom.submenu_icon or beautiful.menu_submenu_icon - - theme.menu_height = custom.height or beautiful.menu_height or 16 - theme.menu_width = custom.width or beautiful.menu_width or 100 - - theme.border = custom.border_color or beautiful.menu_border_color or beautiful.border_normal - theme.border_width = custom.border_width or beautiful.menu_border_width or beautiful.border_width - - return theme +local function load_theme(a, b) + a = a or {} + b = b or {} + local ret = {} + local fallback = beautiful.get() + if a.reset then b = fallback end + if a == "reset" then a = fallback end + ret.border = a.border_color or b.menu_border_color or b.border_normal or + fallback.menu_border_color or fallback.border_normal + ret.border_width= a.border_width or b.menu_border_width or b.border_width or + fallback.menu_border_width or fallback.border_width + ret.fg_focus = a.fg_focus or b.menu_fg_focus or b.fg_focus or + fallback.menu_fg_focus or fallback.fg_focus + ret.bg_focus = a.bg_focus or b.menu_bg_focus or b.bg_focus or + fallback.menu_bg_focus or fallback.bg_focus + ret.fg_normal = a.fg_normal or b.menu_fg_normal or b.fg_normal or + fallback.menu_fg_normal or fallback.fg_normal + ret.bg_normal = a.bg_normal or b.menu_bg_normal or b.bg_normal or + fallback.menu_bg_normal or fallback.bg_normal + ret.submenu_icon= a.submenu_icon or b.menu_submenu_icon or b.submenu_icon or + fallback.menu_submenu_icon or fallback.submenu_icon + ret.height = a.height or b.menu_height or b.height or + fallback.menu_height or 16 + ret.width = a.width or b.menu_width or b.width or + fallback.menu_width or 100 + return ret end -local function item_leave(menu, num) - if num > 0 then - menu.items[num].wibox:set_fg(menu.theme.fg_normal) - menu.items[num].wibox:set_bg(menu.theme.bg_normal) + +local function item_position(menu, child) + local in_dir, other, a, b = 0, 0, "height", "width" + local dir = menu.layout.get_dir and menu.layout:get_dir() or "y" + if dir == "x" then a, b = b, a end + + local in_dir, other = 0, menu[b] + local num = util.table.hasitem(menu.child, child) + if num then + for i = 0, num - 1 do + local item = menu.items[i] + if item then + other = math.max(other, item[b]) + in_dir = in_dir + item[a] + end + end end + local w, h = other, in_dir + if dir == "x" then w, h = h, w end + return w, h +end + + +local function set_coords(menu, screen_idx, m_coords) + local s_geometry = capi.screen[screen_idx].workarea + local screen_w = s_geometry.x + s_geometry.width + local screen_h = s_geometry.y + s_geometry.height + + menu.width = menu.wibox.width + menu.height = menu.wibox.height + + menu.x = menu.wibox.x + menu.y = menu.wibox.y + + if menu.parent then + local w, h = item_position(menu.parent, menu) + w = w + menu.parent.theme.border_width + h = h + menu.parent.theme.border_width + + menu.y = menu.parent.y + h + menu.height > screen_h and + screen_h - menu.height or menu.parent.y + h + menu.x = menu.parent.x + w + menu.width > screen_w and + menu.parent.x - menu.width or menu.parent.x + w + else + if m_coords == nil then + m_coords = capi.mouse.coords() + m_coords.x = m_coords.x + 1 + m_coords.y = m_coords.y + 1 + end + menu.y = m_coords.y < s_geometry.y and s_geometry.y or m_coords.y + menu.x = m_coords.x < s_geometry.x and s_geometry.x or m_coords.x + + menu.y = menu.y + menu.height > screen_h and + screen_h - menu.height or menu.y + menu.x = menu.x + menu.width > screen_w and + screen_w - menu.width or menu.x + end + + menu.wibox.x = menu.x + menu.wibox.y = menu.y +end + + +local function set_size(menu) + local in_dir, other, a, b = 0, 0, "height", "width" + local dir = menu.layout.get_dir and menu.layout:get_dir() or "y" + if dir == "x" then a, b = b, a end + for _, item in ipairs(menu.items) do + other = math.max(other, item[b]) + in_dir = in_dir + item[a] + end + menu[a], menu[b] = in_dir, other + if in_dir > 0 and other > 0 then + menu.wibox[a] = in_dir + menu.wibox[b] = other + return true + end + return false +end + + +local function check_access_key(menu, key) + for i, item in ipairs(menu.items) do + if item.akey == key then + menu:item_enter(i) + menu:exec(i) + return + end + end + if menu.parent then + check_access_key(menu.parent, key) + end +end + + +local function grabber(mod, key, event) + if event == "release" then + return true + end + + local sel = cur_menu.sel or 0 + if util.table.hasitem(menu_keys.up, key) then + local sel_new = sel-1 < 1 and #cur_menu.items or sel-1 + cur_menu:item_enter(sel_new) + elseif util.table.hasitem(menu_keys.down, key) then + local sel_new = sel+1 > #cur_menu.items and 1 or sel+1 + cur_menu:item_enter(sel_new) + elseif sel > 0 and util.table.hasitem(menu_keys.exec, key) then + cur_menu:exec(sel) + elseif util.table.hasitem(menu_keys.back, key) then + cur_menu:hide() + elseif util.table.hasitem(menu_keys.close, key) then + get_root(cur_menu):hide() + else + check_access_key(cur_menu, key) + end + + return true +end + + +function exec(menu, num, mouse_event) + local item = menu.items[num] + if not item then return end + local cmd = item.cmd + if type(cmd) == "table" then + if #cmd == 0 then + return + end + if not menu.child[num] then + menu.child[num] = new(cmd, menu) + end + + if menu.active_child then + menu.active_child:hide() + menu.active_child = nil + end + menu.active_child = menu.child[num] + menu.active_child:show() + elseif type(cmd) == "string" then + get_root(menu):hide() + util.spawn(cmd) + elseif type(cmd) == "function" then + local visible, action = cmd(item, menu) + if not visible then + get_root(menu):hide() + else + menu:update() + if menu.items[num] then + menu:item_enter(num, mouse_event) + end + end + if action and type(action) == "function" then + action() + end + end +end + +function item_enter(menu, num, mouse_event) + local item = menu.items[num] + if num == nil or menu.sel == num or not item then + return + elseif menu.sel then + menu:item_leave(menu.sel) + end + --print("sel", num, menu.sel, item.theme.bg_focus) + item._background:set_fg(item.theme.fg_focus) + item._background:set_bg(item.theme.bg_focus) + cur_menu = menu + menu.sel = num + + if menu.auto_expand and mouse_event then + if menu.active_child then + menu.active_child:hide() + menu.active_child = nil + end + + if type(item.cmd) == "table" then + menu:exec(num) + end + end +end + + +function item_leave(menu, num) + --print("leave", num) + local item = menu.items[num] + if item then + item._background:set_fg(item.theme.fg_normal) + item._background:set_bg(item.theme.bg_normal) + end +end + + +--- Show a menu. +-- @param menu The menu to show. +-- @param args.keygrabber A boolean enabling or not the keyboard navigation. +-- @param args.coords Menu position defaulting to mouse.coords() +function show(menu, args) + args = args or {} + local coords = args.coords or nil + local screen_index = capi.mouse.screen + local keygrabber = args.keygrabber or false + + menu.wibox.screen = screen_index + if not set_size(menu) then return end + set_coords(menu, screen_index, coords) + + if menu.parent then + menu.keygrabber = menu.parent.keygrabber + elseif keygrabber ~= nil then + menu.keygrabber = keygrabber + else + menu.keygrabber = false + end + + if not cur_menu and menu.keygrabber then + capi.keygrabber.run(grabber) + end + cur_menu = menu + menu.wibox.visible = true end --- Hide a menu popup. @@ -77,8 +319,7 @@ end function hide(menu) -- Remove items from screen for i = 1, #menu.items do - item_leave(menu, i) - menu.items[i].wibox.visible = false + menu:item_leave(i) end if menu.active_child then menu.active_child:hide() @@ -92,176 +333,229 @@ function hide(menu) if not cur_menu and menu.keygrabber then capi.keygrabber.stop() end + menu.wibox.visible = false end --- Get the elder parent so for example when you kill --- it, it will destroy the whole family. -local function get_parents(menu) - if menu.parent then - return get_parents(menu.parent) - end - return menu -end - -local function exec(menu, num, mouse_event) - local cmd = menu.items[num].cmd - if type(cmd) == "table" then - if #cmd == 0 then - return - end - if not menu.child[num] then - menu.child[num] = new({ items = cmd }, menu, num) - end - - if menu.active_child then - menu.active_child:hide() - menu.active_child = nil - end - menu.active_child = menu.child[num] - menu.active_child:show() - elseif type(cmd) == "string" then - get_parents(menu):hide() - util.spawn(cmd) - elseif type(cmd) == "function" then - get_parents(menu):hide() - cmd(menu.items[num].returned_value) - end -end - -local function item_enter(menu, num, mouse_event) - if menu.sel == num then - return - elseif menu.sel then - item_leave(menu, menu.sel) - end - - menu.items[num].wibox:set_fg(menu.theme.fg_focus) - menu.items[num].wibox:set_bg(menu.theme.bg_focus) - menu.sel = num - cur_menu = menu - - if menu.auto_expand and mouse_event then - if menu.active_child then - menu.active_child:hide() - menu.active_child = nil - end - - if type(menu.items[num].cmd) == "table" then - exec(menu, num) - end - end -end - -local function check_access_key(menu, key) - for i, item in pairs(menu.items) do - if item.akey == key then - item_enter(menu, i) - exec(menu, i) - return - end - end - if menu.parent then - check_access_key(menu.parent, key) - end -end - -local function grabber(mod, key, event) - if event == "release" then - return true - end - - local sel = cur_menu.sel or 0 - if util.table.hasitem(menu_keys.up, key) then - local sel_new = sel-1 < 1 and #cur_menu.items or sel-1 - item_enter(cur_menu, sel_new) - elseif util.table.hasitem(menu_keys.down, key) then - local sel_new = sel+1 > #cur_menu.items and 1 or sel+1 - item_enter(cur_menu, sel_new) - elseif sel > 0 and util.table.hasitem(menu_keys.exec, key) then - exec(cur_menu, sel) - elseif util.table.hasitem(menu_keys.back, key) then - cur_menu:hide() - elseif util.table.hasitem(menu_keys.close, key) then - get_parents(cur_menu):hide() +--- Toggle menu visibility. +-- @param menu The menu to show if it's hidden, or to hide if it's shown. +-- @param args.keygrabber A boolean enabling or not the keyboard navigation. +-- @param args.coords Menu position {x,y} +function toggle(menu, args) + if menu.wibox.visible then + menu:hide() else - check_access_key(cur_menu, key) + menu:show(args) end - - return true end -local function add_item(data, num, item_info) - local item = wibox({ - fg = data.theme.fg_normal, - bg = data.theme.bg_normal, - border_color = data.theme.border, - border_width = data.theme.border_width, - type = "popup_menu" - }) +--- Update menu content +-- @param menu The mnenu to update. +function update(menu) + if menu.wibox.visible then + menu:show({ + keygrabber = menu.keygrabber, + coords = { x = menu.x, y = menu.y } }) + end +end + + +--- Get the elder parent so for example when you kill +-- it, it will destroy the whole family. +-- @param menu The sub menu of the menu family. +function get_root(menu) + return menu.parent and get_root(menu.parent) or menu +end + +--- Add a new menu entry +-- @param menu The parent menu +-- @param args The item params +-- @param args.new (Default: awful.menu.entry) The menu entry constructor +-- @param args.theme (Optional) The menu entry theme +-- @param args.* params needed for the menu entry constructor +-- @param index (Optional) the index where the new entry will inserted +function add(menu, args, index) + if not args then return end + local theme = load_theme(args.theme or {}, menu.theme) + args.theme = theme + args.new = args.new or entry + local success, item = pcall(args.new, menu, args) + if not success then + print("Error while creating menu entry: " .. item) + return + end + if not item.widget then + print("Error while checking menu entry: no property widget found.") + return + end + item.parent = menu + item.theme = item.theme or theme + item.width = item.width or theme.width + item.height = item.height or theme.height + wibox.widget.base.check_widget(item.widget) + item._background = wibox.widget.background() + item._background:set_widget(item.widget) + item._background:set_fg(item.theme.fg_normal) + item._background:set_bg(item.theme.bg_normal) + -- Create bindings - local bindings = util.table.join( - button({}, 1, function () item_enter(data, num); exec(data, num) end), - button({}, 3, function () data:hide() end) - ) + item._background:buttons(util.table.join( + button({}, 3, function () menu:hide() end), + button({}, 1, function () + local num = util.table.hasitem(menu.items, item) + menu:item_enter(num) + menu:exec(num) + end ))) + + item._mouse = function () + local num = util.table.hasitem(menu.items, item) + menu:item_enter(num, true) + end + item.widget:connect_signal("mouse::enter", item._mouse) + + if index then + menu.layout:reset() + table.insert(menu.items, index, item) + for _, i in ipairs(menu.items) do + menu.layout:add(i._background) + end + else + table.insert(menu.items, item) + menu.layout:add(item._background) + end + return item +end + +-- Delete menu entry at given position +-- @param menu The menu +-- @param num The position in the table of the menu entry to be deleted; can be also the menu entry itself +function delete(menu, num) + if type(num) == "table" then + num = util.table.hasitem(menu.items, num) + end + local item = menu.items[num] + if not item then return end + item.widget:disconnect_signal("mouse::enter", item._mouse) + item.widget.screen = nil + table.remove(menu.items, num) + if menu.sel == num then + menu:item_leave(menu.sel) + menu.sel = nil + end + menu.layout:reset() + for _, i in ipairs(menu.items) do + menu.layout:add(i._background) + end + if menu.child[num] then + menu.child[num]:hide() + if menu.active_child == menu.child[num] then + menu.active_child = nil + end + table.remove(menu.child, num) + end +end + +-------------------------------------------------------------------------------- + +--- Build a popup menu with running clients and shows it. +-- @param menu Menu table, see new() function for more informations +-- @param args.keygrabber A boolean enabling or not the keyboard navigation. +-- @return The menu. +function clients(menu, args) -- FIXME crude api + menu = menu or {} + local cls = capi.client.get() + local cls_t = {} + for k, c in pairs(cls) do + cls_t[#cls_t + 1] = { + util.escape(c.name) or "", + function () + if not c:isvisible() then + tags.viewmore(c:tags(), c.screen) + end + capi.client.focus = c + c:raise() + end, + c.icon } + end + args = args or {} + args.items = args.items or {} + table_merge(args.items, cls_t) + + local m = new(args) + m:show(args) + return m +end + +-------------------------------------------------------------------------------- + +--- Default awful.menu.entry constructor +-- @param parent The parent menu +-- @param args the item params +-- @return table with 'widget', 'cmd', 'akey' and all the properties the user wants to change +function entry(parent, args) + args = args or {} + args.text = args[1] or args.text or "" + args.cmd = args[2] or args.cmd + args.icon = args[3] or args.icon + local ret = {} -- Create the item label widget local label = wibox.widget.textbox() local key = '' - label:set_markup(string.gsub(util.escape(item_info[1]), "&(%w)", - function (l) - key = string.lower(l) - return ""..l.."" - end, 1)) + label:set_markup(string.gsub( + util.escape(args.text), "&(%w)", + function (l) + key = string.lower(l) + return "" .. l .. "" + end, 1)) -- Set icon if needed - local iconbox + local icon, iconbox local margin = wibox.layout.margin() margin:set_widget(label) - if item_info[3] then - local icon = type(item_info[3]) == "string" and capi.oocairo.image_surface_create_from_png(item_info[3]) or item_info[3] - local width = icon:get_width() - local height = icon:get_height() - if width > data.h or height > data.h then + if args.icon then + icon = args.icon + if type(icon) == "string" then + icon = capi.oocairo.image_surface_create_from_png(icon) + end + end + if icon then + local iw = icon:get_width() + local ih = icon:get_height() + if iw > args.theme.width or ih > args.theme.height then local w, h - if ((data.h/height) * width) > data.h then - w, h = data.h, (data.h / width) * height + if ((args.theme.height / ih) * iw) > args.theme.width then + w, h = args.theme.height, (args.theme.height / iw) * ih else - w, h = (data.h / height) * width, data.h + w, h = (args.theme.height / ih) * iw, args.theme.height end -- We need to scale the image to size w x h local img = capi.oocairo.image_surface_create("argb32", w, h) local cr = capi.oocairo.context_create(img) - cr:scale(w / width, h / height) + cr:scale(w / iw, h / ih) cr:set_source(icon, 0, 0) cr:paint() icon = img end iconbox = wibox.widget.imagebox() - margin:set_left(2) - if not iconbox:set_image(icon) then - -- Setting the image failed, it must be invalid + if iconbox:set_image(icon) then + margin:set_left(2) + else iconbox = nil end end if not iconbox then - margin:set_left(data.h + 2) + margin:set_left(args.theme.height + 2) end - - item:buttons(bindings) - - local mouse_enter_func = function () item_enter(data, num, true) end - item:connect_signal("mouse::enter", mouse_enter_func) - -- Create the submenu icon widget - local submenu - if type(item_info[2]) == "table" then - submenu = wibox.widget.imagebox() - if data.theme.submenu_icon then - submenu:set_image(capi.oocairo.image_surface_create_from_png(data.theme.submenu_icon)) + local submenu_icon + if type(args.cmd) == "table" then + submenu_icon = wibox.widget.imagebox() + if args.theme.submenu_icon then + submenu_icon:set_image( + capi.oocairo.image_surface_create_from_png( + args.theme.submenu_icon)) end - submenu:buttons(bindings) end - -- Add widgets to the wibox local left = wibox.layout.fixed.horizontal() if iconbox then @@ -272,136 +566,29 @@ local function add_item(data, num, item_info) local layout = wibox.layout.align.horizontal() layout:set_middle(left) - if submenu then - layout:set_right(submenu) + if submenu_icon then + layout:set_right(submenu_icon) end - item:set_widget(layout) - - local w, h = label:fit(0, 0) - item.height = h + 2 - item.ontop = true - - return { wibox = item, akey= key, cmd = item_info[2], returned_value=item_info[1] } + return table_update(ret, { + label = label, + icon = iconbox, + widget = layout, + cmd = args.cmd, + akey = key, + }) end ---- Build a popup menu with running clients and shows it. --- @param menu Menu table, see new() function for more informations --- @param args.keygrabber A boolean enabling or not the keyboard navigation. --- @return The menu. -function clients(menu, args) - local cls = capi.client.get() - local cls_t = {} - for k, c in pairs(cls) do - cls_t[#cls_t + 1] = { util.escape(c.name) or "", - function () - if not c:isvisible() then - tags.viewmore(c:tags(), c.screen) - end - capi.client.focus = c - c:raise() - end, - c.icon } - end +-------------------------------------------------------------------------------- - if not menu then - menu = {} - end - - menu.items = cls_t - - local m = new(menu) - m:show(args) - return m -end - -local function set_coords(menu, screen_idx, m_coords) - local s_geometry = capi.screen[screen_idx].workarea - local screen_w = s_geometry.x + s_geometry.width - local screen_h = s_geometry.y + s_geometry.height - - local i_h = menu.h + menu.theme.border_width - local m_h = (i_h * #menu.items) + menu.theme.border_width - - if menu.parent then - menu.w = menu.parent.w - menu.h = menu.parent.h - - local p_w = i_h * (menu.num - 1) - local m_w = menu.w - menu.theme.border_width - - menu.y = menu.parent.y + p_w + m_h > screen_h and screen_h - m_h or menu.parent.y + p_w - menu.x = menu.parent.x + m_w*2 > screen_w and menu.parent.x - m_w or menu.parent.x + m_w - else - local m_w = menu.w - if m_coords == nil then - m_coords = capi.mouse.coords() - m_coords.x = m_coords.x + 1 - m_coords.y = m_coords.y + 1 - end - - menu.y = m_coords.y < s_geometry.y and s_geometry.y or m_coords.y - menu.x = m_coords.x < s_geometry.x and s_geometry.x or m_coords.x - - menu.y = menu.y + m_h > screen_h and screen_h - m_h or menu.y - menu.x = menu.x + m_w > screen_w and screen_w - m_w or menu.x - end -end - ---- Show a menu. --- @param menu The menu to show. --- @param args.keygrabber A boolean enabling or not the keyboard navigation. --- @param args.coords Menu position defaulting to mouse.coords() -function show(menu, args) - args = args or {} - local screen_index = capi.mouse.screen - local keygrabber = args.keygrabber or false - local coords = args.coords or nil - set_coords(menu, screen_index, coords) - for num, item in pairs(menu.items) do - local wibox = item.wibox - wibox.width = menu.w - wibox.height = menu.h - wibox.x = menu.x - wibox.y = menu.y + (num - 1) * (menu.h + wibox.border_width) - wibox.visible = true - end - - if menu.parent then - menu.keygrabber = menu.parent.keygrabber - elseif keygrabber ~= nil then - menu.keygrabber = keygrabber - else - menu.keygrabber = false - end - - if not cur_menu and menu.keygrabber then - capi.keygrabber.run(grabber) - end - cur_menu = menu -end - ---- Toggle menu visibility. --- @param menu The menu to show if it's hidden, or to hide if it's shown. --- @param args.keygrabber A boolean enabling or not the keyboard navigation. --- @param args.coords Menu position {x,y} -function toggle(menu, args) - if menu.items[1] and menu.items[1].wibox.visible then - menu:hide() - else - menu:show(args) - end -end - ---- Open a menu popup. --- @param menu Table containing the menu informations.
+--- Create a menu popup. +-- @param args Table containing the menu informations.
-- -- @param parent Specify the parent menu if we want to open a submenu, this value should never be set by the user. --- @param num Specify the parent's clicked item number if we want to open a submenu, this value should never be set by the user. -- @usage The following function builds, and shows a menu of clients that match -- a particular rule. Bound to a key, it can for example be used to select from -- dozens of terminals open on several tags. With the use of @@ -423,49 +610,61 @@ end --     }
--    end
--   end
---   m = awful.menu({items = terms})
+--   m = awful.menu(terms)
--   m:show({keygrabber=true})
--   return m
-- end
--

-function new(menu, parent, num) - -- Create a table to store our menu informations - local data = {} +function new(args, parent) + args = args or {} + args.layout = args.layout or wibox.layout.flex.vertical + local menu = table_update(object(), { + item_enter = item_enter, + item_leave = item_leave, + get_root = get_root, + delete = delete, + update = update, + toggle = toggle, + hide = hide, + show = show, + exec = exec, + add = add, + child = {}, + items = {}, + parent = parent, + layout = args.layout(), + theme = load_theme(args.theme or {}, parent and parent.theme) }) - data.items = {} - data.num = num or 1 - data.theme = parent and parent.theme or load_theme(menu) - data.parent = parent - data.child = {} if parent then - data.auto_expand = parent.auto_expand - elseif menu.auto_expand ~= nil then - data.auto_expand = menu.auto_expand + menu.auto_expand = parent.auto_expand + elseif args.auto_expand ~= nil then + menu.auto_expand = args.auto_expand else - data.auto_expand = true + menu.auto_expand = true end - data.h = parent and parent.h or data.theme.menu_height - if type(data.h) ~= 'number' then data.h = tonumber(data.h) end - data.w = parent and parent.w or data.theme.menu_width - if type(data.w) ~= 'number' then data.w = tonumber(data.w) end -- Create items - for k, v in pairs(menu.items) do - table.insert(data.items, add_item(data, k, v)) + for i, v in ipairs(args) do menu:add(v) end + if args.items then + for i, v in pairs(args.items) do menu:add(v) end end - if #data.items > 0 and data.h < data.items[1].wibox.height then - data.h = data.items[1].wibox.height - end + menu.wibox = wibox({ + ontop = true, + fg = menu.theme.fg_normal, + bg = menu.theme.bg_normal, + border_color = menu.theme.border, + border_width = menu.theme.border_width, + type = "popup_menu" }) + menu.wibox.visible = false + menu.wibox:set_widget(menu.layout) + set_size(menu) - -- Set methods - data.hide = hide - data.show = show - data.toggle = toggle - - return data + menu.x = menu.wibox.x + menu.y = menu.wibox.y + return menu end -setmetatable(_M, { __call = function(_, ...) return new(...) end }) +setmetatable(_M, { __call = function (_, ...) return new(...) end }) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80