triangular_progress_graph.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. -- @author cedlemo
  2. local setmetatable = setmetatable
  3. local ipairs = ipairs
  4. local math = math
  5. local table = table
  6. local type = type
  7. local string = string
  8. local color = require("gears.color")
  9. local base = require("wibox.widget.base")
  10. local helpers = require("blingbling.helpers")
  11. local superproperties = require('blingbling.superproperties')
  12. ---Triangular progress graph widget.
  13. --@module blingbling.triangular_progress_graph
  14. ---Fill all the widget (width * height) with this color (default is transparent ).
  15. --@usage myvolume:set_background_color(string) -->"#rrggbbaa"
  16. --@name set_background_color
  17. --@class function
  18. --@param color a string "#rrggbbaa" or "#rrggbb"
  19. ---Define the form of the graph: use five growing bars instead of a triangle.
  20. --@usage myvolume:set_bar(boolean) --> true or false
  21. --@name set_bar
  22. --@class function
  23. --@param boolean true or false (default is false)
  24. ---Define the top and bottom margin for the graph.
  25. --@usage myvolume:set_v_margin(integer)
  26. --@name set_v_margin
  27. --@class function
  28. --@param margin an integer for top and bottom margin
  29. ---Define the left and right margin for the graph.
  30. --@usage myvolume:set_h_margin(integer)
  31. --@name set_h_margin
  32. --@class function
  33. --@param margin an integer for left and right margin
  34. ---Set the color of the graph background.
  35. --@usage myvolume:set_filled_color(string) -->"#rrggbbaa"
  36. --@name set_filled_color
  37. --@class function
  38. --@param color a string "#rrggbbaa" or "#rrggbb"
  39. ----Define the graph color.
  40. --@usage myvolume:set_graph_color(string) -->"#rrggbbaa"
  41. --@name set_graph_color
  42. --@class function
  43. --@param color a string "#rrggbbaa" or "#rrggbb"
  44. ---Display text on the graph or not.
  45. --@usage myvolume:set_show_text(boolean) --> true or false
  46. --@name set_show_text
  47. --@class function
  48. --@param boolean true or false (default is false)
  49. ---Define the color of the text.
  50. --@usage myvolume:set_text_color(string) -->"#rrggbbaa"
  51. --@name set_text_color
  52. --@class function
  53. --@param color a string "#rrggbbaa" or "#rrggbb" defaul is white
  54. ---Define the background color of the text.
  55. --@usage myvolume:set_text_background_color(string) -->"#rrggbbaa"
  56. --@name set_text_background_color
  57. --@class function
  58. --@param color a string "#rrggbbaa" or "#rrggbb"
  59. ---Define the text font size.
  60. --myvolume:set_font_size(integer)
  61. --@name set_font_size
  62. --@class function
  63. --@param graph the graph
  64. --@param size the font size
  65. ---Define the template of the text to display.
  66. --@usage myvolume:set_label(string)
  67. --By default the text is : (value_send_to_the_widget *100) .. "%"
  68. --static string: example set_label("Volume:") will display "Volume:" on the graph
  69. --dynamic string: use $percent in the string example set_label("Volume $percent %") will display "Volume 10%"
  70. --@name set_label
  71. --@class function
  72. --@param graph the graph
  73. --@param text the text to display
  74. local triangular_progressgraph = { mt = {} }
  75. local data = setmetatable({}, { __mode = "k" })
  76. local properties = {"width", "height", "v_margin", "h_margin", "background_color", "graph_background_color", "graph_color","graph_line_color","show_text", "text_color", "text_background_color" ,"label", "font_size","font", "bar"}
  77. function triangular_progressgraph.draw(tp_graph, wibox, cr, width, height)
  78. local v_margin = superproperties.v_margin
  79. if data[tp_graph].v_margin and data[tp_graph].v_margin <= data[tp_graph].height/4 then
  80. v_margin = data[tp_graph].v_margin
  81. end
  82. local h_margin = superproperties.h_margin
  83. if data[tp_graph].h_margin and data[tp_graph].h_margin <= data[tp_graph].width / 3 then
  84. h_margin = data[tp_graph].h_margin
  85. end
  86. local background_color = data[tp_graph].background_color or superproperties.background_color
  87. local rounded_size = data[tp_graph].rounded_size or superproperties.rounded_size
  88. local graph_background_color = data[tp_graph].graph_background_color or superproperties.graph_background_color
  89. local graph_color = data[tp_graph].graph_color or superproperties.graph_color
  90. local graph_line_color = data[tp_graph].graph_line_color or superproperties.graph_line_color
  91. local text_color = data[tp_graph].text_color or superproperties.text_color
  92. local text_background_color = data[tp_graph].text_background_color or superproperties.text_background_color
  93. local font_size =data[tp_graph].font_size or superproperties.font_size
  94. local font = data[tp_graph].font or superproperties.font
  95. --Generate Background (background color and Tiles)
  96. r,g,b,a = helpers.hexadecimal_to_rgba_percent(background_color)
  97. cr:set_source_rgba(r,g,b,a)
  98. cr:paint()
  99. --Drawn the tp_graph
  100. if data[tp_graph].value > 0 then
  101. if data[tp_graph].bar == true then
  102. --4 bar are use to represent data:
  103. --bar width:
  104. local nb_bar=5
  105. local bar_separator = 2
  106. local bar_width
  107. bar_width=math.floor((data[tp_graph].width -((2*h_margin) + ((nb_bar - 1) * bar_separator)))/nb_bar)
  108. local h_rest =data[tp_graph].width -( 2*h_margin +((nb_bar -1)*bar_separator) + nb_bar * bar_width)
  109. if h_rest ==2 or h_rest == 3 then
  110. h_rest = 1
  111. end
  112. if h_rest == 4 then
  113. h_rest = 2
  114. end
  115. --Drawn background graph
  116. x=h_margin+h_rest
  117. y=data[tp_graph].height - v_margin
  118. for i=1, nb_bar do
  119. cr:rectangle(x,y-((0.2*i)*(data[tp_graph].height - 2*v_margin)),bar_width,((0.2*i)*(data[tp_graph].height - 2*v_margin)))
  120. x=x+(bar_width + bar_separator)
  121. end
  122. r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_background_color)
  123. cr:set_source_rgba(r, g, b, a)
  124. cr:fill()
  125. --Drawn the graph
  126. --find nb column to drawn:
  127. local ranges={0,0.2,0.4,0.6,0.8,1,1.2}
  128. nb_bar=0
  129. for i, limite in ipairs(ranges) do
  130. if data[tp_graph].value < limite then
  131. --helpers.dbg({data[tp_graph].value, limite})
  132. nb_bar = i-1
  133. break
  134. end
  135. end
  136. x=h_margin+h_rest
  137. y=data[tp_graph].height - v_margin
  138. for i=1, nb_bar do
  139. if i ~= nb_bar then
  140. cr:rectangle(x,y-((0.2*i)*(data[tp_graph].height - 2*v_margin)),bar_width,(0.2*i)*(data[tp_graph].height - 2*v_margin))
  141. x=x+(bar_width + bar_separator)
  142. else
  143. val_to_display =data[tp_graph].value - ((nb_bar-1) * 0.2)
  144. cr:rectangle(x,y-((0.2*i)*(data[tp_graph].height - 2*v_margin)),bar_width * (val_to_display/0.2),(0.2*i)*(data[tp_graph].height - 2*v_margin))
  145. end
  146. end
  147. r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_color)
  148. cr:set_source_rgba(r, g, b, a)
  149. cr:fill()
  150. else
  151. x=h_margin
  152. y=data[tp_graph].height-(v_margin)
  153. cr:new_path()
  154. cr:move_to(x,y)
  155. cr:line_to(x,y)
  156. y_range=data[tp_graph].height - (2 * v_margin)
  157. cr:line_to(data[tp_graph].width + h_margin,data[tp_graph].height -( v_margin + y_range ))
  158. cr:line_to(data[tp_graph].width + h_margin, data[tp_graph].height - (v_margin ))
  159. cr:line_to(h_margin,data[tp_graph].height-(v_margin))
  160. cr:close_path()
  161. r,g,b,a = helpers.hexadecimal_to_rgba_percent(graph_background_color)
  162. cr:set_source_rgba(r, g, b,a)
  163. cr:fill()
  164. x=h_margin
  165. y=data[tp_graph].height-(v_margin)
  166. cr:new_path()
  167. cr:move_to(x,y)
  168. cr:line_to(x,y)
  169. y_range=data[tp_graph].height - (2 * v_margin)
  170. cr:line_to(data[tp_graph].width * data[tp_graph].value + h_margin,data[tp_graph].height -( v_margin + (y_range * data[tp_graph].value)))
  171. cr:line_to(data[tp_graph].width * data[tp_graph].value + h_margin, data[tp_graph].height - (v_margin ))
  172. cr:line_to(0+h_margin,data[tp_graph].height-(v_margin))
  173. cr:close_path()
  174. r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_color)
  175. cr:set_source_rgba(r, g, b, a)
  176. cr:fill()
  177. x=0+h_margin
  178. y=data[tp_graph].height-(v_margin)
  179. cr:new_path()
  180. cr:move_to(x,y)
  181. cr:line_to(x,y)
  182. y_range=data[tp_graph].height - (2 * v_margin)
  183. cr:line_to((data[tp_graph].width * data[tp_graph].value) + h_margin ,data[tp_graph].height -( v_margin + (y_range * data[tp_graph].value)))
  184. cr:line_to((data[tp_graph].width * data[tp_graph].value) - h_margin, data[tp_graph].height - (v_margin ))
  185. cr:set_antialias("subpixel")
  186. cr:set_line_width(1)
  187. r,g,b,a=helpers.hexadecimal_to_rgba_percent(graph_line_color)
  188. cr:set_source_rgb(r, g, b)
  189. cr:stroke()
  190. end
  191. end
  192. --Draw Text and it's background
  193. if data[tp_graph].show_text == true then
  194. cr:set_font_size(font_size)
  195. if type(font) == "string" then
  196. cr:select_font_face(font,nil,nil)
  197. elseif type(font) == "table" then
  198. cr:select_font_face(font.family or "Sans", font.slang or "normal", font.weight or "normal")
  199. end
  200. local value = data[tp_graph].value * 100
  201. if data[tp_graph].label then
  202. text=string.gsub(data[tp_graph].label,"$percent", value)
  203. else
  204. text=value .. "%"
  205. end
  206. helpers.draw_text_and_background(cr,
  207. text,
  208. h_margin,
  209. (data[tp_graph].height/2) ,
  210. text_background_color,
  211. text_color,
  212. false,
  213. true,
  214. false,
  215. false)
  216. end
  217. end
  218. function triangular_progressgraph.fit(tp_graph, width, height)
  219. return data[tp_graph].width, data[tp_graph].height
  220. end
  221. ---Set the tp_graph value.
  222. --@param tp_graph The progress bar.
  223. --@param value The progress bar value between 0 and 1.
  224. local function set_value(tp_graph, value)
  225. local value = value or 0
  226. local max_value = data[tp_graph].max_value
  227. data[tp_graph].value = math.min(max_value, math.max(0, value))
  228. tp_graph:emit_signal("widget::updated")
  229. return tp_graph
  230. end
  231. ---Set the tp_graph height.
  232. -- @param height The height to set.
  233. function triangular_progressgraph:set_height( height)
  234. if height >= 5 then
  235. data[self].height = height
  236. self:emit_signal("widget::updated")
  237. end
  238. return self
  239. end
  240. ---Set the tp_graph width.
  241. --@param width The width to set.
  242. function triangular_progressgraph:set_width( width)
  243. if width >= 5 then
  244. data[self].width = width
  245. self:emit_signal("widget::updated")
  246. end
  247. return self
  248. end
  249. -- Build properties function
  250. for _, prop in ipairs(properties) do
  251. if not triangular_progressgraph["set_" .. prop] then
  252. triangular_progressgraph["set_" .. prop] = function(tp_graph, value)
  253. data[tp_graph][prop] = value
  254. tp_graph:emit_signal("widget::updated")
  255. return tp_graph
  256. end
  257. end
  258. end
  259. --- Create a tp_graph widget.
  260. -- @param args Standard widget() arguments. You should add width and height
  261. -- key to set graph geometry.
  262. -- @return A graph widget.
  263. function triangular_progressgraph.new(args)
  264. local args = args or {}
  265. args.width = args.width or 100
  266. args.height = args.height or 20
  267. if args.width < 5 or args.height < 5 then return end
  268. local tp_graph = base.make_widget()
  269. data[tp_graph] = {}
  270. for _, v in ipairs(properties) do
  271. data[tp_graph][v] = args[v]
  272. end
  273. data[tp_graph].value = 0
  274. data[tp_graph].max_value = 1
  275. -- Set methods
  276. tp_graph.set_value = set_value
  277. tp_graph.add_value = set_value
  278. tp_graph.draw = triangular_progressgraph.draw
  279. tp_graph.fit = triangular_progressgraph.fit
  280. for _, prop in ipairs(properties) do
  281. tp_graph["set_" .. prop] = triangular_progressgraph["set_" .. prop]
  282. end
  283. return tp_graph
  284. end
  285. function triangular_progressgraph.mt:__call(...)
  286. return triangular_progressgraph.new(...)
  287. end
  288. return setmetatable(triangular_progressgraph, triangular_progressgraph.mt)