Repository navigation
Expand file tree
/
Copy pathmenu.lua.in
More file actions
268 lines (228 loc) · 8.53 KB
/
Copy pathmenu.lua.in
File metadata and controls
268 lines (228 loc) · 8.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
---------------------------------------------------------------------------
-- @author Damien Leone <damien.leone@gmail.com>
-- @author Julien Danjou <julien@danjou.info>
-- @copyright 2008 Damien Leone, Julien Danjou
-- @release @AWESOME_VERSION@
---------------------------------------------------------------------------
-- Grab environment we need
local pairs = pairs
local table = table
local type = type
local wibox = wibox
local image = image
local widget = widget
local button = button
local capi = { screen = screen, mouse = mouse, client = client }
local util = require("awful.util")
local tags = require("awful.tag")
local awbeautiful = require("beautiful")
local tonumber = tonumber
--- Menu module for awful
module("awful.menu")
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
end
local function mouse_enter(w, theme)
w.fg = theme.fg_focus
w.bg = theme.bg_focus
end
local function mouse_leave(w, theme)
w.fg = theme.fg_normal
w.bg = theme.bg_normal
end
--- Hide a menu popup.
-- @param menu The menu to hide.
function hide(menu)
-- 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()
end
menu.items[i].screen = nil
end
if menu.active_child then
menu.active_child:hide()
active_child = nil
end
end
--- Get the elder parent so for example when you kill
-- it, it will destroy the whole family.
local function get_parents(data)
if data.parent then
return get_parents(data.parent)
end
return data
end
local function exec(data, action, num)
if type(action[2]) == "table" then
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()
end
data.active_child = data.child[num]
data.active_child:show()
elseif type(action[2]) == "string" then
get_parents(data):hide()
util.spawn(action[2])
elseif type(action[2]) == "function" then
get_parents(data):hide()
action[2]()
end
end
local function add_item(data, num, item_info)
local item = wibox({
position = "floating",
fg = data.theme.fg_normal,
bg = data.theme.bg_normal,
border_color = data.theme.border,
border_width = data.theme.border_width
})
-- Create bindings
local bindings = {
button({}, 1, function () exec(data, item_info, num) end),
button({}, 3, function () hide(data) end)
}
-- Create the item label widget
local label = widget({ type = "textbox", align = "left" })
label.text = item_info[1]
label:margin({ left = data.h + 2 })
-- Set icon if needed
if item_info[3] then
local icon = type(item_info[3]) == "string" and image(item_info[3]) or item_info[3]
if icon.width > tonumber(data.h) or icon.height > tonumber(data.h) then
local width, height
if ((data.h/icon.height) * icon.width) > tonumber(data.h) then
width, height = data.h, (tonumber(data.h) / icon.width) * icon.height
else
width, height = (tonumber(data.h) / icon.height) * icon.width, data.h
end
icon = icon:crop_and_scale(0, 0, icon.width, icon.height, width, height)
end
label.bg_image = icon
end
label:buttons(bindings)
function label.mouse_enter() mouse_enter(item, data.theme) end
function label.mouse_leave() mouse_leave(item, data.theme) end
-- Create the submenu icon widget
local submenu
if type(item_info[2]) == "table" then
submenu = widget({ type = "imagebox", align = "right" })
submenu.image = data.theme.submenu_icon and image(data.theme.submenu_icon)
submenu:buttons(bindings)
function submenu.mouse_enter() mouse_enter(item, data.theme) end
function submenu.mouse_leave() mouse_leave(item, data.theme) end
end
-- Add widgets to the wibox
item.widgets = { label, submenu }
item.ontop = true
return item
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)
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
end,
c.icon }
end
if not menu then
menu = {}
end
menu.items = cls_t
m = new(menu)
m:show()
return m
end
local function set_coords(menu, screen_idx)
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
if menu.parent then
menu.w = menu.parent.w
menu.h = menu.parent.h
local p_w = menu.h * (menu.num - 1)
local m_h = menu.h * #menu.items
local m_w = menu.w
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 + menu.w > screen_w and menu.parent.x - m_w or menu.parent.x + m_w
else
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
local m_h = menu.h * #menu.items
local m_w = menu.w
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,
y = menu.y + (num - 1) * menu.h
})
item.screen = screen_index
end
end
--- 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] and menu.items[1].screen then
hide(menu)
else
show(menu)
end
end
--- Open a menu popup.
-- @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.
-- @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.
function new(menu, parent, num)
-- Create a table to store our menu informations
local data = {}
data.items = {}
data.num = num or 1
data.theme = parent and parent.theme or load_theme(menu)
data.parent = parent
data.child = {}
data.h = parent and parent.h or data.theme.menu_height
data.w = parent and parent.w or data.theme.menu_width
-- Create items
for k, v in pairs(menu.items) do
table.insert(data.items, add_item(data, k, v))
end
-- Set methods
data.hide = hide
data.show = show
data.toggle = toggle
return data
end