local awful = require("awful") local wibox = require("wibox") local gears = require("gears") local beautiful = require("beautiful") local menubar = require("menubar") local cairo = require("lgi").cairo local Rsvg = require("lgi").Rsvg local longpress = require("awesome-longpress") local launcherpopup = { buttonsize = 128, spacing = 5, iconPath = gears.filesystem.get_configuration_dir() .. "/awesome-launcherpopup/", updateOnSpawn = true, applications = {}, allInstances = {} } function launcherpopup.update() menubar.menu_gen.generate(function(rv) launcherpopup.applications = rv for k,v in pairs(launcherpopup.allInstances) do if k and v then w,e = pcall(v.populateMenu) end end end) end function launcherpopup.new(s) local menuStart = 1 local launcherWidget = wibox.widget{ layout = wibox.layout.fixed.vertical, spacing = launcherpopup.spacing } local launcher = awful.popup{ layout = wibox.layout.fixed.vertical, widget = launcherWidget, border_color = beautiful.border_focus, border_width = 2, ontop = true, placement = awful.placement.centered, visible = false, screen = s, } local launcherButtons = wibox.widget{ layout = wibox.layout.grid.vertical, spacing = launcherpopup.spacing } local launcherNav = wibox.widget{ layout = wibox.layout.ratio.horizontal, forced_width = math.floor((s.geometry.width) / (launcherpopup.buttonsize + launcherpopup.spacing * 2)) * (launcherpopup.buttonsize + launcherpopup.spacing) } local launcherList = wibox.widget{ layout = wibox.layout.grid, spacing = launcherpopup.spacing } launcherWidget:add(launcherList) launcherWidget:add(launcherNav) local launcherNextPage = wibox.widget{ widget = wibox.widget.imagebox, image = launcherpopup.iconPath .. "/next.svg", forced_width=launcherpopup.buttonsize * 0.75, forced_height=launcherpopup.buttonsize * 0.75 } local launcherPreviousPage = wibox.widget{ widget = wibox.widget.imagebox, image = launcherpopup.iconPath .. "/previous.svg", forced_width=launcherpopup.buttonsize * 0.75, forced_height=launcherpopup.buttonsize * 0.75 } launcherNav:add( wibox.container.place(launcherPreviousPage,"left","top"), wibox.container.place(launcherNextPage,"right","top")) local function fillMenu() launcherList:reset() local maxRows = math.floor(s.geometry.height / (launcherpopup.buttonsize * 1.5 + launcherpopup.spacing * 2)) - 2 local maxColumns = math.floor((s.geometry.width) / (launcherpopup.buttonsize + launcherpopup.spacing * 2)) local maxEntries = maxRows * maxColumns local x,y = 1,1 for y = 1, maxRows do for x = 1, maxColumns do local dentry = launcherpopup.applications[(menuStart - 1) + (y-1)*maxColumns + x] if not dentry then dentry = {icon="",name=""} end local mwidget = wibox.widget{ layout = wibox.layout.fixed.vertical } local mwicon = wibox.widget{ image = dentry.icon or launcherpopup.iconPath .. "/default.svg", widget = wibox.widget.imagebox, forced_width = launcherpopup.buttonsize, forced_height = launcherpopup.buttonsize } mwidget:add(mwicon) local mwtext = wibox.container.constraint(wibox.widget{ widget = wibox.widget.textbox, valign = "top", align = "center", text = dentry.name },"exact",launcherpopup.buttonsize,launcherpopup.buttonsize * 0.5) mwidget:add(mwtext) longpress.add(mwidget,function() if dentry.cmdline then awful.spawn(dentry.cmdline) launcher:hide() end end) launcherList:add_widget_at(wibox.container.constraint(mwidget,"max",launcherpopup.buttonsize,launcherpopup.buttonsize*1.5),y,x) end end end local function goToEntry(n) local maxRows = math.floor(s.geometry.height / (launcherpopup.buttonsize * 1.5 + launcherpopup.spacing * 2)) - 2 local maxColumns = math.floor((s.geometry.width) / (launcherpopup.buttonsize + launcherpopup.spacing * 2)) local maxEntries = maxRows * maxColumns menuStart = n if menuStart < 1 then menuStart = (math.floor(#launcherpopup.applications / maxEntries) * maxEntries) + 1 end if menuStart > #launcherpopup.applications then menuStart = 1 end fillMenu() end longpress.add(launcherNextPage,function() goToEntry(menuStart + ((math.floor(s.geometry.height / (launcherpopup.buttonsize * 1.5 + launcherpopup.spacing * 2)) - 2) * math.floor((s.geometry.width) / (launcherpopup.buttonsize + launcherpopup.spacing * 2)))) end, function() goToEntry(#launcherpopup.applications) end) longpress.add(launcherPreviousPage,function() goToEntry(menuStart - ((math.floor(s.geometry.height / (launcherpopup.buttonsize * 1.5 + launcherpopup.spacing * 2)) - 2) * math.floor((s.geometry.width) / (launcherpopup.buttonsize + launcherpopup.spacing * 2)))) end, function() goToEntry(1) end) function launcher.populateMenu() fillMenu() end function launcher.addButton(icon, fn) local newButton = awful.widget.button{ image = launcherpopup.iconPath .. "/" .. icon } newButton:set_forced_width(launcherpopup.buttonsize) newButton:set_forced_height(launcherpopup.buttonsize) newButton:buttons(gears.table.join( newButton:buttons(), awful.button({}, 1, nil, function() fn() launcher:hide() end) )) launcherButtons:add(newButton) end function launcher.show(self) self.visible = true end function launcher.hide(self) self.visible = false end function launcher.toggle(self) self.visible = not self.visible end launcherpopup.allInstances[#launcherpopup.allInstances+1] = launcher launcherpopup.update() return launcher end return launcherpopup