summaryrefslogtreecommitdiff
path: root/pkgs/astal/src
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/astal/src')
-rw-r--r--pkgs/astal/src/launcher.lua14
-rw-r--r--pkgs/astal/src/shell.lua12
-rw-r--r--pkgs/astal/src/widget/launcher.lua202
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