You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
7.4 KiB
193 lines
7.4 KiB
local awful = require("awful")
|
|
local gears = require("gears")
|
|
local menubar_utils = require("menubar.utils")
|
|
local wibox = require("wibox")
|
|
local beautiful = require("beautiful")
|
|
local awmtk = require("awmtk")
|
|
local function cascade_close(path,limit)
|
|
for I = #path,limit or 1,-1 do
|
|
if path[I] then
|
|
path[I].visible = false
|
|
end
|
|
path[I] = nil
|
|
end
|
|
end
|
|
local function merge_into_widget(widget,args)
|
|
for k,v in ipairs(args) do
|
|
table.insert(widget,v)
|
|
end
|
|
end
|
|
local function get_button_container()
|
|
--This function prevents mouse.current_widget_geometry from picking up textboxes
|
|
local output = {}
|
|
local geo = mouse.current_widgets
|
|
for k,v in pairs(geo) do
|
|
if tostring(v):match("^widget_background") then
|
|
output = mouse.current_widget_geometries[k]
|
|
break
|
|
end
|
|
end
|
|
return output
|
|
end
|
|
local function loader(options)
|
|
local style = awmtk.style(awmtk.defaults,options.style or {},"menu_")
|
|
options = options or {}
|
|
-- Define styles
|
|
local button_bg_on = style.menu_button_bg_focus
|
|
local button_bg_off = style.menu_button_bg_normal
|
|
local userlinks = wibox.widget {
|
|
layout = (
|
|
options.vertical and
|
|
wibox.layout.fixed.vertical
|
|
) or wibox.layout.fixed.horizontal,
|
|
spacing = style.menu_container_spacing or 4,
|
|
}
|
|
local button_template = function(v)
|
|
return {
|
|
layout = (
|
|
options.vertical and
|
|
wibox.layout.fixed.horizontal
|
|
) or wibox.layout.fixed.vertical,
|
|
(v[3] and {
|
|
widget = wibox.widget.imagebox,
|
|
resize = true,
|
|
image = v[3],
|
|
}),
|
|
{
|
|
markup = v[1] or "",
|
|
widget = wibox.widget.textbox,
|
|
ellipsize = "end"
|
|
},
|
|
spacing = 2
|
|
}
|
|
end
|
|
local button_style = {
|
|
bg = button_bg_off,
|
|
forced_height = style.menu_button_height or
|
|
style.menu_height or
|
|
24,
|
|
forced_width = style.menu_button_width or
|
|
style.menu_width or
|
|
140
|
|
}
|
|
local menu_template = function(tree_layer)
|
|
return {
|
|
layout = (
|
|
options.vertical
|
|
and wibox.layout.fixed.vertical
|
|
) or wibox.layout.fixed.horizontal,
|
|
spacing = (
|
|
options.vertical and
|
|
style.menu_container_spacing_vertical
|
|
) or style.menu_container_spacing_horizontal,
|
|
tree_layer = tree_layer,
|
|
}
|
|
end
|
|
local menu_popup_template = {
|
|
visible = false,
|
|
ontop = true,
|
|
preferred_positions = (options.vertical and {"right","left"}) or {"top","bottom"},
|
|
preferred_anchors = (options.inverse and {"back","front"}) or {"front","back"},
|
|
}
|
|
--Create menu root
|
|
local menu = menu_template(1)
|
|
local tree_path = {"spacer"}
|
|
--Insert widgets above/before the menu
|
|
merge_into_widget(menu,options.before or {})
|
|
local function generate_menu(leaf,menu)
|
|
--Iterate over a table of widget defining tables
|
|
for k,v in ipairs(leaf) do
|
|
if type(v) ~= "table" then
|
|
--Error if the structure is invalid
|
|
error("Invalid leaf type "..type(v).." in menu tree")
|
|
else
|
|
local tree_layer = menu.tree_layer+1
|
|
--Create a button widget
|
|
local new_button = style.button(button_template(v),button_style)
|
|
if type(v[2]) == "table" then
|
|
--Create a popup template for the new menu leaf
|
|
local new_popup = menu_template(tree_layer)
|
|
--Add buttons and widgets to the new leaf
|
|
merge_into_widget(new_popup,v[2].before or {})
|
|
generate_menu(v[2],new_popup)
|
|
merge_into_widget(new_popup,v[2].after or {})
|
|
new_popup = awful.popup(style.container(new_popup,menu_popup_template))
|
|
new_button:connect_signal("mouse::enter",function()
|
|
--Hide cascading leaves of a branch when leaf changes
|
|
if menu.current_selection and (menu.current_selection ~= new_popup) then
|
|
cascade_close(tree_path,tree_layer)
|
|
end
|
|
--Move the new popup widget closer to mouse and align it precisely to the button
|
|
if mouse.current_widget_geometry then
|
|
local geo = get_button_container()
|
|
tree_path[tree_layer] = new_popup
|
|
--Apparently it's a thing that needed fixing.
|
|
--I don't question it, and neither should you.
|
|
if geo and geo.x and geo.y then
|
|
new_popup:move_next_to(geo)
|
|
end
|
|
--previous method call aligns the popup to the button,
|
|
--NOT the buttons within the popup. So we do that ourselves (somewhat).
|
|
if new_popup.current_anchor == "front" then
|
|
new_popup.y = new_popup.y - style.menu_container_inner_margin
|
|
else
|
|
new_popup.y = new_popup.y + style.menu_container_inner_margin
|
|
end
|
|
new_popup.visible = true
|
|
menu.current_selection = new_popup
|
|
end
|
|
end)
|
|
elseif type(v[2]) == "function" then
|
|
new_button:connect_signal("button::press",function()
|
|
cascade_close(tree_path,1)
|
|
v[2]()
|
|
end)
|
|
elseif type(v[2]) == "string" then
|
|
new_button:connect_signal("button::press",function()
|
|
cascade_close(tree_path,1)
|
|
awful.spawn(v[2])
|
|
end)
|
|
end
|
|
new_button:connect_signal("mouse::enter",function()
|
|
--Set button bg
|
|
if menu.current_button then
|
|
menu.current_button.bg = button_bg_off
|
|
end
|
|
menu.current_button = new_button
|
|
menu.current_button.bg = button_bg_on
|
|
end)
|
|
table.insert(menu,new_button)
|
|
end
|
|
end
|
|
end
|
|
generate_menu(options.items,menu)
|
|
--Insert widgets below/after the menu
|
|
merge_into_widget(menu,options.after or {})
|
|
menu = awful.popup(style.container(menu,menu_popup_template))
|
|
tree_path[1] = menu
|
|
menu.toggle = function(x,y)
|
|
if (not x) or (not y) then
|
|
x = mouse.coords().x
|
|
y = mouse.coords().y
|
|
end
|
|
menu.x = x
|
|
menu.y = y
|
|
if menu.x+menu.width > menu.screen.geometry.width then
|
|
menu.x = menu.x-menu.width
|
|
end
|
|
if menu.y+menu.height > menu.screen.geometry.height then
|
|
menu.y = menu.y-menu.height
|
|
end
|
|
if menu.visible then
|
|
cascade_close(tree_path,2)
|
|
end
|
|
tree_path[1] = menu
|
|
menu.visible = (not menu.visible)
|
|
end
|
|
menu.show = function(self)
|
|
menu.toggle()
|
|
end
|
|
return menu
|
|
end
|
|
|
|
return loader
|