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 = { }
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
theme.submenu_icon = custom.submenu_icon or beautiful.menu_submenu_icon or " @AWESOME_ICON_PATH@/submenu.png "
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
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
2008-10-30 12:46:49 +01:00
if data.child and data.child . id ~= action [ 1 ] then
destroy ( data.child )
end
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 " ,
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 ) ,
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 )
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 " ,
name = data.id .. " label " .. num ,
align = " flex "
} )
label.text = string.format ( " %s " , item_info [ 1 ] )
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
local submenu = nil
if type ( item_info [ 2 ] ) == " table " then
submenu = widget ( { type = " imagebox " , name = " submenu " , align = " right " } )
2008-10-24 22:31:14 +02:00
submenu.image = 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 : 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-24 22:31:14 +02:00
y = data.y + ( num - 1 ) * ( data.h + data.theme . border_width )
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.
2008-10-24 22:31:14 +02:00
-- @param menu Menu table, see new() function for more informations
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
menu.id = " Clients "
menu.items = cls_t
return new ( menu )
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
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-10-24 09:10:42 +02:00
if data.parent then
data.w = data.parent . w
data.h = data.parent . h
2008-10-27 12:05:34 +01:00
local p_w = ( data.h + data.theme . border_width ) * ( data.num - 1 )
2008-10-24 22:31:14 +02:00
local m_h = data.theme . border_width + ( data.h + data.theme . border_width ) * data.nb_items
local m_w = data.w + data.theme . border_width
data.y = data.parent . y + p_w + m_h > screen_h and screen_h - m_h or data.parent . y + p_w
data.x = data.parent . x + data.w * 2 + data.theme . border_width > screen_w and data.parent . x - m_w or data.parent . x + m_w
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 22:31:14 +02:00
local m_h = data.theme . border_width + ( data.h + data.theme . border_width ) * data.nb_items
local m_w = data.w + data.theme . border_width * 2
data.y = data.y + m_h > screen_h and screen_h - m_h or data.y
data.x = data.x + m_w > screen_w and screen_w - m_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-30 12:46:49 +01:00
-- @param menu Table containing the menu informations. Key id: string naming your menu, only one menu with the same id can be displayed on screen at the same time. Key items: Table containing the displayed items, each element is a tab containing: item name, tiggered action, submenu table or function, item icon (optional). Key menu_toggle (optional, false by default): boolean setting wether the menu should be re-opened or toggle its opened/closed state when mouse button 1 is pressed. 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-23 15:11:13 +02:00
data.id = menu.id
2008-10-30 12:46:49 +01:00
data.menu_toggle = ( parent and parent.menu_toggle ) or menu.menu_toggle or false
-- Close the menu if it was already opened
if menus [ data.id ] then
destroy ( menus [ data.id ] )
if data.menu_toggle then
return
end
end
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
2008-10-24 22:31:14 +02:00
data.theme = parent and parent.theme or load_theme ( menu )
2008-10-24 09:10:42 +02:00
data.parent = parent and parent or nil
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
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-30 12:46:49 +01:00
menus [ data.id ] = data
2008-10-22 14:22:48 +02:00
return data
end
2008-10-27 12:05:34 +01:00
--- Close a menu popup.
-- @param id The name of the menu to close
function close ( id )
destroy ( menus [ id ] )
end