yes, I'm very commit lazy
This commit is contained in:
575
awesome/src/modules/audio/audio_controller.lua
Normal file
575
awesome/src/modules/audio/audio_controller.lua
Normal 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 })
|
||||
@@ -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)
|
||||
@@ -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 })
|
||||
|
||||
Reference in New Issue
Block a user