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>
-- @copyright 2008 Damien Leone, Julien Danjou
2008-10-22 14:22:48 +02:00
-- @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 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-11-13 11:53:41 +01:00
local awbeautiful = require ( " beautiful " )
2008-10-22 14:22:48 +02:00
--- Menu module for awful
module ( " awful.menu " )
2008-10-24 22:31:14 +02:00
local function load_theme ( custom )
local theme = { }
2008-10-22 14:22:48 +02:00
local beautiful
2008-10-24 22:31:14 +02:00
2008-10-22 14:22:48 +02:00
beautiful = awbeautiful.get ( )
2008-10-24 22:31:14 +02:00
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
2008-11-10 11:57:20 +01:00
theme.submenu_icon = custom.submenu_icon or beautiful.menu_submenu_icon
2008-10-22 14:22:48 +02:00
2008-10-24 22:31:14 +02:00
theme.menu_height = custom.height or beautiful.menu_height or 15
theme.menu_width = custom.width or beautiful.menu_width or 100
2008-10-22 14:22:48 +02:00
2008-10-24 22:31:14 +02:00
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
2008-10-22 14:22:48 +02:00
2008-10-24 22:31:14 +02:00
return theme
2008-10-22 14:22:48 +02:00
end
2008-10-24 22:31:14 +02:00
local function mouse_enter ( w , theme )
2008-10-22 14:22:48 +02:00
w.fg = theme.fg_focus
w.bg = theme.bg_focus
end
2008-10-24 22:31:14 +02:00
local function mouse_leave ( w , theme )
2008-10-22 14:22:48 +02:00
w.fg = theme.fg_normal
w.bg = theme.bg_normal
end
2008-11-07 15:27:35 +01:00
--- Hide a menu popup.
-- @param menu The menu to hide.
function hide ( menu )
2008-11-10 19:09:20 +01:00
-- Remove items from screen
for i = 1 , # menu.items do
-- Call mouse_leave to clear menu entry
for k , w in pairs ( menu.items [ i ] . widgets ) do
w.mouse_leave ( )
2008-10-22 14:22:48 +02:00
end
2008-11-10 19:09:20 +01:00
menu.items [ i ] . screen = nil
end
if menu.active_child then
menu.active_child : hide ( )
active_child = nil
2008-10-22 14:22:48 +02:00
end
end
2008-11-07 15:27:35 +01:00
--- Get the elder parent so for example when you kill
-- it, it will destroy the whole family.
2008-10-22 14:22:48 +02:00
local function get_parents ( data )
2008-11-07 15:27:35 +01:00
if data.parent then
return get_parents ( data.parent )
2008-10-22 14:22:48 +02:00
end
2008-11-07 15:27:35 +01:00
return data
2008-10-22 14:22:48 +02:00
end
local function exec ( data , action , num )
if type ( action [ 2 ] ) == " table " then
2008-11-10 19:09:20 +01:00
if not data.child [ num ] then
data.child [ num ] = new ( { items = action [ 2 ] } , data , num )
end
if data.active_child then
data.active_child : hide ( )
2008-10-30 12:46:49 +01:00
end
2008-11-10 19:09:20 +01:00
data.active_child = data.child [ num ]
data.active_child : show ( )
2008-10-22 14:22:48 +02:00
elseif type ( action [ 2 ] ) == " string " then
2008-11-10 19:09:20 +01:00
get_parents ( data ) : hide ( )
2008-10-22 14:22:48 +02:00
util.spawn ( action [ 2 ] )
2008-10-22 17:52:51 +02:00
elseif type ( action [ 2 ] ) == " function " then
2008-11-10 19:09:20 +01:00
get_parents ( data ) : hide ( )
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 ( {
position = " floating " ,
2008-10-24 22:31:14 +02:00
fg = data.theme . fg_normal ,
bg = data.theme . bg_normal ,
border_color = data.theme . border ,
border_width = data.theme . border_width
2008-10-22 14:22:48 +02:00
} )
-- Create bindings
local bindings = {
button ( { } , 1 , function ( ) exec ( data , item_info , num ) end ) ,
2008-11-07 15:27:35 +01:00
button ( { } , 3 , function ( ) hide ( data ) end )
2008-10-22 14:22:48 +02:00
}
-- Create the item icon widget
2008-11-08 14:32:50 +01:00
local icon
2008-11-07 15:27:35 +01:00
if item_info [ 3 ] then
2008-11-08 14:32:50 +01:00
icon = widget ( { type = " imagebox " , 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-11-08 14:32:50 +01:00
else
icon = widget ( { type = " textbox " , align = " left " } )
icon.width = data.h
2008-10-22 14:22:48 +02:00
end
2008-10-22 16:20:32 +02:00
icon : buttons ( bindings )
2008-10-24 22:31:14 +02:00
function icon . mouse_enter ( ) mouse_enter ( item , data.theme ) end
function icon . mouse_leave ( ) mouse_leave ( item , data.theme ) end
2008-10-22 16:20:32 +02:00
2008-10-22 14:22:48 +02:00
-- Create the item label widget
local label = widget ( {
type = " textbox " ,
align = " flex "
} )
2008-11-07 15:27:35 +01:00
label.text = " " .. item_info [ 1 ]
2008-10-22 14:22:48 +02:00
label : buttons ( bindings )
2008-10-24 22:31:14 +02:00
function label . mouse_enter ( ) mouse_enter ( item , data.theme ) end
function label . mouse_leave ( ) mouse_leave ( item , data.theme ) end
2008-10-22 14:22:48 +02:00
-- Create the submenu icon widget
2008-11-07 15:27:35 +01:00
local submenu
2008-10-22 14:22:48 +02:00
if type ( item_info [ 2 ] ) == " table " then
2008-11-07 15:27:35 +01:00
submenu = widget ( { type = " imagebox " , align = " right " } )
2008-11-10 11:57:20 +01:00
submenu.image = data.theme . submenu_icon and image ( data.theme . submenu_icon )
2008-10-22 14:22:48 +02:00
submenu : buttons ( bindings )
2008-10-24 22:31:14 +02:00
function submenu . mouse_enter ( ) mouse_enter ( item , data.theme ) end
function submenu . mouse_leave ( ) mouse_leave ( item , data.theme ) end
2008-10-22 14:22:48 +02:00
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.ontop = true
return item
end
2008-11-07 15:27:35 +01:00
--- Build a popup menu with running clients and shows it.
2008-10-24 22:31:14 +02:00
-- @param menu Menu table, see new() function for more informations
2008-11-07 15:27:35 +01:00
-- @return The menu.
2008-10-24 22:31:14 +02:00
function clients ( menu )
2008-10-23 11:19:46 +02:00
local cls = capi.client . get ( )
local cls_t = { }
for k , c in pairs ( cls ) do
2008-10-27 12:05:34 +01:00
cls_t [ # cls_t + 1 ] = { util.escape ( c.name ) or " " ,
2008-10-23 11:19:46 +02:00
function ( )
if not c : isvisible ( ) then
tags.viewmore ( c : tags ( ) , c.screen )
end
capi.client . focus = c
end ,
c.icon }
end
2008-10-24 22:31:14 +02:00
if not menu then
menu = { }
end
2008-11-07 15:27:35 +01:00
menu.items = cls_t
2008-10-24 22:31:14 +02:00
2008-11-07 15:27:35 +01:00
m = new ( menu )
m : show ( )
return m
2008-10-23 11:19:46 +02:00
end
2008-11-07 15:27:35 +01:00
local function set_coords ( menu , screen_idx )
local s_geometry = capi.screen [ screen_idx ] . workarea
2008-10-24 11:04:02 +02:00
local screen_w = s_geometry.x + s_geometry.width
2008-10-24 22:31:14 +02:00
local screen_h = s_geometry.y + s_geometry.height
2008-10-24 11:04:02 +02:00
2008-11-07 15:27:35 +01:00
if menu.parent then
menu.w = menu.parent . w
menu.h = menu.parent . h
2008-12-12 00:01:43 +01:00
local p_w = menu.h * ( menu.num - 1 )
local m_h = menu.h * # menu.items
local m_w = menu.w
2008-11-07 15:27:35 +01:00
menu.y = menu.parent . y + p_w + m_h > screen_h and screen_h - m_h or menu.parent . y + p_w
2008-12-12 00:01:43 +01:00
menu.x = menu.parent . x + menu.w > screen_w and menu.parent . x - m_w or menu.parent . x + m_w
2008-10-24 09:10:42 +02:00
else
2008-11-07 15:27:35 +01:00
local m_coords = capi.mouse . coords ( )
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-12-12 00:01:43 +01:00
local m_h = menu.h * # menu.items
local m_w = menu.w
2008-11-07 15:27:35 +01:00
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.
function show ( menu )
local screen_index = capi.mouse . screen
set_coords ( menu , screen_index )
for num , item in pairs ( menu.items ) do
item : geometry ( {
width = menu.w ,
height = menu.h ,
x = menu.x ,
2008-12-12 00:01:43 +01:00
y = menu.y + ( num - 1 ) * menu.h
2008-11-07 15:27:35 +01:00
} )
item.screen = screen_index
end
end
2008-10-24 09:10:42 +02:00
2008-11-07 15:27:35 +01:00
--- Toggle menu visibility.
-- @param menu The menu to show if it's hidden, or to hide if it's shown.
function toggle ( menu )
if menu.items [ 1 ] . screen then
hide ( menu )
else
show ( menu )
2008-10-24 09:10:42 +02:00
end
end
2008-10-23 11:19:46 +02:00
--- Open a menu popup.
2008-11-07 15:27:35 +01:00
-- @param menu Table containing the menu informations. Key items: Table containing the displayed items, each element is a tab containing: item name, tiggered action, submenu table or function, item icon (optional). Keys [fg|bg]_[focus|normal], border, border_width, submenu_icon, height and width override the default display for your menu, each of them are optional.
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
-- Create a table to store our menu informations
local data = { }
2008-10-30 12:46:49 +01:00
2008-10-22 14:22:48 +02:00
data.items = { }
2008-11-07 15:27:35 +01:00
data.num = num or 1
2008-10-24 22:31:14 +02:00
data.theme = parent and parent.theme or load_theme ( menu )
2008-11-07 15:27:35 +01:00
data.parent = parent
2008-11-10 19:09:20 +01:00
data.child = { }
2008-10-24 22:31:14 +02:00
data.h = parent and parent.h or data.theme . menu_height
data.w = parent and parent.w or data.theme . menu_width
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
2008-11-07 15:27:35 +01:00
-- Set methods
data.hide = hide
data.show = show
data.toggle = toggle
2008-10-22 14:22:48 +02:00
return data
end