finished application laucnher and bluetooth widget

This commit is contained in:
Rene Kievits
2022-11-27 10:58:27 +01:00
parent c6341f84e7
commit 10f56a7273
77 changed files with 2379 additions and 4938 deletions

View File

@@ -44,6 +44,47 @@ function application_grid:get_widget()
return self._private.widget
end
local function levenshtein_distance(str1, str2)
local len1 = string.len(str1)
local len2 = string.len(str2)
local matrix = {}
local cost = 0
if (len1 == 0) then
return len2
elseif (len2 == 0) then
return len1
elseif (str1 == str2) then
return 0
end
for i = 0, len1, 1 do
matrix[i] = {}
matrix[i][0] = i
end
for j = 0, len2, 1 do
matrix[0][j] = j
end
for i = 1, len1, 1 do
for j = 1, len2, 1 do
if str1:byte(i) == str2:byte(j) then
cost = 0
else
cost = 1
end
matrix[i][j] = math.min(
matrix[i - 1][j] + 1,
matrix[i][j - 1] + 1,
matrix[i - 1][j - 1] + cost
)
end
end
return matrix[len1][len2]
end
function application_grid:get_applications_from_file()
local list = {}
local app_info = Gio.AppInfo
@@ -101,6 +142,7 @@ function application_grid:get_applications_from_file()
border_width = Theme_config.application_launcher.application.border_width,
bg = Theme_config.application_launcher.application.bg,
fg = Theme_config.application_launcher.application.fg,
desktop_file = Gio.DesktopAppInfo.get_filename(desktop_app_info) or "",
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(8))
end,
@@ -256,29 +298,64 @@ function application_grid:set_applications(search_filter)
layout = wibox.layout.grid
}
local dir = gfilesystem.get_configuration_dir() .. "src/config/applications.json"
if not gfilesystem.file_readable(dir) then return end
local handler = io.open(dir, "r")
if not handler then return end
local dock_encoded = handler:read("a") or "{}"
local dock = json:decode(dock_encoded)
if type(dock) ~= "table" then return end
local mylist = {}
for _, application in ipairs(self.app_list) do
-- Match the filter
if string.match(string.lower(application.name or ""), string.lower(filter)) or
string.match(string.lower(application.categories or ""), string.lower(filter)) or
string.match(string.lower(application.keywords or ""), string.lower(filter)) then
grid:add(application)
-- Get the current position in the grid of the application as a table
local pos = grid:get_widget_position(application)
-- Check if the curser is currently at the same position as the application
capi.awesome.connect_signal(
"update::selected",
function()
if self._private.curser.y == pos.row and self._private.curser.x == pos.col then
application.border_color = Theme_config.application_launcher.application.border_color_active
else
application.border_color = Theme_config.application_launcher.application.border_color
end
if #dock == 0 then
application.counter = 0
end
for _, app in ipairs(dock) do
if app.desktop_file == application.desktop_file then
application.counter = app.counter or 0
break;
else
application.counter = 0
end
)
end
table.insert(mylist, application)
end
end
table.sort(mylist, function(a, b)
return levenshtein_distance(filter, a.name) < levenshtein_distance(filter, b.name)
end)
--sort mytable by counter
table.sort(mylist, function(a, b)
return a.counter > b.counter
end)
for _, app in ipairs(mylist) do
grid:add(app)
-- Get the current position in the grid of the app as a table
local pos = grid:get_widget_position(app)
-- Check if the curser is currently at the same position as the app
capi.awesome.connect_signal(
"update::selected",
function()
if self._private.curser.y == pos.row and self._private.curser.x == pos.col then
app.border_color = Theme_config.application_launcher.application.border_color_active
else
app.border_color = Theme_config.application_launcher.application.border_color
end
end
)
end
capi.awesome.emit_signal("update::selected")
self:set_widget(grid)
end
@@ -292,7 +369,6 @@ function application_grid:move_up()
end
function application_grid:move_down()
print(self._private.curser.y)
self._private.curser.y = self._private.curser.y + 1
local grid_rows, _ = self:get_widget():get_dimension()
if self._private.curser.y > grid_rows then
@@ -322,6 +398,35 @@ function application_grid:execute()
local selected_widget = self:get_widget():get_widgets_at(self._private.curser.y,
self._private.curser.x)[1]
Gio.AppInfo.launch_uris_async(Gio.AppInfo.create_from_commandline(selected_widget.exec, nil, 0))
local dir = gfilesystem.get_configuration_dir() .. "src/config/applications.json"
if not gfilesystem.file_readable(dir) then return end
local handler = io.open(dir, "r")
if not handler then return end
local dock_encoded = handler:read("a") or "{}"
local dock = json:decode(dock_encoded)
if type(dock) ~= "table" then return end
for _, prog in ipairs(dock) do
if prog.desktop_file:match(selected_widget.desktop_file) then
prog.counter = prog.counter + 1
goto continue
end
end
do
local prog = {
name = selected_widget.name,
desktop_file = selected_widget.desktop_file,
counter = 1
}
table.insert(dock, prog)
end
::continue::
handler:close()
handler = io.open(dir, "w")
if not handler then return end
handler:write(json:encode_pretty(dock))
handler:close()
end
function application_grid:reset()
@@ -344,10 +449,17 @@ function application_grid.new(args)
y = 1
}
-- Create folder and file if it doesn't exist
local dir = gfilesystem.get_configuration_dir() .. "src/config"
gfilesystem.make_directories(dir)
dir = dir .. "/applications.json"
if not gfilesystem.file_readable(dir) then
os.execute("touch " .. dir)
end
w:get_applications_from_file()
w:set_applications()
return w
end

