2011-03-30 23:11:41 +02:00
--------------------------------------------------------------------------------
2008-10-22 14:22:48 +02:00
-- @author Damien Leone <damien.leone@gmail.com>
2008-11-07 15:27:35 +01:00
-- @author Julien Danjou <julien@danjou.info>
2011-03-30 23:11:41 +02:00
-- @author dodo
-- @copyright 2008, 2011 Damien Leone, Julien Danjou, dodo
2008-10-22 14:22:48 +02:00
-- @release @AWESOME_VERSION@
2011-03-30 23:11:41 +02:00
--------------------------------------------------------------------------------
2008-10-22 14:22:48 +02:00
2011-03-30 23:11:41 +02:00
local wibox = require ( " wibox " )
local button = require ( " awful.button " )
local util = require ( " awful.util " )
local tags = require ( " awful.tag " )
local beautiful = require ( " beautiful " )
local object = require ( " gears.object " )
local setmetatable = setmetatable
local tonumber = tonumber
local string = string
local ipairs = ipairs
2008-10-23 11:19:46 +02:00
local pairs = pairs
2011-03-30 23:11:41 +02:00
local pcall = pcall
local print = print
2008-10-22 14:22:48 +02:00
local table = table
local type = type
2011-03-30 23:11:41 +02:00
local math = math
local capi = {
timer = timer ,
2009-03-04 19:42:25 +01:00
screen = screen ,
mouse = mouse ,
2009-03-09 14:14:01 +01:00
client = client ,
2010-09-29 16:06:44 +02:00
keygrabber = keygrabber ,
2012-01-29 15:17:51 +01:00
awesome = awesome ,
2011-03-30 23:11:41 +02:00
oocairo = oocairo }
2008-10-22 14:22:48 +02:00
module ( " awful.menu " )
2011-03-30 23:11:41 +02:00
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
2009-03-09 14:14:01 +01:00
local cur_menu
2009-08-21 16:34:41 +02:00
--- Key bindings for menu navigation.
2011-05-02 05:30:59 +02:00
-- Keys are: up, down, exec, enter, back, close. Value are table with a list of valid
2009-08-21 16:34:41 +02:00
-- keys for the action, i.e. menu_keys.up = { "j", "k" } will bind 'j' and 'k'
-- key to up action. This is common to all created menu.
-- @class table
-- @name menu_keys
menu_keys = { up = { " Up " } ,
down = { " Down " } ,
back = { " Left " } ,
2011-05-02 05:30:59 +02:00
exec = { " Return " } ,
enter = { " Right " } ,
2009-08-21 16:34:41 +02:00
close = { " Escape " } }
2009-03-09 14:14:01 +01:00
2008-10-24 22:31:14 +02:00
2011-03-30 23:11:41 +02:00
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
2011-05-17 22:29:00 +02:00
ret.submenu = a.submenu or b.menu_submenu or b.submenu or
fallback.menu_submenu or fallback.submenu or " ▶ "
2011-03-30 23:11:41 +02:00
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
2011-04-14 07:04:48 +02:00
ret.font = a.font or b.font or fallback.font
2011-03-31 11:56:11 +02:00
for _ , prop in ipairs ( { " width " , " height " , " menu_width " } ) do
if type ( ret [ prop ] ) ~= " number " then ret [ prop ] = tonumber ( ret [ prop ] ) end
end
2011-03-30 23:11:41 +02:00
return ret
end
2008-10-22 14:22:48 +02:00
2008-10-24 22:31:14 +02:00
2011-03-30 23:11:41 +02:00
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
2008-10-22 14:22:48 +02:00
2011-03-30 23:11:41 +02:00
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
2008-10-22 14:22:48 +02:00
2011-03-30 23:11:41 +02:00
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
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
2008-10-22 14:22:48 +02:00
2011-03-30 23:11:41 +02:00
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
2009-03-04 19:42:25 +01:00
end
2011-03-30 23:11:41 +02:00
menu.wibox . x = menu.x
menu.wibox . y = menu.y
2009-03-04 19:42:25 +01:00
end
2009-03-09 14:14:01 +01:00
2011-03-30 23:11:41 +02:00
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 ]
2009-03-09 14:14:01 +01:00
end
2011-03-30 23:11:41 +02:00
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
2009-03-09 14:14:01 +01:00
end
2011-03-30 23:11:41 +02:00
return false
2008-10-22 14:22:48 +02:00
end
2011-03-30 23:11:41 +02:00
local function check_access_key ( menu , key )
for i , item in ipairs ( menu.items ) do
if item.akey == key then
menu : item_enter ( i )
2011-05-02 05:30:59 +02:00
menu : exec ( i , { exec = true } )
2011-03-30 23:11:41 +02:00
return
end
end
if menu.parent then
check_access_key ( menu.parent , key )
end
end
local function grabber ( mod , key , event )
2012-03-01 21:43:29 +01:00
if event ~= " press " then return end
2011-03-30 23:11:41 +02:00
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 )
2011-05-02 05:30:59 +02:00
elseif sel > 0 and util.table . hasitem ( menu_keys.enter , key ) then
2011-03-30 23:11:41 +02:00
cur_menu : exec ( sel )
2011-05-02 05:30:59 +02:00
elseif sel > 0 and util.table . hasitem ( menu_keys.exec , key ) then
cur_menu : exec ( sel , { exec = true } )
2011-03-30 23:11:41 +02:00
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
2008-10-22 14:22:48 +02:00
end
2011-03-30 23:11:41 +02:00
2011-05-02 05:30:59 +02:00
function exec ( menu , num , opts )
opts = opts or { }
2011-03-30 23:11:41 +02:00
local item = menu.items [ num ]
if not item then return end
local cmd = item.cmd
2009-02-23 12:04:27 +01:00
if type ( cmd ) == " table " then
2011-05-02 05:30:59 +02:00
local action = cmd.cmd
2009-03-30 23:45:29 +02:00
if # cmd == 0 then
2011-05-02 05:30:59 +02:00
if opts.exec and action and type ( action ) == " function " then
action ( )
end
2009-03-30 23:45:29 +02:00
return
end
2009-03-04 19:42:25 +01:00
if not menu.child [ num ] then
2011-03-30 23:11:41 +02:00
menu.child [ num ] = new ( cmd , menu )
2008-11-10 19:09:20 +01:00
end
2011-05-02 05:30:59 +02:00
local can_invoke_action = opts.exec and
action and type ( action ) == " function " and
( not opts.mouse or ( opts.mouse and ( menu.auto_expand or
( menu.active_child == menu.child [ num ] and
menu.active_child . wibox.visible ) ) ) )
if can_invoke_action then
local visible = action ( menu.child [ num ] , item )
if not visible then
get_root ( menu ) : hide ( )
return
else
menu.child [ num ] : update ( )
end
end
if menu.active_child and menu.active_child ~= menu.child [ num ] then
2009-03-04 19:42:25 +01:00
menu.active_child : hide ( )
2008-10-30 12:46:49 +01:00
end
2009-03-04 19:42:25 +01:00
menu.active_child = menu.child [ num ]
2011-05-02 05:30:59 +02:00
if not menu.active_child . visible then
menu.active_child : show ( )
end
2009-02-23 12:04:27 +01:00
elseif type ( cmd ) == " string " then
2011-03-30 23:11:41 +02:00
get_root ( menu ) : hide ( )
2009-02-23 12:04:27 +01:00
util.spawn ( cmd )
elseif type ( cmd ) == " function " then
2011-03-30 23:11:41 +02:00
local visible , action = cmd ( item , menu )
if not visible then
get_root ( menu ) : hide ( )
else
menu : update ( )
if menu.items [ num ] then
2011-05-02 05:30:59 +02:00
menu : item_enter ( num , opts )
2011-03-30 23:11:41 +02:00
end
end
if action and type ( action ) == " function " then
action ( )
end
2008-10-22 14:22:48 +02:00
end
end
2011-05-02 05:30:59 +02:00
function item_enter ( menu , num , opts )
opts = opts or { }
2011-03-30 23:11:41 +02:00
local item = menu.items [ num ]
if num == nil or menu.sel == num or not item then
2009-03-04 19:42:25 +01:00
return
elseif menu.sel then
2011-03-30 23:11:41 +02:00
menu : item_leave ( menu.sel )
2009-03-04 19:42:25 +01:00
end
2011-03-30 23:11:41 +02:00
--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 )
2009-03-09 14:14:01 +01:00
cur_menu = menu
2011-03-30 23:11:41 +02:00
menu.sel = num
2009-03-04 19:42:25 +01:00
2011-05-02 05:30:59 +02:00
if menu.auto_expand and opts.hover then
2009-03-04 19:42:25 +01:00
if menu.active_child then
menu.active_child : hide ( )
menu.active_child = nil
2009-02-22 16:01:39 +01:00
end
2011-03-30 23:11:41 +02:00
if type ( item.cmd ) == " table " then
2011-05-07 16:04:04 +02:00
menu : exec ( num , opts )
2009-02-22 16:01:39 +01:00
end
end
2009-02-23 12:04:27 +01:00
end
2011-03-30 23:11:41 +02:00
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
2009-11-26 12:47:39 +01:00
end
2011-03-30 23:11:41 +02:00
--- Show a menu.
-- @param menu The menu to show.
-- @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
if not set_size ( menu ) then return end
set_coords ( menu , screen_index , coords )
2012-03-01 20:12:56 +01:00
if not cur_menu then
2011-03-30 23:11:41 +02:00
capi.keygrabber . run ( grabber )
end
cur_menu = menu
menu.wibox . visible = true
end
--- Hide a menu popup.
-- @param menu The menu to hide.
function hide ( menu )
-- Remove items from screen
for i = 1 , # menu.items do
menu : item_leave ( i )
end
if menu.active_child then
menu.active_child : hide ( )
menu.active_child = nil
end
menu.sel = nil
if cur_menu == menu then
cur_menu = cur_menu.parent
end
2012-03-01 20:12:56 +01:00
if not cur_menu then
2011-03-30 23:11:41 +02:00
capi.keygrabber . stop ( )
end
menu.wibox . visible = false
end
--- Toggle menu visibility.
-- @param menu The menu to show if it's hidden, or to hide if it's shown.
-- @param args.coords Menu position {x,y}
function toggle ( menu , args )
if menu.wibox . visible then
menu : hide ( )
2009-11-26 12:47:39 +01:00
else
2011-03-30 23:11:41 +02:00
menu : show ( args )
end
end
--- Update menu content
-- @param menu The mnenu to update.
function update ( menu )
if menu.wibox . visible then
2012-03-01 20:12:56 +01:00
menu : show ( { coords = { x = menu.x , y = menu.y } } )
2009-03-09 14:14:01 +01:00
end
end
2011-03-30 23:11:41 +02:00
--- 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 )
2008-10-22 14:22:48 +02:00
-- Create bindings
2011-03-30 23:11:41 +02:00
item._background : buttons ( util.table . join (
button ( { } , 3 , function ( ) menu : hide ( ) end ) ,
button ( { } , 1 , function ( )
local num = util.table . hasitem ( menu.items , item )
2011-05-02 05:30:59 +02:00
menu : item_enter ( num , { mouse = true } )
menu : exec ( num , { exec = true , mouse = true } )
2011-03-30 23:11:41 +02:00
end ) ) )
item._mouse = function ( )
local num = util.table . hasitem ( menu.items , item )
2011-05-02 05:30:59 +02:00
menu : item_enter ( num , { hover = true , moue = true } )
2011-03-30 23:11:41 +02:00
end
item.widget : connect_signal ( " mouse::enter " , item._mouse )
2008-10-22 14:22:48 +02:00
2011-03-30 23:11:41 +02:00
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 )
2011-03-31 12:36:32 +02:00
item.widget . visible = false
2011-03-30 23:11:41 +02:00
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
-- @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 = { }
2008-12-18 18:02:54 +01:00
-- Create the item label widget
2010-10-06 14:21:19 +02:00
local label = wibox.widget . textbox ( )
2009-11-26 12:47:39 +01:00
local key = ' '
2011-04-14 07:04:48 +02:00
label : set_font ( args.theme . font )
2011-03-30 23:11:41 +02:00
label : set_markup ( string.gsub (
util.escape ( args.text ) , " &(%w) " ,
function ( l )
key = string.lower ( l )
return " <u> " .. l .. " </u> "
end , 1 ) )
2008-12-18 18:02:54 +01:00
-- Set icon if needed
2011-03-30 23:11:41 +02:00
local icon , iconbox
2010-10-06 14:21:19 +02:00
local margin = wibox.layout . margin ( )
margin : set_widget ( label )
2011-03-30 23:11:41 +02:00
if args.icon then
icon = args.icon
if type ( icon ) == " string " then
2012-01-29 15:17:51 +01:00
icon = capi.awesome . load_image ( icon )
2011-03-30 23:11:41 +02:00
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
2010-09-29 16:06:44 +02:00
local w , h
2011-03-30 23:11:41 +02:00
if ( ( args.theme . height / ih ) * iw ) > args.theme . width then
w , h = args.theme . height , ( args.theme . height / iw ) * ih
2008-12-18 18:02:54 +01:00
else
2011-03-30 23:11:41 +02:00
w , h = ( args.theme . height / ih ) * iw , args.theme . height
2008-12-18 18:02:54 +01:00
end
2010-09-29 16:06:44 +02:00
-- 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 )
2011-03-30 23:11:41 +02:00
cr : scale ( w / iw , h / ih )
2010-09-29 16:06:44 +02:00
cr : set_source ( icon , 0 , 0 )
cr : paint ( )
icon = img
2008-10-23 11:19:46 +02:00
end
2010-10-06 14:21:19 +02:00
iconbox = wibox.widget . imagebox ( )
2011-03-30 23:11:41 +02:00
if iconbox : set_image ( icon ) then
margin : set_left ( 2 )
else
2011-03-04 22:07:36 +01:00
iconbox = nil
end
end
if not iconbox then
2011-03-30 23:11:41 +02:00
margin : set_left ( args.theme . height + 2 )
2008-10-22 14:22:48 +02:00
end
-- Create the submenu icon widget
2011-05-17 22:29:00 +02:00
local submenu
2011-03-30 23:11:41 +02:00
if type ( args.cmd ) == " table " then
if args.theme . submenu_icon then
2011-05-17 22:29:00 +02:00
submenu = wibox.widget . imagebox ( )
submenu : set_image (
2012-01-29 15:17:51 +01:00
capi.awesome . load_image (
2011-03-30 23:11:41 +02:00
args.theme . submenu_icon ) )
2011-05-17 22:29:00 +02:00
else
submenu = wibox.widget . textbox ( )
submenu : set_font ( args.theme . font )
submenu : set_text ( args.theme . submenu )
2010-10-06 14:21:19 +02:00
end
2008-10-22 14:22:48 +02:00
end
-- Add widgets to the wibox
2010-10-06 14:21:19 +02:00
local left = wibox.layout . fixed.horizontal ( )
2009-08-25 18:13:19 +02:00
if iconbox then
2010-10-06 14:21:19 +02:00
left : add ( iconbox )
end
-- This contains the label
left : add ( margin )
local layout = wibox.layout . align.horizontal ( )
2010-10-07 10:15:29 +02:00
layout : set_middle ( left )
2011-05-17 22:29:00 +02:00
if submenu then
layout : set_right ( submenu )
2008-10-24 22:31:14 +02:00
end
2011-03-30 23:11:41 +02:00
return table_update ( ret , {
label = label ,
2011-05-17 22:29:00 +02:00
sep = submenu ,
2011-03-30 23:11:41 +02:00
icon = iconbox ,
widget = layout ,
cmd = args.cmd ,
akey = key ,
} )
2008-11-07 15:27:35 +01:00
end
2008-10-24 09:10:42 +02:00
2011-03-30 23:11:41 +02:00
--------------------------------------------------------------------------------
2008-10-24 09:10:42 +02:00
2011-03-30 23:11:41 +02:00
--- Create a menu popup.
-- @param args Table containing the menu informations.<br/>
2011-01-26 21:21:53 +01:00
-- <ul>
2011-03-30 23:11:41 +02:00
-- <li> Key items: Table containing the displayed items. Each element is a table by default (when element 'new' is awful.menu.entry) containing: item name, triggered action, submenu table or function, item icon (optional). </li>
-- <li> Keys theme.[fg|bg]_[focus|normal], theme.border_color, theme.border_width, theme.submenu_icon, theme.height and theme.width override the default display for your menu and/or of your menu entry, each of them are optional. </li>
2011-01-26 21:21:53 +01:00
-- <li> Key auto_expand controls the submenu auto expand behaviour by setting it to true (default) or false. </li>
-- </ul>
2008-10-23 11:19:46 +02:00
-- @param parent Specify the parent menu if we want to open a submenu, this value should never be set by the user.
2011-01-26 21:42:58 +01:00
-- @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
-- <code>match_any</code> instead of <code>match</code>, menu of clients with
-- different classes can also be build.
--
-- <p><code>
-- function terminal_menu () <br/>
-- terms = {} <br/>
-- for i, c in pairs(client.get()) do <br/>
-- if awful.rules.match(c, {class = "URxvt"}) then <br/>
-- terms[i] = <br/>
-- {c.name, <br/>
-- function() <br/>
-- awful.tag.viewonly(c:tags()[1]) <br/>
-- client.focus = c <br/>
-- end, <br/>
-- c.icon <br/>
-- } <br/>
-- end <br/>
-- end <br/>
2012-03-01 20:12:56 +01:00
-- awful.menu(terms):show() <br/>
2011-01-26 21:42:58 +01:00
-- end <br/>
--</code></p>
2011-03-30 23:11:41 +02:00
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 ) } )
2009-02-23 14:19:49 +01:00
if parent then
2011-03-30 23:11:41 +02:00
menu.auto_expand = parent.auto_expand
elseif args.auto_expand ~= nil then
menu.auto_expand = args.auto_expand
2009-02-23 14:12:28 +01:00
else
2011-03-30 23:11:41 +02:00
menu.auto_expand = true
2009-02-23 14:12:28 +01:00
end
2008-10-22 14:22:48 +02:00
-- Create items
2011-03-30 23:11:41 +02:00
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
2008-10-22 14:22:48 +02:00
end
2011-03-30 23:11:41 +02:00
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 )
menu.x = menu.wibox . x
menu.y = menu.wibox . y
return menu
2009-04-17 18:08:52 +02:00
end
2009-07-15 15:57:31 +02:00
2011-03-30 23:11:41 +02:00
setmetatable ( _M , { __call = function ( _ , ... ) return new ( ... ) end } )
2009-07-15 15:57:31 +02:00
2011-09-11 16:50:01 +02:00
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80