awful.widget.graph: Various minor fixes
[awesome.git] / lib / awful / widget / graph.lua.in
blob90cc6b15339276b5c67479a5d15d3339c3375a00
1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2009 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 local setmetatable = setmetatable
8 local ipairs = ipairs
9 local math = math
10 local table = table
11 local type = type
12 local color = require("gears.color")
13 local base = require("wibox.widget.base")
15 --- A graph widget.
16 module("awful.widget.graph")
18 local data = setmetatable({}, { __mode = "k" })
20 --- Set the graph border color.
21 -- If the value is nil, no border will be drawn.
22 -- @name set_border_color
23 -- @class function
24 -- @param graph The graph.
25 -- @param color The border color to set.
27 --- Set the graph foreground color.
28 -- @name set_color
29 -- @class function
30 -- @param graph The graph.
31 -- @param color The graph color.
33 --- Set the graph background color.
34 -- @name set_background_color
35 -- @class function
36 -- @param graph The graph.
37 -- @param color The graph background color.
39 --- Set the maximum value the graph should handle.
40 -- If "scale" is also set, the graph never scales up below this value, but it
41 -- automatically scales down to make all data fit.
42 -- @name set_max_value
43 -- @class function
44 -- @param graph The graph.
45 -- @param value The value.
47 --- Set the graph to automatically scale its values. Default is false.
48 -- @name set_scale
49 -- @class function
50 -- @param graph The graph.
51 -- @param scale A boolean value
53 --- Set the graph to draw stacks. Default is false.
54 -- @name set_stack
55 -- @class function
56 -- @param graph The graph.
57 -- @param stack A boolean value.
59 --- Set the graph stacking colors. Order matters.
60 -- @name set_stack_colors
61 -- @class function
62 -- @param graph The graph.
63 -- @param stack_colors A table with stacking colors.
65 local properties = { "width", "height", "border_color", "stack",
66 "stack_colors", "color", "background_color",
67 "max_value", "scale" }
69 function draw(graph, wibox, cr, width, height)
70 local max_value = data[graph].max_value
71 local values = data[graph].values
73 local border_width = 0
74 if data[graph].border_color then
75 border_width = 1
76 end
78 cr:set_line_width(1)
80 -- Draw the background first
81 cr:rectangle(border_width, border_width,
82 width - (2 * border_width),
83 height - (2 * border_width))
84 cr:set_source(color(data[graph].background_color or "#000000aa"))
85 cr:fill()
87 -- Draw a stacked graph
88 if data[graph].stack then
90 if data[graph].scale then
91 for _, v in ipairs(values) do
92 for __, sv in ipairs(v) do
93 if sv > max_value then
94 max_value = sv
95 end
96 end
97 end
98 end
100 for i = 0, width - (2 * border_width) do
101 local rel_i = 0
102 local rel_x = border_width + i + 0.5
104 if data[graph].stack_colors then
105 for idx, col in ipairs(data[graph].stack_colors) do
106 local stack_values = values[idx]
107 if stack_values and i < #stack_values then
108 local value = stack_values[#stack_values - i] + rel_i
109 cr:move_to(rel_x, border_width +
110 (height - 2 * border_width) * (1 - (rel_i / max_value)))
111 cr:line_to(rel_x, border_width +
112 (height - 2 * border_width) * (1 - (value / max_value)))
113 cr:set_source(color(col or "#ff0000"))
114 cr:stroke()
115 rel_i = value
120 else
121 if data[graph].scale then
122 for _, v in ipairs(values) do
123 if v > max_value then
124 max_value = v
129 -- Draw the background on no value
130 if #values ~= 0 then
131 -- Draw reverse
132 for i = 0, #values - 1 do
133 local value = values[#values - i]
134 if value >= 0 then
135 value = value / max_value
136 cr:move_to(border_width + i + 0.5, border_width +
137 (height - 2 * border_width) * (1 - value))
138 cr:line_to(border_width + i + 0.5, border_width +
139 (height - 2 * border_width))
142 cr:set_source(color(data[graph].color or "#ff0000"))
143 cr:stroke()
148 -- Draw the border last so that it overlaps already drawn values
149 if data[graph].border_color then
150 -- Draw the border
151 cr:rectangle(0.5, 0.5, width - 1, height - 1)
152 cr:set_source(color(data[graph].border_color or "#ffffff"))
153 cr:stroke()
157 function fit(graph, width, height)
158 return data[graph].width, data[graph].height
161 --- Add a value to the graph
162 -- @param graph The graph.
163 -- @param value The value between 0 and 1.
164 -- @param group The stack color group index.
165 local function add_value(graph, value, group)
166 if not graph then return end
168 local value = value or 0
169 local values = data[graph].values
170 local max_value = data[graph].max_value
171 value = math.max(0, value)
172 if not data[graph].scale then
173 value = math.min(max_value, value)
176 if data[graph].stack and group then
177 if not data[graph].values[group]
178 or type(data[graph].values[group]) ~= "table"
179 then
180 data[graph].values[group] = {}
182 values = data[graph].values[group]
184 table.insert(values, value)
186 local border_width = 0
187 if data[graph].border_color then border_width = 2 end
189 -- Ensure we never have more data than we can draw
190 while #values > data[graph].width - border_width do
191 table.remove(values, 1)
194 graph:emit_signal("widget::updated")
195 return graph
199 --- Set the graph height.
200 -- @param graph The graph.
201 -- @param height The height to set.
202 function set_height(graph, height)
203 if height >= 5 then
204 data[graph].height = height
205 graph:emit_signal("widget::updated")
207 return graph
210 --- Set the graph width.
211 -- @param graph The graph.
212 -- @param width The width to set.
213 function set_width(graph, width)
214 if width >= 5 then
215 data[graph].width = width
216 graph:emit_signal("widget::updated")
218 return graph
221 -- Build properties function
222 for _, prop in ipairs(properties) do
223 if not _M["set_" .. prop] then
224 _M["set_" .. prop] = function(graph, value)
225 data[graph][prop] = value
226 graph:emit_signal("widget::updated")
227 return graph
232 --- Create a graph widget.
233 -- @param args Standard widget() arguments. You should add width and height
234 -- key to set graph geometry.
235 -- @return A graph widget.
236 function new(args)
237 local args = args or {}
239 local width = args.width or 100
240 local height = args.height or 20
242 if width < 5 or height < 5 then return end
244 local graph = base.make_widget()
246 data[graph] = { width = width, height = height, values = {}, max_value = 1 }
248 -- Set methods
249 graph.add_value = add_value
250 graph.draw = draw
251 graph.fit = fit
253 for _, prop in ipairs(properties) do
254 graph["set_" .. prop] = _M["set_" .. prop]
257 return graph
260 setmetatable(_M, { __call = function(_, ...) return new(...) end })
262 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80