forked from cedlemo/blingbling
/
volume.lua
368 lines (312 loc) · 11.8 KB
/
volume.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
-- @author cedlemo
local setmetatable = setmetatable
local ipairs = ipairs
local math = math
local table = table
local type = type
local string = string
local color = require("gears.color")
local base = require("wibox.widget.base")
local helpers = require("blingbling.helpers")
local awful = require("awful")
local superproperties = require('blingbling.superproperties')
local volume = { mt = {} }
local data = setmetatable({}, { __mode = "k" })
local properties = {"width", "height", "v_margin", "h_margin", "background_color", "graph_background_color", "graph_color","show_text", "text_color", "background_text_color" ,"label", "font_size", "bar"}
function volume.draw(volume_graph, wibox, cr, width, height)
local v_margin = superproperties.v_margin
if data[volume_graph].v_margin and data[volume_graph].v_margin <= data[volume_graph].height/4 then
v_margin = data[volume_graph].v_margin
end
local h_margin = superproperties.h_margin
if data[volume_graph].h_margin and data[volume_graph].h_margin <= data[volume_graph].width / 3 then
h_margin = data[volume_graph].h_margin
end
local background_border = data[volume_graph].background_border or superproperties.background_border
local background_color = data[volume_graph].background_color or superproperties.background_color
local rounded_size = data[volume_graph].rounded_size or superproperties.rounded_size
local graph_background_color = data[volume_graph].graph_background_color or superproperties.graph_background_color
local graph_color = data[volume_graph].graph_color or superproperties.graph_color
local graph_line_color = data[volume_graph].graph_line_color or superproperties.graph_line_color
local text_color = data[volume_graph].text_color or superproperties.text_color
local background_text_color = data[volume_graph].background_text_color or superproperties.background_text_color
local font_size =data[volume_graph].font_size or superproperties.font_size
r,g,b,a = helpers.hexadecimal_to_rgba_percent(background_color)
cr:set_source_rgba(r,g,b,a)
cr:paint()
--Drawn the volume_graph
if data[volume_graph].bar == true then
--4 bar are use to represent data:
--bar width:
local nb_bar=5
local bar_separator = 2
local bar_width
bar_width=math.floor((data[volume_graph].width -((2*h_margin) + ((nb_bar - 1) * bar_separator)))/nb_bar)
local h_rest =data[volume_graph].width -( 2*h_margin +((nb_bar -1)*bar_separator) + nb_bar * bar_width)
if h_rest ==2 or h_rest == 3 then
h_rest = 1
end
if h_rest == 4 then
h_rest = 2
end
--Drawn background graph
x=h_margin+h_rest
y=data[volume_graph].height - v_margin
for i=1, nb_bar do
cr:rectangle(x,y-((0.2*i)*(data[volume_graph].height - 2*v_margin)),bar_width,((0.2*i)*(data[volume_graph].height - 2*v_margin)))
x=x+(bar_width + bar_separator)
end
r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_background_color)
cr:set_source_rgba(r, g, b, a)
cr:fill()
--Drawn the graph
if data[volume_graph].value > 0 then
--find nb column to drawn:
local ranges={0,0.2,0.4,0.6,0.8,1,1.2}
nb_bar=0
for i, limite in ipairs(ranges) do
if data[volume_graph].value < limite then
--helpers.dbg({data[volume_graph].value, limite})
nb_bar = i-1
break
end
end
x=h_margin+h_rest
y=data[volume_graph].height - v_margin
for i=1, nb_bar do
if i ~= nb_bar then
cr:rectangle(x,y-((0.2*i)*(data[volume_graph].height - 2*v_margin)),bar_width,(0.2*i)*(data[volume_graph].height - 2*v_margin))
x=x+(bar_width + bar_separator)
else
val_to_display =data[volume_graph].value - ((nb_bar-1) * 0.2)
cr:rectangle(x,y-((0.2*i)*(data[volume_graph].height - 2*v_margin)),bar_width * (val_to_display/0.2),(0.2*i)*(data[volume_graph].height - 2*v_margin))
end
end
r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_color)
cr:set_source_rgba(r, g, b, a)
cr:fill()
end
else
x=h_margin
y=data[volume_graph].height-(v_margin)
cr:new_path()
cr:move_to(x,y)
cr:line_to(x,y)
y_range=data[volume_graph].height - (2 * v_margin)
cr:line_to(data[volume_graph].width + h_margin,data[volume_graph].height -( v_margin + y_range ))
cr:line_to(data[volume_graph].width + h_margin, data[volume_graph].height - (v_margin ))
cr:line_to(h_margin,data[volume_graph].height-(v_margin))
cr:close_path()
r,g,b,a = helpers.hexadecimal_to_rgba_percent(graph_background_color)
cr:set_source_rgba(r, g, b,a)
cr:fill()
if data[volume_graph].value > 0 then
x=h_margin
y=data[volume_graph].height-(v_margin)
cr:new_path()
cr:move_to(x,y)
cr:line_to(x,y)
y_range=data[volume_graph].height - (2 * v_margin)
cr:line_to(data[volume_graph].width * data[volume_graph].value + h_margin,data[volume_graph].height -( v_margin + (y_range * data[volume_graph].value)))
cr:line_to(data[volume_graph].width * data[volume_graph].value + h_margin, data[volume_graph].height - (v_margin ))
cr:line_to(0+h_margin,data[volume_graph].height-(v_margin))
cr:close_path()
r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_color)
cr:set_source_rgba(r, g, b, a)
cr:fill()
x=0+h_margin
y=data[volume_graph].height-(v_margin)
cr:new_path()
cr:move_to(x,y)
cr:line_to(x,y)
y_range=data[volume_graph].height - (2 * v_margin)
cr:line_to((data[volume_graph].width * data[volume_graph].value) + h_margin ,data[volume_graph].height -( v_margin + (y_range * data[volume_graph].value)))
cr:line_to((data[volume_graph].width * data[volume_graph].value) - h_margin, data[volume_graph].height - (v_margin ))
cr:set_antialias("subpixel")
cr:set_line_width(1)
r,g,b,a=helpers.hexadecimal_to_rgba_percent(data[volume_graph].graph_line_color)
cr:set_source_rgb(r, g, b)
cr:stroke()
end
end
--Draw Text and it's background
if data[volume_graph].show_text == true then
cr:set_font_size(font_size)
local value = data[volume_graph].value * 100
if data[volume_graph].label then
text=string.gsub(data[volume_graph].label,"$percent", value)
else
text=value .. "%"
end
helpers.draw_text_and_background(cr,
text,
h_margin,
(data[volume_graph].height/2) ,
background_text_color,
text_color,
false,
true,
false,
false)
end
end
function volume.fit(volume_graph, width, height)
return data[volume_graph].width, data[volume_graph].height
end
--- Set the graphtype value.
-- @param volume_graph The progress bar.
-- @param value The progress bar value between 0 and 1.
local function set_value(volume_graph, value)
if not volume_graph then return end
local value = value or 0
local max_value = data[volume_graph].max_value
data[volume_graph].value = math.min(max_value, math.max(0, value))
volume_graph:emit_signal("widget::updated")
return volume_graph
end
local function get_master_infos()
local f=io.popen("amixer get Master")
for line in f:lines() do
if string.match(line, "%s%[%d+%%%]%s") ~= nil then
volume=string.match(line, "%s%[%d+%%%]%s")
volume=string.gsub(volume, "[%[%]%%%s]","")
--helpers.dbg({volume})
end
if string.match(line, "%s%[[%l]+%]$") then
state=string.match(line, "%s%[[%l]+%]$")
state=string.gsub(state,"[%[%]%%%s]","")
end
end
f:close()
return state, volume
end
local function set_master(parameters)
local cmd = "amixer --quiet set Master " ..parameters
local f=io.popen(cmd)
f:close()
end
local function update_master(volume_graph)
local state
local value
data[volume_graph].mastertimer = timer({timeout = 0.5})
data[volume_graph].mastertimer:connect_signal("timeout", function()
data[volume_graph].state, value = get_master_infos(); set_value(volume_graph,value/100)
end)
data[volume_graph].mastertimer:start()
return volume_graph
end
local function get_mpd_volume()
local mpd_volume=0
local pass = "\"\""
local host = "127.0.0.1"
local port = "6600"
-- MPD client command
local mpd_c = "mpc" .. " -h " .. host .. " -p " .. port .. " status 2>&1"
-- Get data from MPD server
local f = io.popen(mpd_c)
for line in f:lines() do
--helpers.dbg({line})
if string.find(line,'error:%sConnection%srefused') then
mpd_vol="-1"
end
if string.find(line,"volume:.%d%d%%") then
mpd_volume = string.match(line,"[%s%d]%d%d")
--mpd_volume = line
end
end
f:close()
return mpd_volume
end
---Link the widget to mpd's volume level
--myvolume:update_mpd()
--@param volume_graph the volume graph
local function update_mpd(volume_graph)
local state
local value
data[volume_graph].mastertimer = capi.timer({timeout = 0.5})
data[volume_graph].mastertimer:add_signal("timeout", function()
value = get_mpd_volume(); set_value(volume_graph,value/100)
end)
data[volume_graph].mastertimer:start()
end
---Link the widget to the master channel of your system (uses amixer)
--@usage myvolume:set_master_control()
--a left clic toggle mute/unmute
--wheel up increase the volume
--wheel down decrease the volume
--@param volume_graph the volume graph
local function set_master_control(volume_graph)
volume_graph:buttons(awful.util.table.join(
awful.button({ }, 1, function()
set_master("toggle")
end),
awful.button({ }, 5, function()
set_master("2%-")
end),
awful.button({ }, 4, function()
set_master("2%+")
end)))
end
--- Set the volume_graph height.
-- @param volume_graph The graph.
-- @param height The height to set.
function volume:set_height( height)
if height >= 5 then
data[self].height = height
self:emit_signal("widget::updated")
end
return self
end
--- Set the graph width.
-- @param graph The graph.
-- @param width The width to set.
function volume:set_width( width)
if width >= 5 then
data[self].width = width
self:emit_signal("widget::updated")
end
return self
end
-- Build properties function
for _, prop in ipairs(properties) do
if not volume["set_" .. prop] then
volume["set_" .. prop] = function(volume_graph, value)
data[volume_graph][prop] = value
volume_graph:emit_signal("widget::updated")
return volume_graph
end
end
end
--- Create a volume_graph widget.
-- @param args Standard widget() arguments. You should add width and height
-- key to set graph geometry.
-- @return A graph widget.
function volume.new(args)
args.type = "imagebox"
local args = args or {}
args.width = args.width or 100
args.height = args.height or 20
if args.width < 5 or args.height < 5 then return end
local volume_graph = base.make_widget()
data[volume_graph] = {}
for _, v in ipairs(properties) do
data[volume_graph][v] = args[v]
end
data[volume_graph].value = 0
data[volume_graph].max_value = 1
-- Set methods
--volume_graph.set_value = set_value
volume_graph.update_master = update_master
volume_graph.update_mpd= update_mpd
volume_graph.set_master_control = set_master_control
volume_graph.draw = volume.draw
volume_graph.fit = volume.fit
for _, prop in ipairs(properties) do
volume_graph["set_" .. prop] = volume["set_" .. prop]
end
return volume_graph
end
function volume.mt:__call(...)
return volume.new(...)
end
return setmetatable(volume, volume.mt)