yes, I'm very commit lazy

This commit is contained in:
2023-03-19 19:22:02 +01:00
parent 4f3fb75687
commit f399235db0
107 changed files with 11120 additions and 10906 deletions

View File

@@ -0,0 +1,575 @@
-- Awesome Libs
local abutton = require('awful.button')
local aspawn = require('awful.spawn')
local base = require('wibox.widget.base')
local dpi = require('beautiful').xresources.apply_dpi
local gcolor = require('gears.color')
local gshape = require('gears.shape')
local gtable = require('gears.table')
local gfilesystem = require('gears.filesystem')
local wibox = require('wibox')
-- Third party libs
local rubato = require('src.lib.rubato')
-- Local libs
local audio_helper = require('src.tools.helpers.audio')
local hover = require('src.tools.hover')
-- Icon directory path
local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/audio/'
local audio_controller = {}
--#region wibox.widget.base boilerplate
function audio_controller:layout(_, width, height)
if self._private.widget then
return { base.place_widget_at(self._private.widget, 0, 0, width, height) }
end
end
function audio_controller:fit(context, width, height)
local w, h = 0, 0 ---@type number|nil, number|nil
if self._private.widget then
w, h = base.fit_widget(self, context, self._private.widget, width, height)
end
return w, h
end
--#endregion
---Set the default source asynchronously
---@param sink any
function audio_controller:set_default_sink(sink)
if not sink then return end
aspawn('pactl set-default-sink ' .. sink)
self:emit_signal('AC::device_changed')
end
---Set the default source asynchronously
function audio_controller:set_default_source(source)
if not source then return end
aspawn('pactl set-default-source ' .. source)
self:emit_signal('AC::device_changed')
end
---Get the default sink asynchronously
---@param callback function returns the default sink as string
function audio_controller:get_default_sink_async(callback)
aspawn.easy_async_with_shell('pactl get-default-sink', function(stdout) callback(stdout:gsub('\n', '')) end)
end
---Takes a sink and name and returns a new device widget, the device_type is for the color
---@param device string sink
---@param name string name of the device
---@param device_type string sink or source
---@return wibox.widget
function audio_controller:get_device_widget(device, name, device_type)
--remove leading spaces from name
name = name:gsub('^%s*(.-)%s*$', '%1')
local icon_color, fg
if device_type == 'source' then
icon_color = Theme_config.volume_controller.device_microphone_fg
fg = Theme_config.volume_controller.device_microphone_fg
elseif device_type == 'sink' then
icon_color = Theme_config.volume_controller.device_headphones_fg
fg = Theme_config.volume_controller.device_headphones_fg
end
local device_widget = wibox.widget {
{
{
{
{
id = 'icon',
resize = true,
image = gcolor.recolor_image(icondir .. 'volume-high.svg', icon_color),
valign = 'center',
halign = 'center',
widget = wibox.widget.imagebox,
},
widget = wibox.container.constraint,
width = dpi(24),
height = dpi(24),
strategy = 'exact',
},
{
{
id = 'name',
text = name,
halign = 'center',
valign = 'center',
widget = wibox.widget.textbox,
},
widget = wibox.container.constraint,
height = dpi(24),
strategy = 'exact',
},
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal,
},
margins = dpi(10),
widget = wibox.container.margin,
},
bg = Theme_config.volume_controller.device_bg,
fg = fg,
border_color = Theme_config.volume_controller.device_border_color,
border_width = Theme_config.volume_controller.device_border_width,
shape = Theme_config.volume_controller.device_shape,
widget = wibox.container.background,
sink = device,
}
if device_type == 'sink' then
device_widget:buttons(gtable.join(
abutton({}, 1, function()
self:set_default_sink(device)
end)
))
elseif device_type == 'source' then
device_widget:buttons(gtable.join(
abutton({}, 1, function()
self:set_default_source(device)
end)
))
end
self:connect_signal('AC::device_changed', function(new_sink)
if device_widget.device == new_sink then
device_widget.bg = Theme_config.volume_controller.device_headphones_selected_bg
device_widget.fg = Theme_config.volume_controller.device_headphones_selected_fg
device_widget:get_children_by_id('icon')[1].image = gcolor.recolor_image(icondir .. 'volume-high.svg', Theme_config.volume_controller.device_headphones_selected_fg)
else
device_widget.bg = Theme_config.volume_controller.device_bg
device_widget.fg = fg
device_widget:get_children_by_id('icon')[1].image = gcolor.recolor_image(icondir .. 'volume-high.svg', icon_color)
end
end)
hover.bg_hover { widget = device_widget }
return device_widget
end
---Get all sink devices
---@param callback function returns a list of sinks
function audio_controller:get_sink_devices_async(callback)
-- This command gets all audio sources and their descriptions in this format: "source_name;source_description\n"
aspawn.easy_async_with_shell([=[
LC_ALL=C pactl list sinks | awk '/Name:/ { name=$0 } /Description:/ { sub(/Name: /, "", name); sub(/Description: /, "", $0); print name ";" $0 }'
]=], function(stdout)
local sinks = wibox.layout.fixed.vertical {}
for line in stdout:gmatch('[^\r\n]+') do
-- Call the callback function with the name and description
local s, n = line:match('(.-);(.+)')
table.insert(sinks, self:get_device_widget(s, n, 'sink'))
end
self.sinks = sinks
callback()
end)
end
---Get all source devices
---@param callback function returns a list of sources
function audio_controller:get_source_devices_async(callback)
-- This command gets all audio sources and their descriptions in this format: "source_name;source_description\n"
aspawn.easy_async_with_shell([=[
LC_ALL=C pactl list sources | awk '/Name:/ { name=$0 } /Description:/ { sub(/Name: /, "", name); sub(/Description: /, "", $0); print name ";" $0 }'
]=], function(stdout)
local sources = wibox.layout.fixed.vertical {}
for line in stdout:gmatch('[^\r\n]+') do
local s, n = line:match('(.-);(.+)')
table.insert(sources, self:get_device_widget(s, n, 'source'))
end
self.sources = sources
callback()
end)
end
---Creates a new audio controller
---@return wibox.widget auio_controller the audio controller widget
function audio_controller.new()
local w = base.make_widget_from_value(wibox.widget {
{
{
{ -- sink Device selector
{
{
resize = false,
image = gcolor.recolor_image(icondir .. 'menu-down.svg',
Theme_config.volume_controller.device_headphones_selected_icon_color),
widget = wibox.widget.imagebox,
valign = 'center',
halign = 'center',
id = 'sink_dd_icon',
},
{
{
text = 'Output Devices',
valign = 'center',
halign = 'center',
widget = wibox.widget.textbox,
},
margins = dpi(5),
widget = wibox.container.margin,
},
layout = wibox.layout.fixed.horizontal,
},
id = 'sink_dd_shape',
bg = Theme_config.volume_controller.list_bg,
fg = Theme_config.volume_controller.list_headphones_fg,
shape = Theme_config.volume_controller.list_shape,
widget = wibox.container.background,
},
{ -- sink dropdown
{
{
{
spacing = dpi(10),
layout = require('src.lib.overflow_widget.overflow').vertical,
scrollbar_width = 0,
step = dpi(50),
id = 'sink_list',
},
margins = dpi(10),
widget = wibox.container.margin,
},
border_color = Theme_config.volume_controller.list_border_color,
border_width = Theme_config.volume_controller.list_border_width,
id = 'sink_list_shape',
shape = Theme_config.volume_controller.list_shape,
widget = wibox.container.background,
},
id = 'sink_height',
strategy = 'exact',
height = 0,
width = dpi(300),
widget = wibox.container.constraint,
},
{ -- Spacer
widget = wibox.container.background,
forced_height = dpi(10),
},
{ -- source Device selector
{
{
resize = false,
image = gcolor.recolor_image(icondir .. 'menu-down.svg',
Theme_config.volume_controller.device_headphones_selected_icon_color),
widget = wibox.widget.imagebox,
valign = 'center',
halign = 'center',
id = 'source_dd_icon',
},
{
{
text = 'Input Devices',
valign = 'center',
halign = 'center',
widget = wibox.widget.textbox,
},
margins = dpi(5),
widget = wibox.container.margin,
},
layout = wibox.layout.fixed.horizontal,
},
id = 'source_dd_shape',
bg = Theme_config.volume_controller.list_bg,
fg = Theme_config.volume_controller.list_headphones_fg,
shape = Theme_config.volume_controller.list_shape,
widget = wibox.container.background,
},
{ -- source dropdown
{
{
{
spacing = dpi(10),
layout = require('src.lib.overflow_widget.overflow').vertical,
scrollbar_width = 0,
step = dpi(50),
id = 'source_list',
},
margins = dpi(10),
widget = wibox.container.margin,
},
border_color = Theme_config.volume_controller.list_border_color,
border_width = Theme_config.volume_controller.list_border_width,
id = 'source_list_shape',
shape = Theme_config.volume_controller.list_shape,
widget = wibox.container.background,
},
id = 'source_height',
strategy = 'exact',
height = 0,
width = dpi(300),
widget = wibox.container.constraint,
},
{ -- Spacer
widget = wibox.container.background,
forced_height = dpi(10),
},
{ -- sink volume slider
{
{
{
resize = true,
widget = wibox.widget.imagebox,
valign = 'center',
halign = 'center',
image = gcolor.recolor_image(icondir .. 'volume-high.svg', Theme_config.volume_controller.volume_fg),
id = 'sink_icon',
},
widget = wibox.container.constraint,
width = dpi(26),
height = dpi(26),
strategy = 'exact',
},
{
bar_shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, dpi(5))
end,
bar_height = dpi(5),
bar_color = Theme_config.volume_controller.border_color,
bar_active_color = Theme_config.volume_controller.volume_fg,
handle_color = Theme_config.volume_controller.volume_fg,
handle_shape = gshape.circle,
handle_border_color = Theme_config.volume_controller.volume_fg,
handle_width = dpi(15),
handle_cursor = 'left_ptr',
maximum = 100,
forced_height = 0, -- No idea why its needed but it makes the widget not go into infinity
value = 50,
widget = wibox.widget.slider,
id = 'sink_slider',
},
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal,
},
widget = wibox.container.constraint,
width = dpi(300),
height = dpi(26),
strategy = 'exact',
},
{ -- Spacer
widget = wibox.container.background,
forced_height = dpi(10),
},
{ -- source volume slider
{
{
{
resize = true,
widget = wibox.widget.imagebox,
valign = 'center',
halign = 'center',
image = gcolor.recolor_image(icondir .. 'microphone.svg', Theme_config.volume_controller.volume_fg),
id = 'source_icon',
},
widget = wibox.container.constraint,
width = dpi(26),
height = dpi(26),
strategy = 'exact',
},
{
bar_shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, dpi(5))
end,
bar_height = dpi(5),
bar_color = Theme_config.volume_controller.border_color,
bar_active_color = Theme_config.volume_controller.volume_fg,
handle_color = Theme_config.volume_controller.volume_fg,
handle_shape = gshape.circle,
handle_border_color = Theme_config.volume_controller.volume_fg,
handle_width = dpi(15),
handle_cursor = 'left_ptr',
maximum = 100,
forced_height = 0, -- No idea why its needed but it makes the widget not go into infinity
value = 50,
widget = wibox.widget.slider,
id = 'source_slider',
},
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal,
},
widget = wibox.container.constraint,
width = dpi(400),
height = dpi(26),
strategy = 'exact',
},
layout = wibox.layout.fixed.vertical,
},
margins = dpi(15),
widget = wibox.container.margin,
},
-- The parent margin doesn't render without an empty widget here???
widget = wibox.container.margin,
})
assert(w, 'Failed to create volume controller widget')
gtable.crush(w, audio_controller, true)
local sink_icon = w:get_children_by_id('sink_icon')[1]
local sink_slider = w:get_children_by_id('sink_slider')[1]
sink_slider:connect_signal('property::value', function(_, value)
audio_helper.set_sink_volume(value)
end)
-- Set the volume and icon
audio_helper:connect_signal('sink::get', function(_, muted, volume)
volume = tonumber(volume)
assert(type(muted) == 'boolean' and type(volume) == 'number', 'audio::get signal expects boolean and number')
if w.sink_volume == volume and w.sink_muted == muted then return end
w.sink_volume = volume
w.sink_muted = muted
if muted then
sink_icon:set_image(gcolor.recolor_image(icondir .. 'volume-mute.svg', Theme_config.volume_controller.volume_fg))
else
local icon = icondir .. 'volume'
if volume == 0 then
icon = icon .. '-mute'
elseif volume > 0 and volume < 34 then
icon = icon .. '-low'
elseif volume >= 34 and volume < 67 then
icon = icon .. '-medium'
elseif volume >= 67 then
icon = icon .. '-high'
end
sink_slider:set_value(volume)
sink_icon:set_image(gcolor.recolor_image(icon .. '.svg', Theme_config.volume_controller.volume_fg))
end
end)
local source_icon = w:get_children_by_id('source_icon')[1]
local source_slider = w:get_children_by_id('source_slider')[1]
-- Microphone slider change event
source_slider:connect_signal('property::value', function(_, value)
audio_helper.set_source_volume(value)
end)
--- Set the source volume and icon
audio_helper:connect_signal('source::get', function(_, muted, volume)
volume = tonumber(volume)
assert(type(muted) == 'boolean' and type(volume) == 'number', 'microphone::get signal expects boolean and number')
if w.source_volume == volume and w.source_muted == muted then return end
w.source_volume = volume
w.source_muted = muted
if muted then
source_icon:set_image(gcolor.recolor_image(icondir .. 'microphone-off.svg', Theme_config.volume_controller.microphone_fg))
else
if not volume then return end
source_slider:set_value(tonumber(volume))
if volume > 0 then
source_icon:set_image(gcolor.recolor_image(icondir .. 'microphone.svg', Theme_config.volume_controller.microphone_fg))
else
source_icon:set_image(gcolor.recolor_image(icondir .. 'microphone-off.svg', Theme_config.volume_controller.microphone_fg))
end
end
end)
local sink_dd_shape = w:get_children_by_id('sink_dd_shape')[1]
local sink_height = w:get_children_by_id('sink_height')[1]
local sink_dd_icon = w:get_children_by_id('sink_dd_icon')[1]
local rubato_timer = rubato.timed {
duration = 0.2,
pos = sink_height.height,
clamp_position = true,
subscribed = function(v)
sink_height.height = v
end,
}
sink_dd_shape:buttons(gtable.join {
abutton({}, 1, function()
if sink_height.height == 0 then
local size = dpi((#w.sinks * 44) + ((#w.sinks - 1) * 10) + 20)
if #w.sinks > 4 then
size = dpi(226)
end
rubato_timer.target = size
sink_dd_shape.shape = function(cr, width, height)
gshape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4))
end
sink_dd_icon:set_image(gcolor.recolor_image(icondir .. 'menu-up.svg',
Theme_config.volume_controller.device_headphones_selected_icon_color))
else
rubato_timer.target = 0
sink_dd_shape.shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, 4)
end
sink_dd_icon:set_image(gcolor.recolor_image(icondir .. 'menu-down.svg',
Theme_config.volume_controller.device_headphones_selected_icon_color))
end
end),
})
local source_dd_shape = w:get_children_by_id('source_dd_shape')[1]
local source_height = w:get_children_by_id('source_height')[1]
local source_dd_icon = w:get_children_by_id('source_dd_icon')[1]
local rubato_timer = rubato.timed {
duration = 0.2,
pos = source_height.height,
clamp_position = true,
subscribed = function(v)
source_height.height = v
end,
}
source_dd_shape:buttons(gtable.join {
abutton({}, 1, function()
if source_height.height == 0 then
local size = dpi(((#w.sources * 44) + ((#w.sources - 1) * 10) + 20))
if #w.sources > 4 then
size = dpi(226)
end
rubato_timer.target = size
source_dd_shape.shape = function(cr, width, height)
gshape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4))
end
source_dd_icon:set_image(gcolor.recolor_image(icondir .. 'menu-up.svg',
Theme_config.volume_controller.device_headphones_selected_icon_color))
else
rubato_timer.target = 0
source_dd_shape.shape = function(cr, width, height)
gshape.rounded_rect(cr, width, height, 4)
end
source_dd_icon:set_image(gcolor.recolor_image(icondir .. 'menu-down.svg',
Theme_config.volume_controller.device_headphones_selected_icon_color))
end
end),
})
local sink_list = w:get_children_by_id('sink_list')[1]
w:get_sink_devices_async(function()
sink_list.children = w.sinks
end)
local source_list = w:get_children_by_id('source_list')[1]
w:get_source_devices_async(function()
source_list.children = w.sources
end)
hover.bg_hover { widget = sink_dd_shape }
hover.bg_hover { widget = source_dd_shape }
return w
end
return setmetatable(audio_controller, { __call = function() return audio_controller.new() end })

View File

@@ -1,553 +0,0 @@
-----------------------------------
-- This is the volume controller --
-----------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local gobject = require("gears.object")
local capi = {
awesome = awesome,
mousegrabber = mousegrabber,
}
local rubato = require("src.lib.rubato")
-- Icon directory path
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/audio/"
local volume_controler = { mt = {} }
function volume_controler.get_device_widget()
local device = wibox.widget {
{
{
{
id = "icon",
resize = false,
valign = "center",
halign = "center",
widget = wibox.widget.imagebox
},
spacing = dpi(10),
{
text = name,
id = "node",
widget = wibox.widget.textbox
},
id = "device_layout",
layout = wibox.layout.fixed.horizontal
},
id = "device_margin",
margins = dpi(9),
widget = wibox.container.margin
},
id = "background",
bg = Theme_config.volume_controller.device_bg,
border_color = Theme_config.volume_controller.device_border_color,
border_width = Theme_config.volume_controller.device_border_width,
shape = Theme_config.volume_controller.device_shape,
widget = wibox.container.background
}
if true then
device:connect_signal(
"button::press",
function(_, _, _, key)
if key == 1 then
if node then
--awful.spawn("./.config/awesome/src/scripts/vol.sh set_sink " .. node)
--capi.awesome.emit_signal("update::bg_sink", node)
end
end
end
)
--[[ capi.awesome.connect_signal(
"update::bg_sink",
function(new_node)
if node == new_node then
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "headphones.svg",
Theme_config.volume_controller.device_icon_color)
device.bg = Theme_config.volume_controller.device_headphones_selected_bg
device.fg = Theme_config.volume_controller.device_headphones_selected_fg
Hover_signal(device)
else
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "headphones.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color)
device.bg = Theme_config.volume_controller.device_bg
device.fg = Theme_config.volume_controller.device_headphones_fg
Hover_signal(device)
end
end
) ]]
else
device:connect_signal(
"button::press",
function(_, _, _, key)
if key == 1 then
if node then
--awful.spawn("./.config/awesome/src/scripts/mic.sh set_source " .. node)
--capi.awesome.emit_signal("update::bg_source", node)
end
end
end
)
--[[ capi.awesome.connect_signal(
"update::bg_source",
function(new_node)
if node == new_node then
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "microphone.svg",
Theme_config.volume_controller.device_icon_color)
device.bg = Theme_config.volume_controller.device_microphone_selected_bg
device.fg = Theme_config.volume_controller.device_microphone_selected_fg
Hover_signal(device)
else
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "microphone.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color)
device.bg = Theme_config.volume_controller.device_bg
device.fg = Theme_config.volume_controller.device_microphone_fg
Hover_signal(device)
end
end
) ]]
end
return device
end
-- Get all source devices
function volume_controler:get_source_devices()
end
-- Get all input devices
function volume_controler:get_input_devices()
end
function volume_controler:toggle()
volume_controler.popup.visible = not volume_controler.popup.visible
end
function volume_controler.run(args)
args = args or {}
local ret = gobject {}
local w = wibox.widget {
{
{
-- Audio Device selector
{
{
{
{
{
resize = false,
image = gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color),
widget = wibox.widget.imagebox,
valign = "center",
halign = "center",
id = "icon"
},
id = "center",
halign = "center",
valign = "center",
widget = wibox.container.place,
},
{
{
text = "Output Device",
widget = wibox.widget.textbox,
id = "device_name"
},
margins = dpi(5),
widget = wibox.container.margin
},
id = "audio_volume",
layout = wibox.layout.fixed.horizontal
},
id = "audio_bg",
bg = Theme_config.volume_controller.list_bg,
fg = Theme_config.volume_controller.list_headphones_fg,
shape = Theme_config.volume_controller.list_shape,
widget = wibox.container.background
},
id = "audio_selector_margin",
left = dpi(10),
right = dpi(10),
top = dpi(10),
widget = wibox.container.margin
},
{
id = "volume_list",
widget = {
{
{
{
{
spacing = dpi(10),
layout = require("src.lib.overflow_widget.overflow").vertical,
scrollbar_width = 0,
step = dpi(50),
id = "volume_device_list",
},
id = "margin",
margins = dpi(10),
widget = wibox.container.margin
},
id = "place",
height = dpi(200),
strategy = "max",
widget = wibox.container.constraint
},
border_color = Theme_config.volume_controller.list_border_color,
border_width = Theme_config.volume_controller.list_border_width,
id = "volume_device_background",
shape = Theme_config.volume_controller.list_shape,
widget = wibox.container.background
},
left = dpi(10),
right = dpi(10),
widget = wibox.container.margin
},
forced_height = 0
},
-- Microphone selector
{
{
{
{
{
resize = false,
image = gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color),
widget = wibox.widget.imagebox,
valign = "center",
halign = "center",
id = "icon",
},
id = "center",
halign = "center",
valign = "center",
widget = wibox.container.place,
},
{
{
text = "Input Device",
widget = wibox.widget.textbox,
id = "device_name"
},
margins = dpi(5),
widget = wibox.container.margin
},
id = "mic_volume",
layout = wibox.layout.fixed.horizontal
},
id = "mic_bg",
bg = Theme_config.volume_controller.list_bg,
fg = Theme_config.volume_controller.list_microphone_fg,
shape = Theme_config.volume_controller.selector_shape,
widget = wibox.container.background
},
id = "mic_selector_margin",
left = dpi(10),
right = dpi(10),
top = dpi(10),
widget = wibox.container.margin
},
{
id = "mic_list",
widget = {
{
{
{
{
spacing = dpi(10),
layout = require("src.lib.overflow_widget.overflow").vertical,
id = "volume_device_list",
scrollbar_width = 0,
step = dpi(50),
},
id = "margin",
margins = dpi(10),
widget = wibox.container.margin
},
id = "place",
height = dpi(200),
strategy = "max",
widget = wibox.container.constraint
},
id = "volume_device_background",
border_color = Theme_config.volume_controller.list_border_color,
border_width = Theme_config.volume_controller.list_border_width,
shape = Theme_config.volume_controller.list_shape,
widget = wibox.container.background
},
left = dpi(10),
right = dpi(10),
widget = wibox.container.margin
},
forced_height = 0
},
-- Audio volume slider
{
{
{
resize = false,
widget = wibox.widget.imagebox,
valign = "center",
halign = "center",
image = gears.color.recolor_image(icondir .. "volume-high.svg", Theme_config.volume_controller.volume_fg),
id = "icon",
},
{
{
bar_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(5))
end,
bar_height = dpi(5),
bar_color = Theme_config.volume_controller.border_color,
bar_active_color = Theme_config.volume_controller.volume_fg,
handle_color = Theme_config.volume_controller.volume_fg,
handle_shape = gears.shape.circle,
handle_border_color = Theme_config.volume_controller.volume_fg,
handle_width = dpi(12),
maximum = 100,
forced_height = dpi(26),
widget = wibox.widget.slider,
id = "slider"
},
left = dpi(5),
id = "slider_margin",
widget = wibox.container.margin
},
id = "audio_volume",
layout = wibox.layout.align.horizontal
},
id = "audio_volume_margin",
top = dpi(10),
left = dpi(10),
right = dpi(10),
widget = wibox.container.margin
},
-- Microphone volume slider
{
{
{
resize = false,
widget = wibox.widget.imagebox,
valign = "center",
halign = "center",
image = gears.color.recolor_image(icondir .. "microphone.svg", Theme_config.volume_controller.microphone_fg),
id = "icon"
},
{
{
bar_shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(5))
end,
bar_height = dpi(5),
bar_color = Theme_config.volume_controller.device_border_color,
bar_active_color = Theme_config.volume_controller.microphone_fg,
handle_color = Theme_config.volume_controller.microphone_fg,
handle_shape = gears.shape.circle,
handle_border_color = Theme_config.volume_controller.microphone_fg,
handle_width = dpi(12),
maximum = 100,
forced_height = dpi(26),
widget = wibox.widget.slider,
id = "slider"
},
left = dpi(5),
id = "slider_margin",
widget = wibox.container.margin
},
id = "mic_volume",
layout = wibox.layout.align.horizontal
},
id = "mic_volume_margin",
left = dpi(10),
right = dpi(10),
top = dpi(10),
widget = wibox.container.margin
},
id = "controller_layout",
layout = wibox.layout.fixed.vertical
},
id = "controller_margin",
margins = dpi(10),
widget = wibox.container.margin
},
bg = Theme_config.volume_controller.bg,
border_color = Theme_config.volume_controller.border_color,
border_width = Theme_config.volume_controller.border_width,
shape = Theme_config.volume_controller.shape,
forced_width = dpi(400),
widget = wibox.container.background
}
ret.widget = w
ret.audio_dropdown = w:get_children_by_id("audio_list")[1]
ret.mic_dropdown = w:get_children_by_id("mic_list")[1]
ret.audio_slider = w:get_children_by_id("slider")[1]
ret.mic_slider = w:get_children_by_id("slider")[1]
-- Main container
ret.popup = awful.popup {
widget = w,
ontop = true,
bg = Theme_config.volume_controller.bg,
stretch = false,
visible = false,
screen = args.screen,
--! Calculate the popup position instead of hardcoding it
placement = function(c) awful.placement.align(c,
{ position = "top_right", margins = { right = dpi(305), top = dpi(60) } })
end,
shape = Theme_config.volume_controller.shape,
}
-- Set the volume and icon
capi.awesome.connect_signal(
"audio::get",
function(muted, volume)
if muted then
volume_controller.controller_margin.controller_layout.audio_volume_margin.audio_volume.icon:set_image(gears.color
.recolor_image(icondir .. "volume-mute.svg", Theme_config.volume_controller.volume_fg))
else
volume = tonumber(volume)
if not volume then
return
end
local icon = icondir .. "volume"
if volume < 1 then
icon = icon .. "-mute"
elseif volume >= 1 and volume < 34 then
icon = icon .. "-low"
elseif volume >= 34 and volume < 67 then
icon = icon .. "-medium"
elseif volume >= 67 then
icon = icon .. "-high"
end
volume_controller.controller_margin.controller_layout.audio_volume_margin.audio_volume.slider_margin.slider:
set_value(volume)
volume_controller.controller_margin.controller_layout.audio_volume_margin.audio_volume.icon:set_image(gears.color
.recolor_image(icon
.. ".svg", Theme_config.volume_controller.volume_fg))
end
end
)
-- Get microphone volume
capi.awesome.connect_signal(
"microphone::get",
function(muted, volume)
if muted then
--volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.slider_margin.slider:set_value(tonumber(0))
volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.icon:set_image(gears.color.recolor_image(icondir
.. "microphone-off.svg", Theme_config.volume_controller.microphone_fg))
else
volume = tonumber(volume)
if not volume then
return
end
volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.slider_margin.slider:set_value(tonumber(volume))
if volume > 0 then
volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.icon:set_image(gears.color.recolor_image(icondir
.. "microphone.svg", Theme_config.volume_controller.microphone_fg))
else
volume_controller:get_children_by_id("mic_volume_margin")[1].mic_volume.icon:set_image(gears.color.recolor_image(icondir
.. "microphone-off.svg", Theme_config.volume_controller.microphone_fg))
end
end
end
)
-- Microphone slider change event
ret.widget:connect_signal(
"property::value",
function()
end
)
-- Slide animation
ret.audio_dropdown:connect_signal(
"button::press",
function(_, _, _, key)
if key == 1 then
local rubato_timer = rubato.timed {
duration = 0.4,
intro = 0.1,
outro = 0.1,
pos = mic_list.forced_height,
easing = rubato.linear,
subscribed = function(v)
mic_list.forced_height = v
end
}
if mic_list.forced_height == 0 then
rubato_timer.target = dpi(200)
mic_selector_margin.mic_bg.shape = function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4))
end
mic_volume.icon:set_image(gears.color.recolor_image(icondir .. "menu-up.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color))
else
rubato_timer.target = 0
mic_bg.shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(4))
end
mic_volume.icon:set_image(gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color))
end
end
end
)
-- Slide animation
ret.mic_dropdown:connect_signal(
"button::press",
function(_, _, _, key)
if key == 1 then
local rubato_timer = rubato.timed {
duration = 0.4,
intro = 0.1,
outro = 0.1,
pos = volume_list.forced_height,
easing = rubato.linear,
subscribed = function(v)
volume_list.forced_height = v
end
}
if volume_list.forced_height == 0 then
rubato_timer.target = dpi(200)
audio_bg.shape = function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4))
end
audio_volume.icon:set_image(gears.color.recolor_image(icondir .. "menu-up.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color))
else
rubato_timer.target = 0
audio_bg.shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(4))
end
audio_volume.icon:set_image(gears.color.recolor_image(icondir .. "menu-down.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color))
end
end
end
)
return ret
end
function volume_controler.mt:__call(...)
return volume_controler.run(...)
end
return setmetatable(volume_controler, volume_controler.mt)

View File

@@ -3,151 +3,136 @@
-----------------------------------
-- Awesome Libs
local awful = require("awful")
local dpi = require("beautiful").xresources.apply_dpi
local gears = require("gears")
local wibox = require("wibox")
local gobject = require("gears.object")
local aplacement = require('awful.placement')
local apopup = require('awful.popup')
local dpi = require('beautiful').xresources.apply_dpi
local gcolor = require('gears.color')
local gfilesystem = require('gears.filesystem')
local gshape = require('gears.shape')
local gtable = require('gears.table')
local gtimer = require('gears.timer')
local wibox = require('wibox')
local capi = {
awesome = awesome,
mouse = mouse,
}
local audio_helper = require('src.tools.helpers.audio')
-- Icon directory path
local icondir = gears.filesystem.get_configuration_dir() .. "src/assets/icons/audio/"
local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/audio/'
local osd = { mt = {} }
local osd = {}
function osd:run()
self.visible = true
if self.timer.started then
self.timer:again()
else
self.timer:start()
end
end
function osd.new(args)
args = args or {}
args.screen = args.screen or 1
local ret = gobject {}
ret.w = wibox.widget {
{
local w = apopup {
widget = {
{
{ -- Volume Icon
image = gears.color.recolor_image(icondir .. "volume-high.svg", Theme_config.volume_osd.icon_color),
valign = "center",
halign = "center",
resize = false,
id = "icon",
widget = wibox.widget.imagebox
},
{ -- Volume Bar
{
{
{ -- Volume Icon
{
id = "progressbar1",
color = Theme_config.volume_osd.bar_bg_active,
background_color = Theme_config.volume_osd.bar_bg,
max_value = 100,
value = 50,
forced_height = dpi(6),
shape = function(cr, width, heigth)
gears.shape.rounded_bar(cr, width, heigth, dpi(6))
end,
widget = wibox.widget.progressbar
image = gcolor.recolor_image(icondir .. 'volume-off.svg', Theme_config.volume_osd.icon_color),
valign = 'center',
halign = 'center',
resize = true,
id = 'icon_role',
widget = wibox.widget.imagebox,
},
id = "progressbar_container2",
halign = "center",
valign = "center",
widget = wibox.container.place
widget = wibox.container.constraint,
width = dpi(25),
height = dpi(25),
strategy = 'exact',
},
id = "progressbar_container",
width = dpi(240),
heigth = dpi(20),
stragety = "max",
widget = wibox.container.constraint
{ -- Volume Bar
{
{
id = 'progressbar',
color = Theme_config.volume_osd.bar_bg_active,
background_color = Theme_config.volume_osd.bar_bg,
max_value = 100,
value = 0,
shape = gshape.rounded_rect,
widget = wibox.widget.progressbar,
},
widget = wibox.container.constraint,
width = dpi(250),
height = dpi(5),
},
widget = wibox.container.place,
},
{ -- Volume text
widget = wibox.widget.textbox,
id = 'text_role',
text = '0',
valign = 'center',
halign = 'center',
},
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal,
},
id = "layout1",
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal
left = dpi(10),
right = dpi(10),
top = dpi(20),
bottom = dpi(20),
widget = wibox.container.margin,
},
id = "margin",
margins = dpi(10),
widget = wibox.container.margin
shape = Theme_config.volume_osd.shape,
widget = wibox.container.background,
},
forced_width = dpi(300),
forced_height = dpi(80),
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(12))
end,
ontop = true,
stretch = false,
visible = false,
border_color = Theme_config.volume_osd.border_color,
border_width = Theme_config.volume_osd.border_width,
fg = Theme_config.volume_osd.fg,
bg = Theme_config.volume_osd.bg,
widget = wibox.container.background
screen = 1,
placement = function(c) aplacement.bottom(c, { margins = dpi(20) }) end,
}
local volume_container = awful.popup {
widget = ret.w,
ontop = true,
stretch = false,
visible = false,
screen = args.screen,
placement = function(c) awful.placement.bottom_left(c, { margins = dpi(20) }) end,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, dpi(14))
end
}
gtable.crush(w, osd)
local hide_volume_osd = gears.timer {
w.timer = gtimer {
timeout = 2,
autostart = true,
callback = function()
volume_container.visible = false
end
w.visible = false
end,
}
capi.awesome.connect_signal(
"audio::get",
function(muted, volume)
if muted then
ret.w:get_children_by_id("icon")[1]
:set_image(gears.color.recolor_image(
icondir .. "volume-mute" .. ".svg", Theme_config.volume_osd.icon_color))
ret.w:get_children_by_id("progressbar1")[1].value = tonumber(0)
else
volume = tonumber(volume)
if not volume then
return
end
ret.w:get_children_by_id("progressbar1")[1].value = tonumber(volume)
local icon = icondir .. "volume"
if volume < 1 then
icon = icon .. "-mute"
elseif volume >= 1 and volume < 34 then
icon = icon .. "-low"
elseif volume >= 34 and volume < 67 then
icon = icon .. "-medium"
elseif volume >= 67 then
icon = icon .. "-high"
end
ret.w:get_children_by_id("icon")[1]:set_image(gears.color.recolor_image(icon .. ".svg",
Theme_config.volume_osd.icon_color))
audio_helper:connect_signal('output::get', function(_, muted, volume)
volume = tonumber(volume or 0)
if muted then
w.widget:get_children_by_id('icon_role')[1]:set_image(gcolor.recolor_image(icondir .. 'volume-mute' .. '.svg', Theme_config.volume_osd.icon_color))
w.widget:get_children_by_id('progressbar')[1].value = 0
else
w.widget:get_children_by_id('progressbar')[1].value = volume
local icon = icondir .. 'volume'
if volume < 1 then
icon = icon .. '-mute'
elseif volume >= 1 and volume < 34 then
icon = icon .. '-low'
elseif volume >= 34 and volume < 67 then
icon = icon .. '-medium'
elseif volume >= 67 then
icon = icon .. '-high'
end
end
)
capi.awesome.connect_signal(
"widget::volume_osd:rerun",
function()
if capi.mouse.screen == args.screen then
volume_container.visible = true
if hide_volume_osd.started then
hide_volume_osd:again()
else
hide_volume_osd:start()
end
end
w.widget:get_children_by_id('icon_role')[1]:set_image(gcolor.recolor_image(icon .. '.svg', Theme_config.volume_osd.icon_color))
w.widget:get_children_by_id('text_role')[1].text = volume
end
)
w:run()
end)
return w
end
function osd.mt:__call(...)
return osd.new(...)
end
return setmetatable(osd, osd.mt)
return setmetatable(osd, { __call = function(_, ...) return osd.new(...) end })