2008-10-22 14:22:48 +02:00
---------------------------------------------------------------------------
-- @author Damien Leone <damien.leone@gmail.com>
-- @copyright 2008 Damien Leone
-- @release @AWESOME_VERSION@
---------------------------------------------------------------------------
-- Grab environment we need
2008-10-23 11:19:46 +02:00
local pairs = pairs
2008-10-22 14:22:48 +02:00
local table = table
local type = type
local wibox = wibox
local image = image
local string = string
local widget = widget
local button = button
2008-10-23 11:19:46 +02:00
local capi = { screen = screen , mouse = mouse , client = client }
2008-10-22 14:22:48 +02:00
local util = require ( " awful.util " )
2008-10-23 11:19:46 +02:00
local tags = require ( " awful.tag " )
2008-10-22 14:22:48 +02:00
local awbeautiful = require ( " awful.beautiful " )
--- Menu module for awful
module ( " awful.menu " )
-- Table containing all currently opened menus
local menus = { }
-- Theme table
local theme
local function load_theme ( )
local beautiful
beautiful = awbeautiful.get ( )
theme = { }
theme.fg_focus = beautiful.menu_fg_focus or beautiful.fg_focus
theme.bg_focus = beautiful.menu_bg_focus or beautiful.bg_focus
theme.fg_normal = beautiful.menu_fg_normal or beautiful.fg_normal
theme.bg_normal = beautiful.menu_bg_normal or beautiful.bg_normal
theme.submenu_icon = beautiful.menu_submenu_icon or " @AWESOME_ICON_PATH@/submenu.png "
theme.menu_height = beautiful.menu_height or 15
theme.menu_width = beautiful.menu_width or 100
theme.border = beautiful.menu_border_color or beautiful.border_normal
theme.border_width = beautiful.menu_border_width or beautiful.border_width
end
local function mouse_enter ( w )
w.fg = theme.fg_focus
w.bg = theme.bg_focus
end
local function mouse_leave ( w )
w.fg = theme.fg_normal
w.bg = theme.bg_normal
end
local function destroy ( data )
if data then
-- Remove items from screen
for i = 1 , # data.items do
data.items [ i ] . screen = nil
end
-- Clean memory, dirty but I'm lazy
for i = 1 , # data.items do
table.remove ( data.items )
end
destroy ( data.child )
-- Remove menu from menus table
menus [ data.id ] = nil
end
end
local function get_parents ( data )
local p_data = data
-- Get the elder parent so when you kill
-- it he will destroy the whole family
while p_data.parent do
p_data = p_data.parent
end
return p_data
end
local function exec ( data , action , num )
if type ( action [ 2 ] ) == " table " then
destroy ( data.child )
2008-10-23 15:11:13 +02:00
data.child = new ( { id = action [ 1 ] , items = action [ 2 ] } , data , num )
2008-10-22 14:22:48 +02:00
elseif type ( action [ 2 ] ) == " string " then
destroy ( get_parents ( data ) )
util.spawn ( action [ 2 ] )
2008-10-22 17:52:51 +02:00
elseif type ( action [ 2 ] ) == " function " then
2008-10-23 11:19:46 +02:00
destroy ( get_parents ( data ) )
2008-10-22 17:52:51 +02:00
action [ 2 ] ( )
2008-10-22 14:22:48 +02:00
end
end
local function add_item ( data , num , item_info )
local item = wibox ( {
name = data.id .. " item " .. num ,
position = " floating " ,
fg = theme.fg_normal ,
bg = theme.bg_normal ,
border_color = theme.border ,
border_width = theme.border_width
} )
-- Create bindings
local bindings = {
button ( { } , 1 , function ( ) exec ( data , item_info , num ) end ) ,
button ( { } , 3 , function ( ) destroy ( data ) end )
}
-- Create the item icon widget
local icon = nil
if item_info [ 3 ] then
icon = widget ( { type = " imagebox " , name = " icon " , align = " left " } )
2008-10-23 11:19:46 +02:00
if type ( item_info [ 3 ] ) == " string " then
icon.image = image ( item_info [ 3 ] )
else
icon.image = item_info [ 3 ]
end
2008-10-22 16:20:32 +02:00
else
icon = widget ( { type = " textbox " , name = " icon " , align = " left " } )
2008-10-23 15:11:13 +02:00
icon.width = data.h
2008-10-22 14:22:48 +02:00
end
2008-10-22 16:20:32 +02:00
icon : buttons ( bindings )
function icon . mouse_enter ( ) mouse_enter ( item ) end
function icon . mouse_leave ( ) mouse_leave ( item ) end
2008-10-22 14:22:48 +02:00
-- Create the item label widget
local label = widget ( {
type = " textbox " ,
name = data.id .. " label " .. num ,
align = " flex "
} )
label.text = string.format ( " %s " , item_info [ 1 ] )
label : buttons ( bindings )
function label . mouse_enter ( ) mouse_enter ( item ) end
function label . mouse_leave ( ) mouse_leave ( item ) end
-- Create the submenu icon widget
local submenu = nil
if type ( item_info [ 2 ] ) == " table " then
submenu = widget ( { type = " imagebox " , name = " submenu " , align = " right " } )
submenu.image = image ( theme.submenu_icon )
submenu : buttons ( bindings )
function submenu . mouse_enter ( ) mouse_enter ( item ) end
function submenu . mouse_leave ( ) mouse_leave ( item ) end
end
-- Add widgets to the wibox
2008-10-23 11:19:46 +02:00
item.widgets = { icon , label , submenu }
2008-10-22 14:22:48 +02:00
item : geometry ( {
2008-10-23 15:11:13 +02:00
width = data.w ,
height = data.h ,
2008-10-22 14:22:48 +02:00
x = data.x ,
2008-10-23 15:11:13 +02:00
y = data.y + data.h * ( num - 1 )
2008-10-22 14:22:48 +02:00
} )
item.ontop = true
item.screen = data.screen
return item
end
2008-10-23 11:19:46 +02:00
--- Open a popup menu with running clients.
function clients ( )
local cls = capi.client . get ( )
local cls_t = { }
for k , c in pairs ( cls ) do
cls_t [ # cls_t + 1 ] = { c.name ,
function ( )
if not c : isvisible ( ) then
tags.viewmore ( c : tags ( ) , c.screen )
end
capi.client . focus = c
end ,
c.icon }
end
2008-10-23 15:11:13 +02:00
return new ( { id = " Clients " , items = cls_t } )
2008-10-23 11:19:46 +02:00
end
2008-10-24 09:10:42 +02:00
local function set_coords ( data )
local m_coords = capi.mouse . coords ( )
local s_geometry = capi.screen [ data.screen ] . workarea
2008-10-24 11:04:02 +02:00
local screen_w = s_geometry.x + s_geometry.width
local screen_h = s_geometry.height
2008-10-24 09:10:42 +02:00
if data.parent then
local t , t2
data.w = data.parent . w
data.h = data.parent . h
t = data.w + theme.border_width
2008-10-24 11:04:02 +02:00
data.x = data.parent . x + data.w * 2 + theme.border_width > screen_w and data.parent . x - t or data.parent . x + t
2008-10-24 09:10:42 +02:00
t = data.h * ( data.num - 1 )
t2 = data.h * ( data.nb_items - 1 )
2008-10-24 11:04:02 +02:00
data.y = data.parent . y + t + t2 > screen_h and screen_h - t2 or data.parent . y + t
2008-10-24 09:10:42 +02:00
else
data.y = m_coords.y < s_geometry.y and s_geometry.y or m_coords.y
data.x = m_coords.x < s_geometry.x and s_geometry.x or m_coords.x
2008-10-24 11:04:02 +02:00
data.y = data.y + data.h > screen_h and screen_h - data.h or data.y
data.x = data.x + data.w > screen_w and screen_w - data.w or data.x
2008-10-24 09:10:42 +02:00
end
end
2008-10-23 11:19:46 +02:00
--- Open a menu popup.
2008-10-23 15:11:13 +02:00
-- @param menu Table containing the menu informations. Element id: string naming your menu, only one menu with the same id can be displayed on screen at the same time. Element items: Table containing the displayed items, each element is a tab containing: item name, tiggered action or submenu table, item icon (optional). Elements width and height: force the geometry of your menu, if one (or both) of these elements is not specified, the default values will be used.
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.
-- @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.
2008-10-23 15:11:13 +02:00
function new ( menu , parent , num )
2008-10-22 14:22:48 +02:00
-- Load config only one time
if not theme then
load_theme ( )
end
-- Close the menu if it was already opened
2008-10-23 15:11:13 +02:00
if menus [ menu.id ] then
destroy ( menus [ menu.id ] )
2008-10-22 14:22:48 +02:00
end
-- Create a table to store our menu informations
local data = { }
2008-10-23 15:11:13 +02:00
data.id = menu.id
2008-10-22 14:22:48 +02:00
data.screen = capi.mouse . screen
data.items = { }
data.child = nil
2008-10-24 09:10:42 +02:00
data.nb_items = # menu.items
data.num = num and num or 1
data.parent = parent and parent or nil
data.h = parent and parent.h or ( menu.height and menu.height or theme.menu_height )
data.w = parent and parent.w or ( menu.width and menu.width or theme.menu_width )
2008-10-22 14:22:48 +02:00
2008-10-24 09:10:42 +02:00
set_coords ( data )
2008-10-22 14:22:48 +02:00
-- Create items
2008-10-23 15:11:13 +02:00
for k , v in pairs ( menu.items ) do
2008-10-23 11:19:46 +02:00
table.insert ( data.items , add_item ( data , k , v ) )
2008-10-22 14:22:48 +02:00
end
-- Add menu to menus table
2008-10-23 15:11:13 +02:00
menus [ menu.id ] = data
2008-10-22 14:22:48 +02:00
return data
end