helpers.lua 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  1. -- @author cedlemo
  2. local naughty= require("naughty")
  3. local lgi = require("lgi")
  4. local cairo = lgi.cairo
  5. local pango = lgi.Pango
  6. local pangocairo = lgi.PangoCairo
  7. local string = require("string")
  8. local os = require('os')
  9. local awful = require('awful')
  10. local wibox = require('wibox')
  11. local math = math
  12. local table = table
  13. local print = print
  14. ---Functions used in blingbling.
  15. --@module blingbling.helpers
  16. local helpers={}
  17. ---Display values of variables in an awesome popup.
  18. --Each variables in vars is separated by a "|"
  19. --@param vars a table of variable
  20. function helpers.dbg(vars)
  21. local text = ""
  22. for i=1, #vars do text = text .. vars[i] .. " | " end
  23. naughty.notify({ text = text, timeout = 15 })
  24. end
  25. ---Convert an hexadecimal color to rgba color.
  26. --It convert a string variable "#rrggbb" or "#rrggbbaa" (with r,g,b and a which are hexadecimal value) to r, g, b a=1 or r,g,b,a (with r,g,b,a floated value from 0 to 1.
  27. --The function returns 4 variables.
  28. --@param my_color a string "#rrggbb" or "#rrggbbaa"
  29. function helpers.hexadecimal_to_rgba_percent(my_color)
  30. --check if color is a valid hex color else return white
  31. if string.find(my_color,"#[0-f][0-f][0-f][0-f][0-f]") then
  32. --delete #
  33. my_color=string.gsub(my_color,"^#","")
  34. r=string.format("%d", "0x"..string.sub(my_color,1,2))
  35. v=string.format("%d", "0x"..string.sub(my_color,3,4))
  36. b=string.format("%d", "0x"..string.sub(my_color,5,6))
  37. if string.sub(my_color,7,8) == "" then
  38. a=255
  39. else
  40. a=string.format("%d", "0x"..string.sub(my_color,7,8))
  41. end
  42. else
  43. r=255
  44. v=255
  45. b=255
  46. a=255
  47. end
  48. return r/255,v/255,b/255,a/255
  49. end
  50. ---Get red green blue value in parameters and return hexadecimal string
  51. function helpers.rgb(red, green, blue)
  52. if type(red) == "number" or type(green) == "number" or type(blue) == "number" then
  53. return "#"..string.format("%02x",red)..string.format("%02x",green)..string.format("%02x",blue)
  54. else
  55. return nil
  56. end
  57. end
  58. ---Get red green blue and alpha value in parameters and return hexadecimal string.
  59. function helpers.rgba(red, green, blue, alpha)
  60. if type(red) == "number" or type(green) == "number" or type(blue) == "number" or type(alpha) == "number" then
  61. return "#"..string.format("%02x",red)..string.format("%02x",green)..string.format("%02x",blue)..string.format("%02x",alpha * 255)
  62. else
  63. return nil
  64. end
  65. end
  66. ---Check if an hexadecimal color is fully transparent.
  67. --Returns true or false
  68. --@param my_color a string "#rrggbb" or "#rrggbbaa"
  69. function helpers.is_transparent(my_color)
  70. --check if color is a valid hex color else return white
  71. if string.find(my_color,"#[0-f][0-f][0-f][0-f][0-f]") then
  72. --delete #
  73. local my_color=string.gsub(my_color,"^#","")
  74. if string.sub(my_color,7,8) == "" then
  75. return false
  76. else
  77. local alpha=string.format("%d", "0x"..string.sub(my_color,7,8))
  78. if alpha/1 == 0 then
  79. return true
  80. else
  81. return false
  82. end
  83. end
  84. else
  85. return false
  86. end
  87. end
  88. ---Split string in different parts which are returned in a table. The delimiter of each part is a pattern given in argument.
  89. --@param str the string to split
  90. --@param pat the pattern delimiter
  91. function helpers.split(str, pat)
  92. local t = {} -- NOTE: use {n = 0} in Lua-5.0
  93. local fpat = "(.-)" .. pat
  94. local last_end = 1
  95. local s, e, cap = string.find(str,fpat, 1)
  96. while s do
  97. if s ~= 1 or cap ~= "" then
  98. table.insert(t,cap)
  99. end
  100. last_end = e+1
  101. s, e, cap = string.find(str,fpat, last_end)
  102. end
  103. if last_end <= #str then
  104. cap = string.sub(str,last_end)
  105. table.insert(t, cap)
  106. end
  107. return t
  108. end
  109. ---Draw tiles in a cairo context.
  110. --@param cr a cairo context.
  111. --@param height the height of the surface on which we want tiles
  112. --@param v_margin value used to define top margin and/or bottom margin (tiles are not drawn on the margins)
  113. --@param width the width of the surface on which we want tiles
  114. --@param h_margin value used to define left margin and/or right margin.
  115. function helpers.draw_background_tiles(cr, height, v_margin , width, h_margin)
  116. --tiles: width 4 px height 2px horizontal separator=1 px vertical separator=2px
  117. -- v_separator
  118. -- _______\ /_______
  119. -- |_______| |_______|
  120. -- _______ _______ <--h_separator
  121. -- |_______| |_______| <--tiles_height
  122. -- / \
  123. -- tiles_width
  124. tiles_width=4
  125. tiles_height=2
  126. h_separator=1
  127. v_separator=2
  128. --find nb max horizontal lignes we can display with 2 pix squarre and 1 px separator (3px)
  129. local max_line=math.floor((height - v_margin*2) /(tiles_height+h_separator))
  130. --what to do with the rest of the height:
  131. local h_rest=(height - v_margin*2) - (max_line * (tiles_height+h_separator))
  132. if h_rest >= (tiles_height) then
  133. max_line= max_line + 1
  134. h_rest= h_rest - tiles_height
  135. end
  136. if h_rest > 0 then
  137. h_rest =h_rest / 2
  138. end
  139. --find nb columns we can draw with tile of 4px width and 2 px separator (6px) and center them horizontaly
  140. local max_column=math.floor((width - h_margin*2)/6)
  141. local v_rest=(width- h_margin*2)-(max_column*( tiles_width + v_separator))
  142. if v_rest >= (tiles_width) then
  143. max_column= max_column + 1
  144. v_rest= v_rest - tiles_width
  145. end
  146. if v_rest > 0 then
  147. h_rest =h_rest / 2
  148. end
  149. x=width-(tiles_width + v_rest)
  150. y=height -(v_margin +tiles_height + h_rest)
  151. for i=1,max_column do
  152. for j=1,max_line do
  153. cr:rectangle(x,y,4,2)
  154. y= y-(tiles_height + h_separator)
  155. end
  156. y=height -(v_margin + tiles_height + h_rest)
  157. x=x-(tiles_width + v_separator)
  158. end
  159. end
  160. ---Draw text on a rectangle which width and height depend on the text width and height.
  161. --@param cr a cairo context already initialised with oocairo.context_create( )
  162. --@param text the text to display
  163. --@param x the x coordinate of the left of the text
  164. --@param y the y coordinate of the bottom of the text
  165. --@param text_background_color a string "#rrggbb" or "#rrggbbaa" for the rectangle color
  166. --@param text_color a string "#rrggbb" or "#rrggbbaa" for the text color
  167. --@param show_text_centered_on_x a boolean value not mandatory (false by default) if true, x parameter is the coordinate of the middle of the text
  168. --@param show_text_centered_on_y a boolean value not mandatory (false by default) if true, y parameter is the coordinate of the middle of the text
  169. --@param show_text_on_left_of_x a boolean value not mandatory (false by default) if true, x parameter is the right of the text
  170. --@param show_text_on_bottom_of_y a boolean value not mandatory (false by default) if true, y parameter is the top of the text
  171. function helpers.draw_text_and_background(cr, text, x, y, text_background_color, text_color, text_x_center, text_y_center, text_x_left, text_y_bottom)
  172. --Text background
  173. ext=cr:text_extents(text)
  174. x_modif = 0
  175. y_modif = 0
  176. if text_x_centered == true then
  177. x_modif = ((ext.width + ext.x_bearing) / 2) + ext.x_bearing / 2
  178. text_x_left = false
  179. else
  180. if text_x_left == true then
  181. x_modif = ext.width + 2 *ext.x_bearing
  182. else
  183. x_modif = x_modif
  184. end
  185. end
  186. if text_y_centered == true then
  187. y_modif = ((ext.height +ext.y_bearing)/2 ) + ext.y_bearing / 2
  188. text_y_left = false
  189. else
  190. if text_y_bottom == true then
  191. y_modif = ext.height + 2 *ext.y_bearing
  192. else
  193. y_modif = y_modif
  194. end
  195. end
  196. cr:rectangle(x + ext.x_bearing - x_modif,y + ext.y_bearing - y_modif,ext.width, ext.height)
  197. r,g,b,a=helpers.hexadecimal_to_rgba_percent(text_background_color)
  198. cr:set_source_rgba(r,g,b,a)
  199. cr:fill()
  200. --Text
  201. cr:new_path()
  202. cr:move_to(x-x_modif,y-y_modif)
  203. r,g,b,a=helpers.hexadecimal_to_rgba_percent(text_color)
  204. cr:set_source_rgba(r, g, b, a)
  205. cr:show_text(text)
  206. end
  207. ---Draw text on a rectangle which width and height depend on the text width and height.
  208. --@param cr a cairo context already initialised
  209. --@param text the text to display
  210. --@param x the x coordinate of the left of the text
  211. --@param y the y coordinate of the bottom of the text
  212. --@param bg_color a string "#rrggbb" or "#rrggbbaa" for the rectangle color
  213. --@param fg_color a string "#rrggbb" or "#rrggbbaa" for the text color
  214. --@param x_position a string "start", "middle" or "end" which define how the drawing will be positioned from x ("start" by default)
  215. --@param y_position a string "start", "middle" or "end" which define how the drawing will be positioned from y ("start" by default)
  216. function helpers.draw_layout_and_background(cr, text, x, y, font, bg_color, fg_color, x_position, y_position)
  217. local layout = pangocairo.create_layout(cr)
  218. local font_desc = pango.FontDescription.from_string(font)
  219. layout:set_font_description(font_desc)
  220. layout.text = text
  221. local _, logical = layout:get_pixel_extents()
  222. local height = logical.height
  223. local width = logical.width
  224. local text_x = x -- x position start
  225. local text_y = y -- y position start
  226. if x_position == "middle" then
  227. text_x = text_x - width / 2
  228. elseif x_position == "end" then
  229. text_x = text_x - width
  230. end
  231. if y_position == "middle" then
  232. text_y = text_y - height / 2
  233. elseif y_position == "end" then
  234. text_y = text_y - height
  235. end
  236. cr:rectangle(text_x, text_y, width, height)
  237. local r,g,b,a = helpers.hexadecimal_to_rgba_percent(bg_color)
  238. cr:set_source_rgba(r,g,b,a)
  239. cr:fill()
  240. cr:move_to(text_x, text_y)
  241. local r,g,b,a = helpers.hexadecimal_to_rgba_percent(fg_color)
  242. cr:set_source_rgba(r,g,b,a)
  243. cr:show_layout(layout)
  244. end
  245. ---Drawn one foreground arrow with a background arrow that depend on a value.
  246. --If the value is egal to 0 then the foreground arrow is not drawn.
  247. --@param cr a cairo context already initialised with oocairo.context_create( )
  248. --@param x the x coordinate in the cairo context where the arrow start
  249. --@param y_bottom the bottom corrdinate of the arrows
  250. --@param y_top the top coordinate of the arrows
  251. --@param value a number
  252. --@param background_arrow_color the color of the background arrow, a string "#rrggbb" or "#rrggbbaa"
  253. --@param arrow_color the color of the foreground arrow, a string "#rrggbb" or "#rrggbbaa"
  254. --@param arrow_line_color the color of the outline of the foreground arrow , a string "#rrggbb" or "#rrggbbaa"
  255. --@param up boolean value if false draw a down arrow, if true draw a up arrow
  256. function helpers.draw_up_down_arrows(cr,x,y_bottom,y_top,value,background_arrow_color, arrow_color, arrow_line_color,up)
  257. if up ~= false then
  258. invert = 1
  259. else
  260. invert= -1
  261. end
  262. --Draw the background arrow
  263. cr:move_to(x,y_bottom)
  264. cr:line_to(x,y_top )
  265. cr:line_to(x-(6 * invert), y_top + (6 * invert))
  266. cr:line_to(x-(3*invert), y_top + (6 * invert))
  267. cr:line_to(x-(3*invert), y_bottom)
  268. cr:line_to(x,y_bottom)
  269. cr:close_path()
  270. r,g,b,a = helpers.hexadecimal_to_rgba_percent(background_arrow_color)
  271. cr:set_source_rgba(r, g, b, a)
  272. cr:fill()
  273. --Draw the arrow if value is > 0
  274. if value > 0 then
  275. cr:move_to(x,y_bottom)
  276. cr:line_to(x,y_top )
  277. cr:line_to(x-(6*invert), y_top + (6 * invert))
  278. cr:line_to(x-(3*invert), y_top + (6 * invert))
  279. cr:line_to(x-(3*invert), y_bottom)
  280. cr:line_to(x,y_bottom)
  281. cr:close_path()
  282. r,g,b,a = helpers.hexadecimal_to_rgba_percent(arrow_color)
  283. cr:set_source_rgba(r, g, b, a)
  284. cr:fill()
  285. cr:move_to(x,y_bottom)
  286. cr:line_to(x,y_top )
  287. cr:line_to(x-(6*invert), y_top + (6 * invert))
  288. cr:line_to(x-(3*invert), y_top + (6 * invert))
  289. cr:line_to(x-(3*invert), y_bottom)
  290. cr:line_to(x,y_bottom)
  291. cr:close_path()
  292. r,g,b,a = helpers.hexadecimal_to_rgba_percent(arrow_line_color)
  293. cr:set_source_rgba(r, g, b, a)
  294. cr:set_line_width(1)
  295. cr:stroke()
  296. end
  297. end
  298. ---Draw a vertical bar with gradient color, so it looks like a cylinder, and it's height depends on a value.
  299. --@param cr a cairo context already initialised with oocairo.context_create( )
  300. --@param h_margin the left and right margin of the bar in the cr
  301. --@param v_margin the top and bottom margin of the bar in the cr
  302. --@param width the width used to display the left margin, the bar and the right margin
  303. --@param height the height used to display the top margin, the bar and the bottom margin
  304. --@param represent a table {background_bar_color = "#rrggbb" or "#rrggbbaa", color = "#rrggbb" or "#rrggbbaa", value =the value used to calculate the height of the bar}
  305. function helpers.draw_vertical_bar(cr,h_margin,v_margin, width,height, represent)
  306. x=h_margin
  307. bar_width=width - 2*h_margin
  308. bar_height=height - 2*v_margin
  309. y=v_margin
  310. if represent["background_bar_color"] == nil then
  311. r,g,b,a = helpers.hexadecimal_to_rgba_percent("#000000")
  312. else
  313. r,g,b,a = helpers.hexadecimal_to_rgba_percent(represent["background_bar_color"])
  314. end
  315. cr:rectangle(x,y,bar_width ,bar_height)
  316. gradient=cairo.pattern_create_linear(h_margin, height/2, width-h_margin, height/2)
  317. gradient:add_color_stop_rgba(0, r, g, b, 0.5)
  318. gradient:add_color_stop_rgba(0.5, 1, 1, 1, 0.5)
  319. gradient:add_color_stop_rgba(1, r, g, b, 0.5)
  320. cr:set_source(gradient)
  321. cr:fill()
  322. if represent["value"] ~= nil and represent["color"] ~= nil then
  323. x=h_margin
  324. bar_width=width - 2*h_margin
  325. bar_height=height - 2*v_margin
  326. if represent["invert"] == true then
  327. y=v_margin
  328. else
  329. y=height - (bar_height*represent["value"] + v_margin )
  330. end
  331. cr:rectangle(x,y,bar_width,bar_height*represent["value"])
  332. r,g,b,a = helpers.hexadecimal_to_rgba_percent(represent["color"])
  333. gradient=cairo.pattern_create_linear(0, height/2,width, height/2)
  334. gradient:add_color_stop_rgba(0, r, g, b, 0.1)
  335. gradient:add_color_stop_rgba(0.5, r, g, b, 1)
  336. gradient:add_color_stop_rgba(1, r, g, b, 0.1)
  337. cr:set_source(gradient)
  338. cr:fill()
  339. end
  340. end
  341. ---Draw an horizontal bar with gradient color, so it looks like a cylinder, and it's height depends on a value.
  342. --@param cr a cairo context already initialised with oocairo.context_create( )
  343. --@param h_margin the left and right margin of the bar in the cr
  344. --@param v_margin the top and bottom margin of the bar in the cr
  345. --@param width the width used to display the left margin, the bar and the right margin
  346. --@param height the height used to display the top margin, the bar and the bottom margin
  347. --@param represent a table {background_bar_color = "#rrggbb" or "#rrggbbaa", color = "#rrggbb" or "#rrggbbaa", value =the value used to calculate the width of the bar}
  348. function helpers.draw_horizontal_bar( cr,h_margin,v_margin, width, height, represent)
  349. x=h_margin
  350. bar_width=width - 2*h_margin
  351. bar_height=height - 2*v_margin
  352. y=v_margin
  353. if represent["background_bar_color"] == nil then
  354. r,g,b,a = helpers.hexadecimal_to_rgba_percent("#000000")
  355. else
  356. r,g,b,a = helpers.hexadecimal_to_rgba_percent(represent["background_bar_color"])
  357. end
  358. cr:rectangle(x,y,bar_width,bar_height)
  359. gradient=cairo.pattern_create_linear( width /2,v_margin , width/2, height - v_margin)
  360. gradient:add_color_stop_rgba(0, r, g, b, 0.5)
  361. gradient:add_color_stop_rgba(0.5, 1, 1, 1, 0.5)
  362. gradient:add_color_stop_rgba(1, r, g, b, 0.5)
  363. cr:set_source(gradient)
  364. cr:fill()
  365. if represent["value"] ~= nil and represent["color"] ~= nil then
  366. x=h_margin
  367. bar_width=width - 2*h_margin
  368. bar_height=height - 2*v_margin
  369. if represent["invert"] == true then
  370. x=width - (h_margin + bar_width*represent["value"] )
  371. else
  372. x=h_margin
  373. end
  374. cr:rectangle(x,y,bar_width*represent["value"],bar_height)
  375. r,g,b,a = helpers.hexadecimal_to_rgba_percent(represent["color"])
  376. gradient=cairo.pattern_create_linear(width /2,0 , width/2, height)
  377. gradient:add_color_stop_rgba(0, r, g, b, 0.1)
  378. gradient:add_color_stop_rgba(0.5, r, g, b, 1)
  379. gradient:add_color_stop_rgba(1, r, g, b, 0.1)
  380. cr:set_source(gradient)
  381. cr:fill()
  382. end
  383. end
  384. ---Draw a rectangle width rounded corners.
  385. --@param cr a cairo context already initialised with oocairo.context_create( )
  386. --@param x the x coordinate of the left top corner
  387. --@param y the y corrdinate of the left top corner
  388. --@param width the width of the rectangle
  389. --@param height the height of the rectangle
  390. --@param color a string "#rrggbb" or "#rrggbbaa" for the color of the rectangle
  391. --@param rounded_size a float value from 0 to 1 (0 is no rounded corner) or a table of float value
  392. function helpers.draw_rounded_corners_rectangle(cr,x,y,width, height, color, rounded_size)
  393. if helpers.is_transparent(color) then return nil end
  394. --if rounded_size =0 it is a classical rectangle (whooooo!)
  395. local height = height
  396. local width = width
  397. local x = x
  398. local y = y
  399. local rounded_sizes = {}
  400. if type(rounded_size) == "number" then
  401. for i = 1,4 do
  402. rounded_sizes[i]=rounded_size or 0
  403. end
  404. elseif type(rounded_size) == "table" then
  405. for i = 1,4 do
  406. rounded_sizes[i] = rounded_size[i] or 0
  407. end
  408. end
  409. radius = height > width and 0.5 * width or 0.5 * height
  410. PI = 2*math.asin(1)
  411. r,g,b,a = helpers.hexadecimal_to_rgba_percent(color)
  412. cr:set_source_rgba(r, g, b, a)
  413. --top left corner
  414. cr:arc(x + radius*rounded_sizes[1],
  415. y + radius*rounded_sizes[1],
  416. radius*rounded_sizes[1], PI, PI * 1.5)
  417. --top right corner
  418. cr:arc(width - radius*rounded_sizes[2],
  419. y + radius*rounded_sizes[2],
  420. radius*rounded_sizes[2], PI*1.5, PI * 2)
  421. --bottom right corner
  422. cr:arc(width - radius*rounded_sizes[3],
  423. height - radius*rounded_sizes[3],
  424. radius*rounded_sizes[3],PI*0, PI * 0.5)
  425. --bottom left corner
  426. cr:arc(x + radius*rounded_sizes[4],
  427. height - radius*rounded_sizes[4],
  428. radius*rounded_sizes[4],PI*0.5, PI * 1)
  429. cr:close_path()
  430. cr:fill()
  431. end
  432. ---Set a rectangle width rounded corners that define the area to draw.
  433. --@param cr a cairo context already initialised with oocairo.context_create( )
  434. --@param x the x coordinate of the left top corner
  435. --@param y the y corrdinate of the left top corner
  436. --@param width the width of the rectangle
  437. --@param height the height of the rectangle
  438. --@param rounded_size a float value from 0 to 1 (0 is no rounded corner)
  439. function helpers.clip_rounded_corners_rectangle(cr,x,y,width, height, rounded_size)
  440. --if rounded_size =0 it is a classical rectangle (whooooo!)
  441. local height = height
  442. local width = width
  443. local x = x
  444. local y = y
  445. local rounded_size = rounded_size or 0.4
  446. if height > width then
  447. radius=0.5 * width
  448. else
  449. radius=0.5 * height
  450. end
  451. PI = 2*math.asin(1)
  452. --top left corner
  453. cr:arc(x + radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI, PI * 1.5)
  454. --top right corner
  455. cr:arc(width - radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI*1.5, PI * 2)
  456. --bottom right corner
  457. cr:arc(width - radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0, PI * 0.5)
  458. --bottom left corner
  459. cr:arc(x + radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  460. cr:close_path()
  461. cr:clip()
  462. end
  463. ---Draw a foreground rounded corners rectangle which width depends on a value, and a background rounded corners rectangle.
  464. --@param cr a cairo context already initialised with oocairo.context_create( )
  465. --@param x the x coordinate of the left top corner
  466. --@param y the y corrdinate of the left top corner
  467. --@param width the width of the background rectangle and the maximal width of th foreground rectangle
  468. --@param height the height of the background and the foreground rectangles
  469. --@param background_color a string "#rrggbb" or "#rrggbbaa" for the color of the background rectangle
  470. --@param graph_color a string "#rrggbb" or "#rrggbbaa" for the color of the foreground rectangle
  471. --@param rounded_size a float value from 0 to 1 (0 is no rounded corner)
  472. --@param value_to_represent the percent of the max width used to calculate the width of the foreground rectangle
  473. --@param graph_line_color a string "#rrggbb" or "#rrggbbaa" for the outiline color of the background rectangle
  474. function helpers.draw_rounded_corners_horizontal_graph(cr,x,y,width, height, background_color, graph_color, rounded_size, value_to_represent, graph_line_color)
  475. --if rounded_size =0 it is a classical rectangle (whooooo!)
  476. local height = height
  477. local width = width
  478. local x = x
  479. local y = y
  480. local rounded_size = rounded_size or 0.4
  481. if height > width then
  482. radius=0.5 * width
  483. else
  484. radius=0.5 * height
  485. end
  486. PI = 2*math.asin(1)
  487. --draw the background
  488. r,g,b,a=helpers.hexadecimal_to_rgba_percent(background_color)
  489. cr:set_source_rgba(r,g,b,a)
  490. --top left corner
  491. cr:arc(x + radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI, PI * 1.5)
  492. --top right corner
  493. cr:arc(width - radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI*1.5, PI * 2)
  494. --bottom right corner
  495. cr:arc(width - radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0, PI * 0.5)
  496. --bottom left corner
  497. cr:arc(x + radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  498. cr:close_path()
  499. cr:fill()
  500. --represent the value
  501. -- value in 0 -> 1
  502. -- radius*rounded_size | width - 2*( radius*rounded) | radius * rounded_size
  503. -- | | |
  504. -- | _________| _______________________|
  505. -- | | |
  506. -- v ____v_________ v
  507. -- /| |\
  508. -- | | | | (... and yes I don't have a job)
  509. -- \|______________|/
  510. --
  511. --1 => width/ width
  512. --limit_2 => width -radius / width
  513. --limit_1 => radius /width
  514. value = value_to_represent
  515. limit_2 = (width -(radius * rounded_size)) / width
  516. limit_1 = radius* rounded_size /width
  517. r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_color)
  518. cr:set_source_rgba(r,g,b,a)
  519. if value <= 1 and value > limit_2 then
  520. cr:arc(x + radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI, PI * 1.5)
  521. ratio = (value - limit_2) / (1 - limit_2)
  522. cr:arc(width - radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI*1.5, PI *(1.5 +(0.5 * ratio)))
  523. cr:arc(width - radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*(0.5 - (0.5 * ratio)) , PI * 0.5)
  524. cr:arc(x + radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  525. cr:close_path()
  526. cr:fill()
  527. elseif value <= limit_2 and value > limit_1 then
  528. cr:arc(x + radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI, PI * 1.5)
  529. ratio = value / limit_2
  530. cr:line_to(limit_2*width*ratio,y)
  531. cr:line_to(limit_2*width*ratio,height)
  532. cr:arc(x + radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  533. cr:close_path()
  534. cr:fill()
  535. elseif value <= limit_1 and value > 0 then
  536. ratio = value / limit_1
  537. cr:arc(x + radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI, PI * (1+ (0.5*ratio)))
  538. cr:arc(x + radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*(1-(0.5 * ratio)) , PI * 1)
  539. cr:close_path()
  540. cr:fill()
  541. end
  542. if graph_line_color then
  543. r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_line_color)
  544. cr:set_source_rgba(r,g,b,a)
  545. cr:set_line_width(1)
  546. if value <= 1 and value > limit_2 then
  547. cr:arc(x +1+ radius*rounded_size,y+1 + radius*rounded_size, radius*rounded_size,PI, PI * 1.5)
  548. ratio = (value - limit_2) / (1 - limit_2)
  549. cr:arc(width-1 - radius*rounded_size,y+1 + radius*rounded_size, radius*rounded_size,PI*1.5, PI *(1.5 +(0.5 * ratio)))
  550. cr:arc(width-1 - radius*rounded_size,height-1 - radius*rounded_size, radius*rounded_size,PI*(0.5 - (0.5 * ratio)) , PI * 0.5)
  551. cr:arc(x+1 + radius*rounded_size,height-1 - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  552. cr:close_path()
  553. cr:stroke()
  554. elseif value <= limit_2 and value > limit_1 then
  555. cr:arc(x +1+ radius*rounded_size,y+1 + radius*rounded_size, radius*rounded_size,PI, PI * 1.5)
  556. ratio = value / limit_2
  557. cr:line_to(limit_2*width*ratio -1 ,y +1)
  558. cr:line_to(limit_2*width*ratio -1 ,height -1 )
  559. cr:arc(x +1 + radius*rounded_size,height -1 - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  560. cr:close_path()
  561. cr:stroke()
  562. elseif value <= limit_1 and value > 0 then
  563. ratio = value / limit_1
  564. cr:arc(x +1 + radius*rounded_size,y +1 + radius*rounded_size, radius*rounded_size,PI, PI * (1+ (0.5*ratio)))
  565. cr:arc(x +1 + radius*rounded_size,height +1 - radius*rounded_size, radius*rounded_size,PI*(1-(0.5 * ratio)) , PI * 1)
  566. cr:close_path()
  567. cr:stroke()
  568. end
  569. end
  570. end
  571. ---Draw a foreground rounded corners rectangle which height depends on a value, and a background rounded corners rectangle.
  572. --@param cr a cairo context already initialised with oocairo.context_create( )
  573. --@param x the x coordinate of the left top corner
  574. --@param y the y corrdinate of the left top corner
  575. --@param width the width of the background and the foreground rectangles
  576. --@param height the height of the background rectangle and the maximal height of the foreground rectangle
  577. --@param background_color a string "#rrggbb" or "#rrggbbaa" for the color of the background rectangle
  578. --@param graph_color a string "#rrggbb" or "#rrggbbaa" for the color of the foreground rectangle
  579. --@param rounded_size a float value from 0 to 1 (0 is no rounded corner)
  580. --@param value_to_represent the percent of the max height used to calculate the height of the foreground rectangle
  581. --@param graph_line_color a string "#rrggbb" or "#rrggbbaa" for the outiline color of the background rectangle
  582. function helpers.draw_rounded_corners_vertical_graph(cr,x,y,width, height, background_color, graph_color, rounded_size, value_to_represent, graph_line_color)
  583. --if rounded_size =0 it is a classical rectangle (whooooo!)
  584. local height = height
  585. local width = width
  586. local x = x
  587. local y = y
  588. if rounded_size == nil or rounded_size == 0 then
  589. --draw the background:
  590. r,g,b,a=helpers.hexadecimal_to_rgba_percent(background_color)
  591. cr:set_source_rgba(r,g,b,a)
  592. cr:move_to(x,y)
  593. cr:line_to(x,height)
  594. cr:line_to(width,height)
  595. cr:line_to(width,y)
  596. cr:close_path()
  597. cr:fill()
  598. --draw the graph:
  599. r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_color)
  600. cr:set_source_rgba(r,g,b,a)
  601. cr:move_to(x,height)
  602. cr:line_to(x, height -((height -y)* value_to_represent) )
  603. cr:line_to(width,height -((height - y)*value_to_represent) )
  604. cr:line_to(width,height)
  605. cr:close_path()
  606. cr:fill()
  607. if graph_line_color then
  608. r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_line_color)
  609. cr:set_source_rgba(r,g,b,a)
  610. cr:move_to(x,height)
  611. cr:line_to(x,height -((height -y)* value_to_represent) )
  612. cr:line_to(width,height -((height -y)*value_to_represent) )
  613. cr:line_to(width,height)
  614. cr:close_path()
  615. cr:set_line_width(1)
  616. cr:stroke()
  617. end
  618. else
  619. local rounded_size = rounded_size or 0.4
  620. if height > width then
  621. radius=0.5 * width
  622. else
  623. radius=0.5 * height
  624. end
  625. PI = 2*math.asin(1)
  626. --draw the background
  627. r,g,b,a=helpers.hexadecimal_to_rgba_percent(background_color)
  628. cr:set_source_rgba(r,g,b,a)
  629. --top left corner
  630. cr:arc(x + radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI, PI * 1.5)
  631. --top right corner
  632. cr:arc(width - radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI*1.5, PI * 2)
  633. --bottom right corner
  634. cr:arc(width - radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0, PI * 0.5)
  635. --bottom left corner
  636. cr:arc(x + radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  637. cr:close_path()
  638. cr:fill()
  639. --represent the value
  640. -- value in 0 -> 1
  641. -- radius*rounded_size | height - 2*( radius*rounded) | radius * rounded_size
  642. -- | | |
  643. -- | ____| _______________________|
  644. -- |_______ | |
  645. -- ___ | | |
  646. -- /___\ <- | |
  647. -- | | | |
  648. -- | |<---- |
  649. -- |_____| |
  650. -- \___/<------------
  651. --
  652. --1 => height/ height
  653. --limit_2 => height -radius / height
  654. --limit_1 => radius /height
  655. value = value_to_represent
  656. limit_2 = (height -(radius * rounded_size)) / height
  657. limit_1 = radius* rounded_size /height
  658. --dbg({value, limit_2, limit_1})
  659. r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_color)
  660. cr:set_source_rgba(r,g,b,a)
  661. if value <= 1 and value > limit_2 then
  662. ratio = (value - limit_2) / (1 - limit_2)
  663. cr:arc(width - radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0 , PI * 0.5)
  664. cr:arc(x + radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  665. cr:arc(x + radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI, PI * (1+(0.5* ratio)) )
  666. cr:arc(width - radius*rounded_size,y + radius*rounded_size, radius*rounded_size,PI*(2 -(0.5* ratio)), PI *2)
  667. cr:close_path()
  668. cr:fill()
  669. elseif value <= limit_2 and value > limit_1 then
  670. ratio = value / limit_2
  671. cr:arc(width - radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0 , PI * 0.5)
  672. cr:arc(x + radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  673. cr:line_to(x,y + height - (height * ratio*limit_2) )
  674. cr:line_to(width,y+ height - (height * ratio*limit_2) )
  675. cr:close_path()
  676. cr:fill()
  677. elseif value <= limit_1 and value > 0 then
  678. ratio = value / limit_1
  679. cr:arc(width - radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*(0.5-( 0.5*ratio)) , PI * 0.5)
  680. cr:arc(x + radius*rounded_size,height - radius*rounded_size, radius*rounded_size,PI*0.5, PI *(0.5+ (0.5*ratio)))
  681. cr:close_path()
  682. cr:fill()
  683. end
  684. if graph_line_color then
  685. r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_line_color)
  686. cr:set_source_rgba(r,g,b,a)
  687. cr:set_line_width(1)
  688. if value <= 1 and value > limit_2 then
  689. ratio = (value - limit_2) / (1 - limit_2)
  690. cr:arc(width -1 - radius*rounded_size,height -1 - radius*rounded_size, radius*rounded_size,PI*0 , PI * 0.5)
  691. cr:arc(x+1 + radius*rounded_size,height -1 - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  692. cr:arc(x+1 + radius*rounded_size,y+1 + radius*rounded_size, radius*rounded_size,PI, PI * (1+(0.5* ratio)) )
  693. cr:arc(width -1 - radius*rounded_size,y+1 + radius*rounded_size, radius*rounded_size,PI*(2 -(0.5* ratio)), PI *2)
  694. cr:close_path()
  695. cr:stroke()
  696. elseif value <= limit_2 and value > limit_1 then
  697. ratio = value / limit_2
  698. cr:arc(width -1 - radius*rounded_size,height -1 - radius*rounded_size, radius*rounded_size,PI*0 , PI * 0.5)
  699. cr:arc(x+1 + radius*rounded_size,height -1 - radius*rounded_size, radius*rounded_size,PI*0.5, PI * 1)
  700. cr:line_to(x +1 ,y +1 + height - (height * ratio*limit_2) )
  701. cr:line_to(width - 1,y +1 + height - (height * ratio*limit_2) )
  702. cr:close_path()
  703. cr:stroke()
  704. elseif value <= limit_1 and value > 0 then
  705. ratio = value / limit_1
  706. cr:arc(width -1 - radius*rounded_size,height -1 - radius*rounded_size, radius*rounded_size,PI*(0.5-( 0.5*ratio)) , PI * 0.5)
  707. cr:arc(x +1 + radius*rounded_size,height -1 - radius*rounded_size, radius*rounded_size,PI*0.5, PI *(0.5+ (0.5*ratio)))
  708. cr:close_path()
  709. cr:stroke()
  710. end
  711. end
  712. end
  713. end
  714. ---Generate a text in front of a centered rectangle with rounded corners (or not) in a cairo context.
  715. --It returns a table ={ width = the width of the image, height = the height of the image}
  716. --@param cr a cairo context already initialised with oocairo.context_create( )
  717. --@param width the width of the widget
  718. --@param height the height of the widget
  719. --@param text the text to display
  720. --@param padding the left/right/top/bottom padding used to center the text in the background rectangle
  721. --@param background_color a string "#rrggbb" or "#rrggbbaa" for the color of the background rectangle
  722. --@param text_color a string "#rrggbb" or "#rrggbbaa" for the color of the text
  723. --@param font_size define the size of the font
  724. --@param rounded_size a float value from 0 to 1 (0 is no rounded corner)
  725. --@param border a color as a string "#rrggbb" or "#rrggbbaa"
  726. function helpers.generate_rounded_rectangle_with_text(cr, width, height, text, padding, background_color, text_color, font_size, rounded_size, border)
  727. local data={}
  728. local padding = padding or 2
  729. --find the height and width of the image:
  730. cr:set_font_size(font_size)
  731. local ext = cr:text_extents(text)
  732. data.height = (font_size + 2* padding) > height and (font_size + 2* padding) or height
  733. data.width = (ext.width +ext.x_bearing*2 + 2*padding) > width and (ext.width +ext.x_bearing *2 + 2*padding) or width
  734. --draw the background
  735. draw_rounded_corners_rectangle(cr,0,0,data.width, data.height, background_color, rounded_size, border)
  736. --draw the text
  737. cr:move_to((data.width/2) -((ext.width+ext.x_bearing*2)/2), (data.height)/2 + (font_size/2))
  738. r,g,b,a=helpers.hexadecimal_to_rgba_percent(text_color)
  739. cr:set_font_size(font_size)
  740. cr:set_source_rgba(r,g,b,a)
  741. cr:show_text(text)
  742. return data
  743. end
  744. ---Draw a rectangular triangle filled with given color
  745. --@param cr cairo context
  746. --@param first point coordinates {x= 1.0, y = 2.0}
  747. --@param second point coordinates {x= 1.0, y = 2.0}
  748. --@param third point coordinates {x= 1.0, y = 2.0}
  749. --@param color a color as a string "#rrggbb" or "#rrggbbaa"
  750. function helpers.draw_triangle(cr, first, second, third, color)
  751. local r,g,b,a = helpers.hexadecimal_to_rgba_percent(color)
  752. cr:new_path()
  753. cr:set_source_rgba(r,g,b,a)
  754. cr:move_to(first.x, first.y)
  755. cr:line_to(second.x, second.y)
  756. cr:line_to(third.x, third.y)
  757. cr:close_path()
  758. cr:fill()
  759. end
  760. --- Draw a rectangular triangular outline of the given color
  761. --@param cr cairo context
  762. --@param first point coordinates {x= 1.0, y = 2.0}
  763. --@param second point coordinates {x= 1.0, y = 2.0}
  764. --@param third point coordinates {x= 1.0, y = 2.0}
  765. --@param color a color as a string "#rrggbb" or "#rrggbbaa"
  766. function helpers.draw_triangle_outline(cr, first, second, third, color)
  767. local r,g,b,a = helpers.hexadecimal_to_rgba_percent(color)
  768. cr:new_path()
  769. cr:set_source_rgba(r,g,b,a)
  770. cr:move_to(first.x, first.y)
  771. cr:line_to(second.x, second.y)
  772. cr:line_to(third.x, third.y)
  773. cr:close_path()
  774. cr:set_antialias("subpixel")
  775. cr:set_line_width(1)
  776. cr:stroke()
  777. end
  778. --- Compute the width of each bar in a graph
  779. --It returns the width of the bar and a value
  780. --that corresponds to the remaing space divided
  781. --by 2
  782. --@param nb_bars the number of bars
  783. --@param width the width of the graph
  784. --@param sep the size between two bars
  785. function compute_bar_width(nb_bars, width, sep)
  786. local bar_width = 0
  787. local h_rest = 0
  788. local total_sep = (nb_bars - 1) * sep
  789. bar_width=math.floor ((width - total_sep) / nb_bars)
  790. h_rest = width - (total_sep + nb_bars * bar_width)
  791. --center the graph according to h_rest (2, 3 or 4)
  792. if h_rest ==2 or h_rest == 3 then
  793. h_rest = 1
  794. end
  795. if h_rest == 4 then
  796. h_rest = 2
  797. end
  798. return bar_width, h_rest
  799. end
  800. function helpers.draw_triangle_using_bars(cr, width, height, h_margin, v_margin, color)
  801. local nb_bars=5
  802. local bar_separator = 2
  803. local bar_width, h_rest = compute_bar_width(nb_bars, width - 2*h_margin, bar_separator)
  804. x=h_margin+h_rest
  805. y=height - v_margin
  806. for i=1, nb_bars do
  807. cr:rectangle(x,y-((0.2*i)*(height - 2*v_margin)),bar_width,((0.2*i)*(height - 2*v_margin)))
  808. x=x+(bar_width + bar_separator)
  809. end
  810. local r,g,b,a=helpers.hexadecimal_to_rgba_percent(color)
  811. cr:set_source_rgba(r, g, b, a)
  812. cr:fill()
  813. end
  814. --- Display a value using bars or parts of bar in a triangular form
  815. --@param cr cairo context
  816. --@param width width of the graph
  817. --@param height height of the graph
  818. --@param h_margin horizontal space left at left and right of the graph
  819. --@param v_margin vertical space left at top and bottom of the graph
  820. --@param color the color of the graph
  821. --@param value to represent
  822. function helpers.draw_triangle_graph_using_bars(cr, width, height, h_margin, v_margin, color, value)
  823. local nb_bars=5
  824. local bar_separator = 2
  825. local bar_width, h_rest = compute_bar_width(nb_bars, width - 2*h_margin, bar_separator)
  826. if value > 0 then
  827. local ranges={0,0.2,0.4,0.6,0.8,1,1.2}
  828. nb_bars=0
  829. for i, limite in ipairs(ranges) do
  830. if value < limite then
  831. nb_bar = i-1
  832. break
  833. end
  834. end
  835. x=h_margin + h_rest
  836. y=height - v_margin
  837. for i=1, nb_bar do
  838. if i ~= nb_bar then
  839. cr:rectangle(x,y-((0.2*i)*(height - 2*v_margin)),bar_width,(0.2*i)*(height - 2*v_margin))
  840. x=x+(bar_width + bar_separator)
  841. else
  842. val_to_display =value - ((nb_bar-1) * 0.2)
  843. cr:rectangle(x,y-((0.2*i)*(height - 2*v_margin)),bar_width * (val_to_display/0.2),(0.2*i)*(height - 2*v_margin))
  844. end
  845. end
  846. r,g,b,a=helpers.hexadecimal_to_rgba_percent(color)
  847. cr:set_source_rgba(r, g, b, a)
  848. cr:fill()
  849. end
  850. end
  851. ---Remove an element from a table using key.
  852. --@param hash the table
  853. --@param key the key to remove
  854. function helpers.hash_remove(hash,key)
  855. local element = hash[key]
  856. hash[key] = nil
  857. return element
  858. end
  859. ---Functions for date and calendar
  860. local function is_leap_year(year)
  861. return year % 4 == 0 and (year % 100 ~= 0 or year % 400 == 0)
  862. end
  863. local days_in_m = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  864. ---Get the number of days in a given month of a year.
  865. --iT returns a number
  866. --@param month the month we focus on ( 1 to 12 )
  867. --@param year a number YYYY used to check if it's a leap year.
  868. function helpers.get_days_in_month(month, year)
  869. if month == 2 and is_leap_year(year) then
  870. return 29
  871. else
  872. return days_in_m[month]
  873. end
  874. end
  875. ---Find the weeks numbers of a given month.
  876. --Implementation as per the ISO 8601 definition (http://en.wikipedia.org/wiki/ISO_week_date)
  877. --Fully compatible with original, returns table with 6 week numbers
  878. --@param month the month
  879. --@param year the year
  880. function helpers.get_ISO8601_weeks_number_of_month(month, year)
  881. local wday = os.date("*t", os.time{year=year,month=month,day=1}).wday-1
  882. wday = wday == 0 and 7 or wday
  883. local yday = os.date("*t", os.time{year=year,month=month,day=1}).yday
  884. local nweeks = is_leap_year(month == 12 and year+1 or year) and 53 or 52 -- Make a correction for leap weeks!
  885. local week = math.floor((yday-wday+10)/7) -- First week of the month
  886. if (week < 1) then week = nweeks+week end
  887. if (week > nweeks) then week = week-nweeks end
  888. local t = {week}
  889. for i = 1, 5 do -- Calculate the next 5 weeks, correct where necessary
  890. t[i+1] = ((week+i) > nweeks and (week+i)-nweeks or week+i)
  891. end
  892. return t
  893. end
  894. ---Get the number of cpu cores
  895. --@return a number
  896. function helpers.get_nb_cores()
  897. local f=io.open("/proc/stat")
  898. local nb=0
  899. for line in f:lines() do
  900. if string.find(line,"cpu%d+%s") then nb = nb + 1 end
  901. end
  902. return nb
  903. end
  904. ---Get the cpu name
  905. --@return a string describing the cpu
  906. function helpers.get_cpu_name()
  907. local file = io.open("/proc/cpuinfo")
  908. for line in file:lines() do
  909. local cpu = string.match(line,"model%sname%s:%s*(.*)")
  910. if cpu then return cpu end
  911. end
  912. end
  913. ---Get all the currently mounted devices
  914. --@return an indexed table from 1 to n, where each element is a table with the "mnt", and "dev" key.
  915. function helpers.get_mounted_devices()
  916. local buf = awful.util.pread("mount")
  917. buf = helpers.split(buf, "\n")
  918. local devices = {}
  919. local n = 0 --devices will be an array of table {dev, mnt} (allowing to keep an alphabetical order on /dev/sxxx
  920. for i=1,#buf do
  921. local dev, mnt = string.match(buf[i],"(/dev/[^%s]*)%s+on%s+([^%s]+).*")
  922. if dev and mnt then
  923. n=n+1
  924. devices[n]={mnt=mnt, dev=dev}
  925. end
  926. end
  927. table.sort(devices, function(a,b) return a.dev < b.dev end)
  928. return devices
  929. end
  930. ---Get the total amount of RAM in kb
  931. --@return a number
  932. function helpers.get_total_mem_in_kb()
  933. local file = io.open("/proc/meminfo")
  934. for line in file:lines() do
  935. local mem = string.match(line,"MemTotal:%s*(%d*)")
  936. if mem then return mem end
  937. end
  938. end
  939. ---Get the input device names
  940. --@return an table with "keyboard" and "mouse" keys
  941. function helpers.get_input_devices()
  942. local file = io.open("/proc/bus/input/devices")
  943. local devices={}
  944. local i= 0
  945. for line in file:lines() do
  946. local name, ev, handlers = nil
  947. if string.match(line,"I:%s") then
  948. devices[#devices+1]={}
  949. end
  950. name=string.match(line,"N:%sName=\"(.*)\"")
  951. if (name) then
  952. devices[#devices].name=name
  953. end
  954. ev=string.match(line,"B:%sEV=(.*)")
  955. if (ev) then
  956. devices[#devices].ev=ev
  957. end
  958. handlers=string.match(line,"H:%sHandlers=(.*)")
  959. if (handlers) then
  960. devices[#devices].handlers=handlers
  961. end
  962. end
  963. local inputs={}
  964. for _,device in ipairs(devices) do
  965. if string.match(device.ev, "120013") then
  966. inputs.keyboard= device.name
  967. end
  968. if device.handlers and string.match(device.handlers, "mouse") then
  969. inputs.mouse=device.name
  970. end
  971. end
  972. file:close()
  973. return inputs
  974. end
  975. ---Get the current graphic card
  976. --@return a string
  977. function helpers.get_graphic_card()
  978. local buf = awful.util.pread("lspci | grep VGA")
  979. local graph_card = string.match(buf,"[^%s]*%s+VGA%s+compatible%s+controller:%s+(.*)")
  980. return graph_card
  981. end
  982. --- Get OS related informations from /etc/os-release
  983. --@return a key/value table
  984. function helpers.get_os_release_informations()
  985. local file = io.open("/etc/os-release")
  986. local infos = {}
  987. for line in file:lines() do
  988. local key,value = string.match(line,"([^%s]+)=%s*\"?([^\"]*)\"?")
  989. if key and value then
  990. infos[#infos +1]={key=key,value = value}
  991. end
  992. end
  993. return infos
  994. end
  995. --- Function used in order to have a tasklist with icons only
  996. --The classical usage of it is:
  997. --awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, mytasklist.buttons,nil,icons_only_tasklist)
  998. function helpers.icons_only_tasklist(w, buttons, label, data, objects)
  999. w:reset()
  1000. local l = wibox.layout.fixed.horizontal()
  1001. for i, o in ipairs(objects) do
  1002. local cache = data[o]
  1003. if cache then
  1004. ib = cache.ib
  1005. else
  1006. local common = require("awful.widget.common")
  1007. ib = wibox.widget.imagebox()
  1008. ib:buttons(common.create_buttons(buttons, o))
  1009. data[o] = {
  1010. ib = ib
  1011. }
  1012. end
  1013. local text, bg, bg_image, icon = label(o)
  1014. ib:set_image(icon)
  1015. l:add(ib)
  1016. end
  1017. w:add(l)
  1018. end
  1019. ---Function used in widgets in order to create a local table of
  1020. --all the widget properties which are a mix between the properties
  1021. --provided by the user trought the widget interface, or the properties
  1022. --defined by superproperties
  1023. --@param properties a table with the names of all the properties
  1024. --@param data the data table of the module that references all the same widgets
  1025. --@param graph the widget itself
  1026. --@param superproperties the table of the superporperties
  1027. function helpers.load_properties( properties, data, graph, superproperties)
  1028. local props = {}
  1029. for _i, prop in ipairs(properties) do
  1030. props[prop] = data[graph][prop] or superproperties[prop]
  1031. if prop == "v_margin" then
  1032. if data[graph].v_margin and data[graph].v_margin <= data[graph].height/4 then
  1033. props.v_margin = data[graph].v_margin
  1034. end
  1035. end
  1036. if prop == "h_margin" then
  1037. if data[graph].h_margin and data[graph].h_margin <= data[graph].height/3 then
  1038. props.h_margin = data[graph].h_margin
  1039. end
  1040. end
  1041. end
  1042. return props
  1043. end
  1044. return helpers