Add application launcher and rewritten window switcher, remove rofi as its no longer needed and replaced by widgets. Fixed a lot of bugs and weird behaviour
This commit is contained in:
@@ -5,17 +5,226 @@
|
||||
-- Awesome Libs
|
||||
local awful = require("awful")
|
||||
local dpi = require("beautiful").xresources.apply_dpi
|
||||
local desktop_parser = require("src.tools.desktop_parser")
|
||||
local gears = require("gears")
|
||||
local wibox = require("wibox")
|
||||
|
||||
return function()
|
||||
|
||||
local application_list = wibox.widget {
|
||||
local desktop_files = desktop_parser.Get_all_visible_desktop()
|
||||
|
||||
local application_grid = wibox.widget {
|
||||
homogenous = true,
|
||||
expand = false,
|
||||
spacing = dpi(10),
|
||||
layout = wibox.container.grid
|
||||
id = "grid",
|
||||
forced_num_cols = 8,
|
||||
forced_num_rows = 7,
|
||||
orientation = "vertical",
|
||||
layout = wibox.layout.grid
|
||||
}
|
||||
-- Selected application position, default is first at 1,1
|
||||
-- The typo *might* be intentional
|
||||
local curser = {
|
||||
x = 1,
|
||||
y = 1
|
||||
}
|
||||
|
||||
return application_list
|
||||
local filter = ""
|
||||
|
||||
---Executes only once to create a widget from each desktop file
|
||||
---@return table widgets Unsorted widget table
|
||||
local function get_applications_from_file()
|
||||
local list = {}
|
||||
for _, file in ipairs(desktop_files) do
|
||||
if not file.nodisplay then
|
||||
local app_widget = wibox.widget {
|
||||
{
|
||||
{
|
||||
{
|
||||
{
|
||||
{ -- Icon
|
||||
valign = "center",
|
||||
halign = "center",
|
||||
image = xdg_icon_lookup:find_icon(file.icon, 64) or "/home/crylia/Bilder/yes.png",
|
||||
resize = true,
|
||||
widget = wibox.widget.imagebox
|
||||
},
|
||||
height = dpi(64),
|
||||
width = dpi(64),
|
||||
strategy = "exact",
|
||||
widget = wibox.container.constraint
|
||||
},
|
||||
{
|
||||
{ -- Name
|
||||
text = file.name,
|
||||
align = "center",
|
||||
valign = "center",
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
strategy = "exact",
|
||||
width = dpi(170),
|
||||
-- Prevents widget from overflowing
|
||||
height = dpi(40),
|
||||
widget = wibox.container.constraint
|
||||
},
|
||||
layout = wibox.layout.fixed.vertical
|
||||
},
|
||||
halign = "center",
|
||||
valign = "center",
|
||||
widget = wibox.container.place
|
||||
},
|
||||
margins = dpi(10),
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
name = file.name,
|
||||
comment = file.comment,
|
||||
exec = file.exec,
|
||||
keywords = file.keywords,
|
||||
categories = file.categories,
|
||||
terminal = file.terminal,
|
||||
border_color = Theme_config.application_launcher.application.border_color,
|
||||
border_width = Theme_config.application_launcher.application.border_width,
|
||||
bg = Theme_config.application_launcher.application.bg,
|
||||
shape = function(cr, width, height)
|
||||
gears.shape.rounded_rect(cr, width, height, dpi(8))
|
||||
end,
|
||||
widget = wibox.container.background
|
||||
}
|
||||
|
||||
-- Execute command on left click and hide launcher
|
||||
app_widget:buttons(
|
||||
gears.table.join(
|
||||
awful.button(
|
||||
{},
|
||||
1,
|
||||
nil,
|
||||
function()
|
||||
awful.spawn.with_shell(file.exec)
|
||||
awesome.emit_signal("application_launcher::show")
|
||||
end
|
||||
)
|
||||
)
|
||||
)
|
||||
table.insert(list, app_widget)
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
-- Table to hold all application widgets unsorted
|
||||
local application_list = get_applications_from_file()
|
||||
|
||||
---Function to filter the applications and sort them into a widget grid
|
||||
---@param search_filter string Filter string from the searchbar
|
||||
---@return wibox.layout.grid wibox.layout.grid Sorted grid with all applications matching the filter
|
||||
local function get_applications(search_filter)
|
||||
filter = search_filter or filter
|
||||
--Clear grid from previous widgets
|
||||
application_grid:reset()
|
||||
-- Reset to first position
|
||||
curser = {
|
||||
x = 1,
|
||||
y = 1
|
||||
}
|
||||
for _, application in ipairs(application_list) do
|
||||
-- Match the filter
|
||||
if string.match(string.lower(application.name), string.lower(filter)) or
|
||||
string.match(string.lower(application.categories), string.lower(filter)) or
|
||||
string.match(string.lower(application.keywords), string.lower(filter)) then
|
||||
application_grid:add(application)
|
||||
|
||||
-- Get the current position in the grid of the application as a table
|
||||
local pos = application_grid:get_widget_position(application)
|
||||
|
||||
-- Check if the curser is currently at the same position as the application
|
||||
awesome.connect_signal(
|
||||
"update::selected",
|
||||
function()
|
||||
if curser.y == pos.row and 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
|
||||
end
|
||||
)
|
||||
awesome.emit_signal("update::selected")
|
||||
Hover_signal(application, Theme_config.application_launcher.application.bg,
|
||||
Theme_config.application_launcher.application.fg, application.border_color)
|
||||
end
|
||||
end
|
||||
|
||||
return application_grid
|
||||
end
|
||||
|
||||
application_grid = get_applications(filter)
|
||||
|
||||
awesome.connect_signal(
|
||||
"application::left",
|
||||
function()
|
||||
curser.x = curser.x - 1
|
||||
if curser.x < 1 then
|
||||
curser.x = 1
|
||||
end
|
||||
awesome.emit_signal("update::selected")
|
||||
end
|
||||
)
|
||||
|
||||
awesome.connect_signal(
|
||||
"application::right",
|
||||
function()
|
||||
curser.x = curser.x + 1
|
||||
local _, grid_cols = application_grid:get_dimension()
|
||||
if curser.x > grid_cols then
|
||||
curser.x = grid_cols
|
||||
end
|
||||
awesome.emit_signal("update::selected")
|
||||
end
|
||||
)
|
||||
|
||||
awesome.connect_signal(
|
||||
"application::up",
|
||||
function()
|
||||
curser.y = curser.y - 1
|
||||
if curser.y < 1 then
|
||||
curser.y = 1
|
||||
end
|
||||
awesome.emit_signal("update::selected")
|
||||
end
|
||||
)
|
||||
|
||||
awesome.connect_signal(
|
||||
"application::down",
|
||||
function()
|
||||
curser.y = curser.y + 1
|
||||
local grid_rows, _ = application_grid:get_dimension()
|
||||
if curser.y > grid_rows then
|
||||
curser.y = grid_rows
|
||||
end
|
||||
awesome.emit_signal("update::selected")
|
||||
end
|
||||
)
|
||||
|
||||
awesome.connect_signal(
|
||||
"update::application_list",
|
||||
function(filter)
|
||||
application_grid = get_applications(filter)
|
||||
end
|
||||
)
|
||||
|
||||
awesome.connect_signal(
|
||||
"application_launcher::execute",
|
||||
function()
|
||||
awesome.emit_signal("searchbar::stop")
|
||||
|
||||
local selected_widget = application_grid:get_widgets_at(curser.y, curser.x)[1]
|
||||
if selected_widget.terminal then
|
||||
awful.spawn.with_shell(selected_widget.exec)
|
||||
else
|
||||
awful.spawn(selected_widget.exec)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
return application_grid
|
||||
end
|
||||
|
||||
@@ -13,20 +13,26 @@ local searchbar = require("src.modules.application_launcher.searchbar")()
|
||||
|
||||
return function(s)
|
||||
|
||||
|
||||
local applicaton_launcher = wibox.widget {
|
||||
{
|
||||
{
|
||||
searchbar,
|
||||
wibox.widget.inputtextbox,
|
||||
application_grid,
|
||||
{
|
||||
application_grid,
|
||||
spacing = dpi(10),
|
||||
layout = require("src.lib.overflow_widget.overflow").vertical,
|
||||
scrollbar_width = 0,
|
||||
step = dpi(50),
|
||||
id = "scroll_bar",
|
||||
},
|
||||
spacing = dpi(10),
|
||||
layout = wibox.layout.fixed.vertical
|
||||
},
|
||||
margins = dpi(20),
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
height = dpi(600),
|
||||
width = dpi(800),
|
||||
height = s.geometry.height / 100 * 60,
|
||||
width = s.geometry.width / 100 * 60,
|
||||
strategy = "exact",
|
||||
widget = wibox.container.constraint
|
||||
}
|
||||
@@ -52,9 +58,14 @@ return function(s)
|
||||
}
|
||||
|
||||
awesome.connect_signal(
|
||||
"application_laucher::show",
|
||||
"application_launcher::show",
|
||||
function()
|
||||
application_container.visible = not application_container.visible
|
||||
if mouse.screen == s then
|
||||
application_container.visible = not application_container.visible
|
||||
end
|
||||
if application_container.visible then
|
||||
awesome.emit_signal("searchbar::start")
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
|
||||
@@ -6,42 +6,62 @@
|
||||
local awful = require("awful")
|
||||
local dpi = require("beautiful").xresources.apply_dpi
|
||||
local gears = require("gears")
|
||||
local gfs = gears.filesystem
|
||||
local gtable = gears.table
|
||||
local gdebug = gears.debug
|
||||
local gstring = gears.string
|
||||
local keygrabber = require("awful.keygrabber")
|
||||
local wibox = require("wibox")
|
||||
|
||||
local icondir = awful.util.getdir("config") .. "src/assets/icons/application_launcher/searchbar/"
|
||||
|
||||
local kgrabber
|
||||
|
||||
return function()
|
||||
|
||||
local searchbar = wibox.widget {
|
||||
{
|
||||
{
|
||||
{
|
||||
{ -- Search icon
|
||||
{ -- Search icon
|
||||
{
|
||||
{
|
||||
resize = false,
|
||||
image = icondir .. "search.svg",
|
||||
valign = "center",
|
||||
halign = "center",
|
||||
image = gears.color.recolor_image(icondir .. "search.svg",
|
||||
Theme_config.application_launcher.searchbar.icon_color),
|
||||
widget = wibox.widget.imagebox
|
||||
},
|
||||
strategy = "exact",
|
||||
widget = wibox.container.constraint
|
||||
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,
|
||||
text = "Search",
|
||||
markup = "Search",
|
||||
valign = "center",
|
||||
align = "center",
|
||||
widget = wibox.widget.textbox
|
||||
widget = wibox.widget.textbox,
|
||||
id = "search_hint"
|
||||
},
|
||||
widget = wibox.layout.fixed.horizontal
|
||||
margins = dpi(5),
|
||||
widget = wibox.container.margin,
|
||||
id = "s_margin"
|
||||
},
|
||||
margins = dpi(5),
|
||||
widget = wibox.container.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
|
||||
widget = wibox.container.background,
|
||||
shape = Theme_config.application_launcher.searchbar.shape,
|
||||
id = "s_background"
|
||||
},
|
||||
width = dpi(400),
|
||||
height = dpi(40),
|
||||
@@ -49,5 +69,184 @@ return function()
|
||||
widget = wibox.container.constraint
|
||||
}
|
||||
|
||||
local old_wibox, old_cursor
|
||||
local mouse_enter = function()
|
||||
local w = 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
|
||||
awesome.emit_signal("update::application_list", text_string)
|
||||
end
|
||||
|
||||
update()
|
||||
|
||||
kgrabber = keygrabber.run(
|
||||
function(modifiers, key, event)
|
||||
awesome.connect_signal("searchbar::stop", function()
|
||||
keygrabber.stop(kgrabber)
|
||||
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 = ""
|
||||
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 = ""
|
||||
awesome.emit_signal("application_launcher::execute")
|
||||
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
|
||||
awesome.emit_signal("application::left")
|
||||
-- Move cursor to the right
|
||||
elseif key == "Right" then
|
||||
--cur_pos = cur_pos + 1
|
||||
awesome.emit_signal("application::right")
|
||||
elseif key == "Up" then
|
||||
awesome.emit_signal("application::up")
|
||||
elseif key == "Down" then
|
||||
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
|
||||
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)
|
||||
))
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user