local astal = require("astal") local Widget = require("astal.gtk3.widget") local App = require("astal.gtk3.app") local Gdk = require("astal.gtk3").Gdk local Gtk = require("astal.gtk3").Gtk local astalify = require("astal.gtk3").astalify local Apps = astal.require("AstalApps") local Variable = astal.Variable local lib = require("lib") local MAX_ENTRIES = 20 local FlowBox = astalify(Gtk.FlowBox) local FlowBoxChild = astalify(Gtk.FlowBoxChild) local apps = Apps.Apps() local text = Variable("") local list = text(function(text) return lib.slice(apps:exact_query(text), 0, MAX_ENTRIES) end) function on_show() text:set("") end function close() App:quit() end function on_key_press(self, event) if event.keyval == Gdk.KEY_Escape then close() end end function on_enter() local found = apps:exact_query(text:get())[1] if found then found:launch() close() end end function Application(app) return FlowBoxChild({ Widget.Button({ class_name = "app", on_clicked = function() app:launch() close() end, Widget.Box({ halign = "CENTER", valign = "CENTER", vertical = true, Widget.Icon({ icon = app.icon_name, }), Widget.Label({ class_name = "name", label = app.name, valign = "CENTER", ellipsize = "END", max_width_chars = 20, }), }), }), }) end function Applications(apps) return FlowBox({ hexpand = true, homogeneous = true, class_name = "apps", lib.map(apps, Application) }) end function Launcher() return Widget.Box({ vertical = true, Widget.Entry({ class_name = "search", placeholder_text = "Search", halign = "CENTER", text = text(), on_changed = function(self) text:set(self.text) end, on_activate = on_enter, }), Widget.Box({ class_name = "apps", list:as(Applications), }), }) end return function() local Anchor = astal.require('Astal').WindowAnchor return Widget.Window({ class_name = "launcher", anchor = Anchor.TOP + Anchor.BOTTOM + Anchor.LEFT + Anchor.RIGHT, exclusivity = "EXCLUSIVE", keymode = "ON_DEMAND", application = App, on_show = on_show, on_key_press_event = on_key_press, Launcher(), }) end