diff options
Diffstat (limited to 'pkgs/astal/src')
-rw-r--r-- | pkgs/astal/src/launcher.lua | 14 | ||||
-rw-r--r-- | pkgs/astal/src/shell.lua | 12 | ||||
-rw-r--r-- | pkgs/astal/src/widget/launcher.lua | 202 |
3 files changed, 147 insertions, 81 deletions
diff --git a/pkgs/astal/src/launcher.lua b/pkgs/astal/src/launcher.lua index cc16bb9..3c3994e 100644 --- a/pkgs/astal/src/launcher.lua +++ b/pkgs/astal/src/launcher.lua @@ -1,10 +1,16 @@ local App = require("astal.gtk3.app") +local lib = require("lib") + +local Launcher = require("widget.launcher") App:start({ + instance_name = "launcher", + css = lib.src("main.css"), main = function() - error("must start astal-shell first") - end, - client = function(req) - req("launcher") + for _, mon in pairs(App.monitors) do + if mon.is_primary then + Launcher(mon) + end + end end, }) diff --git a/pkgs/astal/src/shell.lua b/pkgs/astal/src/shell.lua index 417f754..c370349 100644 --- a/pkgs/astal/src/shell.lua +++ b/pkgs/astal/src/shell.lua @@ -4,11 +4,9 @@ local lib = require("lib") local Bar = require("widget.bar") local Corners = require("widget.corners") local Deck = require("widget.deck") -local Launcher = require("widget.launcher") - -local launcher_visible App:start({ + instance_name = "shell", css = lib.src("main.css"), main = function() for _, mon in pairs(App.monitors) do @@ -16,13 +14,5 @@ App:start({ Corners(mon) Deck(mon) end - launcher_visible = Launcher() - end, - request_handler = function(req, res) - if req == "launcher" then - launcher_visible:set(true) - return res("opening launcher") - end - res("unknown command") end, }) diff --git a/pkgs/astal/src/widget/launcher.lua b/pkgs/astal/src/widget/launcher.lua index 66fa4b0..44dbcdd 100644 --- a/pkgs/astal/src/widget/launcher.lua +++ b/pkgs/astal/src/widget/launcher.lua @@ -8,58 +8,110 @@ local Apps = astal.require("AstalApps") local Variable = astal.Variable local lib = require("lib") -local MAX_ENTRIES = 20 -local WIDTH = 7 +local WIDTH +local MAX_ENTRIES local FlowBox = astalify(Gtk.FlowBox) local FlowBoxChild = astalify(Gtk.FlowBoxChild) -local apps = Apps.Apps() +local function exit() + App:quit() +end -local text = Variable("") -local visible = Variable(false) -local selection = Variable(1) +local selection = Variable(0) local entry = Variable(nil) -local list = text(function(text) - return lib.slice(apps:exact_query(text), 0, MAX_ENTRIES) -end) +function Application(app, selected) + return FlowBoxChild({ + Widget.Button({ + class_name = selected(function(bool) + if bool then + return "app selected" + else + return "app" + end + end), + on_clicked = function() + app:launch() + exit() + 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 = 16, + }), + }), + }), + }) +end + +local astal_apps = Apps.Apps() +local apps = {} -local function on_show() - text:set("") - selection:set(0) - entry:get():grab_focus() +local function get_app(key) + local tbl = apps[key] + if tbl.elm == nil then + local selected = Variable(false) + tbl.elm = Application(tbl.app, selected) + tbl.selected = selected + apps[entry] = tbl + end + return tbl end -local function hide() - visible:set(false) +for _,app in pairs(astal_apps.list) do + apps[app.entry] = { + app = app, + } end +local text = Variable("") +local list = text(function(query) + return lib.slice(astal_apps:fuzzy_query(query), 0, MAX_ENTRIES) +end) + local function on_enter() - local found = apps:exact_query(text:get())[selection:get() + 1] - if found then - found:launch() - hide() - end + local app = list:get()[selection:get() + 1] + app:launch() + exit() end local function update_pos(change_x, change_y) - local pos = selection:get() + local old_pos = selection:get() + local pos = old_pos local pos_x = (pos % WIDTH) + change_x local pos_y = math.floor(pos / WIDTH) + change_y - local count = lib.count(list:get()) - local height = math.floor((count + WIDTH - 1) / WIDTH) + local count = math.min(MAX_ENTRIES, lib.count(list:get())) pos_x = pos_x % WIDTH - pos_y = pos_y % height + pos_y = pos_y % (MAX_ENTRIES/WIDTH) pos = lib.clamp(pos_y * WIDTH + pos_x, 0, count - 1) selection:set(pos) + + local old_app = list:get()[old_pos + 1] + if old_app then + get_app(old_app.entry).selected:set(false) + end + + local app = list:get()[pos + 1] + if app then + get_app(app.entry).selected:set(true) + end end local function on_key_press(_, event) if event.keyval == Gdk.KEY_Escape then - hide() + exit() elseif event.keyval == Gdk.KEY_Return then on_enter() elseif event.keyval == Gdk.KEY_Left then @@ -73,45 +125,29 @@ local function on_key_press(_, event) end end -function Application(app, idx) - return FlowBoxChild({ - Widget.Button({ - class_name = selection():as(function(c) - if (c + 1) == idx then - return "app selected" - else - return "app" - end - end), - on_clicked = function() - app:launch() - hide() - 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 = 16, - }), - }), - }), - }) -end - -function Applications(apps) +function Applications() return FlowBox({ hexpand = true, homogeneous = true, class_name = "apps", - lib.map(apps, Application) + list:as(function(l) + -- remove all old elements + for _,tbl in pairs(apps) do + local elm = tbl.elm + if elm then + local parent = elm.parent + if parent ~= nil then + parent:remove(elm) + end + end + end + + -- map list to elements + return lib.map(l, function(app) + local tbl = get_app(app.entry) + return tbl.elm + end) + end), }) end @@ -133,25 +169,59 @@ function Launcher() }), Widget.Box({ class_name = "apps", - list:as(Applications), + Applications(), }), }) end -return function() +local function calc_bounds(gdkmonitor) + -- constants + local font_size = 14 + local outer_gap = 12 + + -- get screen dimensions + local screen_width = gdkmonitor.geometry.width + local screen_height = gdkmonitor.geometry.height + + -- calculate size of a cell + local cell_min_width = 15 * font_size + local cell_padding = outer_gap*4 + local cell_size = cell_min_width + cell_padding + + -- caculate usuable bounds + local used_width = 2*5*font_size + local used_height = 15*font_size + local free_width = screen_width - used_width + local free_height = screen_height - used_height + + -- caculate counts + local width = math.floor(free_width / cell_size) + local height = math.floor(free_height / cell_size) + + WIDTH = width + MAX_ENTRIES = width*height +end + +return function(gdkmonitor) local Anchor = astal.require('Astal').WindowAnchor - Widget.Window({ + calc_bounds(gdkmonitor) + + local function on_show() + text:set("") + selection:set(0) + entry:get():grab_focus() + end + + return Widget.Window({ class_name = "launcher", + gdkmonitor = gdkmonitor, 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, - visible = visible(), Launcher(), }) - - return visible end |