View File

@@ -10,6 +10,7 @@ local wibox = require("wibox")
local gshape = require("gears.shape")
local gtable = require("gears.table")
local gobject = require("gears.object")
local abutton = require("awful.button")
local capi = {
awesome = awesome,
@@ -18,39 +19,6 @@ local capi = {
local application_launcher = { mt = {} }
application_launcher.searchbar = awful.widget.inputbox {
widget_template = wibox.template {
widget = wibox.widget {
{
{
{
widget = wibox.widget.textbox,
halign = "left",
valign = "center",
id = "text_role",
},
widget = wibox.container.margin,
margins = 5,
id = "marg"
},
widget = wibox.container.constraint,
strategy = "exact",
width = 400,
height = 50,
id = "const"
},
widget = wibox.container.background,
bg = "#212121",
fg = "#F0F0F0",
border_color = "#414141",
border_width = 2,
shape = gshape.rounded_rect,
},
update_callback = function(template_widget, args)
template_widget.widget.const.marg.text_role.markup = args.text
end
}
}
application_launcher.application_grid = require("src.modules.application_launcher.application") {}
@@ -62,10 +30,58 @@ function application_launcher.new(args)
gtable.crush(ret, application_launcher, true)
local searchbar = awful.widget.inputbox {
hint_text = "Search...",
valign = "center",
halign = "left",
}
searchbar:buttons(
gtable.join {
abutton({}, 1, function()
searchbar:focus()
end)
}
)
local old_cursor, old_wibox
searchbar:connect_signal("mouse::enter", function()
local wid = capi.mouse.current_wibox
if wid then
old_cursor, old_wibox = wid.cursor, wid
wid.cursor = "xterm"
end
end)
searchbar:connect_signal("mouse::leave", function()
old_wibox.cursor = old_cursor
old_wibox = nil
end)
local applicaton_launcher = wibox.widget {
{
{
ret.searchbar,
{
{
{
searchbar,
widget = wibox.container.margin,
margins = 5,
id = "marg"
},
widget = wibox.container.constraint,
strategy = "exact",
width = 400,
height = 50,
id = "const"
},
widget = wibox.container.background,
bg = Theme_config.application_launcher.searchbar.bg,
fg = Theme_config.application_launcher.searchbar.fg,
border_color = Theme_config.application_launcher.searchbar.border_color,
border_width = Theme_config.application_launcher.searchbar.border_width,
shape = gshape.rounded_rect,
id = "searchbar_bg"
},
{
ret.application_grid,
spacing = dpi(10),
@@ -101,52 +117,70 @@ function application_launcher.new(args)
border_width = Theme_config.application_launcher.border_width
}
local searchbar_bg = applicaton_launcher:get_children_by_id("searchbar_bg")[1]
capi.awesome.connect_signal(
"application_launcher::show",
function()
capi.awesome.emit_signal("update::selected")
if capi.mouse.screen == args.screen then
ret.application_container.visible = not ret.application_container.visible
end
if ret.application_container.visible then
ret.searchbar:focus()
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_active
searchbar:focus()
else
searchbar:set_text("")
awful.keygrabber.stop()
end
end
)
ret.searchbar:connect_signal(
searchbar:connect_signal(
"submit",
function(text)
function(_, text)
ret.application_grid:execute()
capi.awesome.emit_signal("application_launcher::show")
searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text())
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color
end
)
ret.searchbar:connect_signal(
searchbar:connect_signal(
"stopped",
function()
ret.searchbar:get_widget().widget.border_color = Theme_config.application_launcher.searchbar.border_color
function(_, stop_key)
if stop_key == "Escape" then
capi.awesome.emit_signal("application_launcher::show")
end
searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text())
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color
end
)
ret.searchbar:connect_signal(
searchbar:connect_signal(
"started",
function()
ret.searchbar:get_widget().widget.border_color = Theme_config.application_launcher.searchbar.border_active
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_active
end
)
awesome.connect_signal(
searchbar:connect_signal(
"inputbox::key_pressed",
function(modkey, key)
function(_, modkey, key)
if key == "Escape" then
ret.searchbar:stop()
searchbar:stop()
capi.awesome.emit_signal("application_launcher::show")
ret.application_grid:reset()
ret.searchbar:set_text("")
searchbar:set_text("")
elseif key == "Down" or key == "Right" then
ret.searchbar:stop()
if key == "Down" then
ret.application_grid:move_down()
elseif key == "Right" then
ret.application_grid:move_right()
end
searchbar:stop()
awful.keygrabber.run(function(mod, key2, event)
if event == "press" then
if key2 == "Down" then
@@ -155,7 +189,7 @@ function application_launcher.new(args)
local old_y = ret.application_grid._private.curser.y
ret.application_grid:move_up()
if old_y - ret.application_grid._private.curser.y == 0 then
ret.searchbar:focus()
searchbar:focus()
end
elseif key2 == "Left" then
ret.application_grid:move_left()
@@ -166,17 +200,20 @@ function application_launcher.new(args)
ret.application_grid:execute()
capi.awesome.emit_signal("application_launcher::show")
ret.application_grid:reset()
ret.searchbar:set_text("")
searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text())
elseif key2 == "Escape" then
capi.awesome.emit_signal("application_launcher::show")
ret.application_grid:reset()
ret.searchbar:set_text("")
searchbar:set_text("")
ret.application_grid:set_applications(searchbar:get_text())
awful.keygrabber.stop()
end
end
end)
searchbar_bg.border_color = Theme_config.application_launcher.searchbar.border_color
end
ret.application_grid:set_applications(ret.searchbar:get_text())
ret.application_grid:set_applications(searchbar:get_text())
end
)

View File

@@ -1,252 +0,0 @@
-------------------------------------------------------
-- This is the seachbar for the application launcher --
-------------------------------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local gstring = gears.string
local keygrabber = require("awful.keygrabber")
local wibox = require("wibox")
local capi = {
awesome = awesome,
mouse = mouse,
}
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/application_launcher/searchbar/"
local kgrabber
return function()
local searchbar = wibox.widget {
{
{
{ -- Search icon
{
{
resize = false,
valign = "center",
halign = "center",
image = gears.color.recolor_image(icondir .. "search.svg",
Theme_config.application_launcher.searchbar.icon_color),
widget = wibox.widget.imagebox
},
bg = Theme_config.application_launcher.searchbar.icon_background,
widget = wibox.container.background
},
strategy = "exact",
width = dpi(30),
widget = wibox.container.constraint
},
{
{
fg = Theme_config.application_launcher.searchbar.fg_hint,
markup = "Search",
valign = "center",
align = "center",
widget = wibox.widget.textbox,
id = "search_hint"
},
margins = dpi(5),
widget = wibox.container.margin,
id = "s_margin"
},
widget = wibox.layout.fixed.horizontal,
id = "s_layout"
},
bg = Theme_config.application_launcher.searchbar.bg,
fg = Theme_config.application_launcher.searchbar.fg,
border_color = Theme_config.application_launcher.searchbar.border_color,
border_width = Theme_config.application_launcher.searchbar.border_width,
widget = wibox.container.background,
shape = Theme_config.application_launcher.searchbar.shape,
id = "s_background"
},
width = dpi(400),
height = dpi(40),
strategy = "exact",
widget = wibox.container.constraint
}
local old_wibox, old_cursor
local mouse_enter = function()
local w = capi.mouse.current_wibox
if w then
old_cursor, old_wibox = w.cursor, w
w.cursor = "xterm"
end
end
local mouse_leave = function()
old_wibox.cursor = old_cursor
old_wibox = nil
end
searchbar:disconnect_signal("mouse::enter", mouse_enter)
searchbar:disconnect_signal("mouse::leave", mouse_leave)
searchbar:connect_signal("mouse::enter", mouse_enter)
searchbar:connect_signal("mouse::leave", mouse_leave)
local function have_multibyte_char_at(text, position)
return #text:sub(position, position) == -1
end
local search_text = searchbar:get_children_by_id("search_hint")[1]
local function promt_text_with_cursor(text, cursor_pos)
local char, spacer, text_start, text_end
local cursor_color = Theme_config.application_launcher.searchbar.bg_cursor
local text_color = Theme_config.application_launcher.searchbar.fg_cursor
if text == "" then
return "<span foreground='" .. Theme_config.application_launcher.searchbar.fg_hint .. "'>Search</span>"
end
if #text < cursor_pos then
char = " "
spacer = ""
text_start = gstring.xml_escape(text)
text_end = ""
else
local offset = 0
if have_multibyte_char_at(text, cursor_pos) then
offset = 1
end
char = gstring.xml_escape(text:sub(cursor_pos, cursor_pos + offset))
spacer = " "
text_start = gstring.xml_escape(text:sub(1, cursor_pos - 1))
text_end = gstring.xml_escape(text:sub(cursor_pos + offset + 1))
end
return text_start ..
"<span background='" ..
cursor_color .. "' foreground='" .. text_color .. "'>" .. char .. "</span>" .. text_end .. spacer
end
local text_string = ""
---Start a new keygrabber to simulate an input textbox
local function keygrabber_start()
local cur_pos = #text_string + 1
--Draws the string on each keypress
local function update()
search_text:set_markup(promt_text_with_cursor(text_string, cur_pos))
--Send the string over to the application to filter applications
capi.awesome.emit_signal("update::application_list", text_string)
end
update()
kgrabber = keygrabber.run(
function(modifiers, key, event)
capi.awesome.connect_signal("searchbar::stop", function()
keygrabber.stop(kgrabber)
capi.awesome.emit_signal("application_launcher::kgrabber_start")
end)
local mod = {}
for _, v in ipairs(modifiers) do
mod[v] = true
end
if event ~= "press" then
return
end
--Escape cases
if (mod.Control and (key == "c" or key == "g"))
or (not mod.Control and key == "Escape") then
keygrabber.stop(kgrabber)
search_text:set_markup(promt_text_with_cursor("", 1))
text_string = ""
capi.awesome.emit_signal("application_launcher::show")
elseif (not mod.Control and key == "Return") or
(not mod.Control and key == "KP_Enter") then
keygrabber.stop(kgrabber)
searchbar.s_background.border_color = Theme_config.application_launcher.searchbar.border_color
searchbar.s_background.fg = Theme_config.application_launcher.searchbar.fg_hint
search_text:set_markup(promt_text_with_cursor("", 1))
text_string = ""
capi.awesome.emit_signal("application_launcher::execute")
capi.awesome.emit_signal("application_launcher::show")
end
if mod.Control then
elseif mod.Mod1 or mod.Mod3 then
else
--Delete character to the left and move cursor
if key == "BackSpace" then
if cur_pos > 1 then
local offset = 0
if have_multibyte_char_at(text_string, cur_pos - 1) then
offset = 1
end
text_string = text_string:sub(1, cur_pos - 2 - offset) .. text_string:sub(cur_pos)
cur_pos = cur_pos - 1 - offset
end
update()
--Delete character to the right
elseif key == "Delete" then
text_string = text_string:sub(1, cur_pos - 1) .. text_string:sub(cur_pos + 1)
update()
-- Move cursor to the left
elseif key == "Left" then
--cur_pos = cur_pos - 1
capi.awesome.emit_signal("application::left")
-- Move cursor to the right
elseif key == "Right" then
--cur_pos = cur_pos + 1
capi.awesome.emit_signal("application::right")
elseif key == "Up" then
capi.awesome.emit_signal("application::up")
elseif key == "Down" then
capi.awesome.emit_signal("application::down")
else
--Add key at cursor position
if key:wlen() == 1 then
text_string = text_string:sub(1, cur_pos - 1) .. key .. text_string:sub(cur_pos)
cur_pos = cur_pos + #key
end
update()
end
--Make sure cursor can't leave string bounds
if cur_pos < 1 then
cur_pos = 1
elseif cur_pos > #text_string + 1 then
cur_pos = #text_string + 1
end
end
end
)
end
--Start the keygrabber when the searchbar is left clicked
searchbar:buttons(gears.table.join(
awful.button({}, 1, function()
if not awful.keygrabber.is_running then
searchbar.s_background.border_color = Theme_config.application_launcher.searchbar.border_active
searchbar.s_background.fg = Theme_config.application_launcher.searchbar.fg
search_text:set_markup(promt_text_with_cursor("", 1))
end
end)
))
capi.awesome.connect_signal(
"searchbar::start",
function()
if not awful.keygrabber.is_running then
keygrabber_start()
searchbar.s_background.border_color = Theme_config.application_launcher.searchbar.border_active
searchbar.s_background.fg = Theme_config.application_launcher.searchbar.fg
search_text:set_markup(promt_text_with_cursor("", 1))
end
end
)
return searchbar
end