1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2009 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 local setmetatable
= setmetatable
12 local color
= require("gears.color")
13 local base
= require("wibox.widget.base")
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
24 -- @param graph The graph.
25 -- @param color The border color to set.
27 --- Set the graph foreground color.
30 -- @param graph The graph.
31 -- @param color The graph color.
33 --- Set the graph background color.
34 -- @name set_background_color
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
44 -- @param graph The graph.
45 -- @param value The value.
47 --- Set the graph to automatically scale its values. Default is false.
50 -- @param graph The graph.
51 -- @param scale A boolean value
53 --- Set the graph to draw stacks. Default is false.
56 -- @param graph The graph.
57 -- @param stack A boolean value.
59 --- Set the graph stacking colors. Order matters.
60 -- @name set_stack_colors
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
75 -- Draw the background first
76 cr
:set_source(color(data
[graph
].background_color
or "#000000aa"))
79 -- Account for the border width
81 if data
[graph
].border_color
then
83 width
, height
= width
- 2, height
- 2
86 -- Draw a stacked graph
87 if data
[graph
].stack
then
89 if data
[graph
].scale
then
90 for _
, v
in ipairs(values
) do
91 for __
, sv
in ipairs(v
) do
92 if sv
> max_value
then
101 local rel_x
= i
+ 0.5
103 if data
[graph
].stack_colors
then
104 for idx
, col
in ipairs(data
[graph
].stack_colors
) do
105 local stack_values
= values
[idx
]
106 if stack_values
and i
< #stack_values
then
107 local value
= stack_values
[#stack_values
- i
] + rel_i
108 cr
:move_to(rel_x
, height
* (1 - (rel_i
/ max_value
)))
109 cr
:line_to(rel_x
, height
* (1 - (value
/ max_value
)))
110 cr
:set_source(color(col
or "#ff0000"))
118 if data
[graph
].scale
then
119 for _
, v
in ipairs(values
) do
120 if v
> max_value
then
126 -- Draw the background on no value
129 for i
= 0, #values
- 1 do
130 local value
= values
[#values
- i
]
132 value
= value
/ max_value
133 cr
:move_to(i
+ 0.5, height
* (1 - value
))
134 cr
:line_to(i
+ 0.5, height
)
137 cr
:set_source(color(data
[graph
].color
or "#ff0000"))
143 -- Undo the cr:translate() for the border
146 -- Draw the border last so that it overlaps already drawn values
147 if data
[graph
].border_color
then
148 -- We decremented these by two above
149 width
, height
= width
+ 2, height
+ 2
152 cr
:rectangle(0.5, 0.5, width
- 1, height
- 1)
153 cr
:set_source(color(data
[graph
].border_color
or "#ffffff"))
158 function fit(graph
, width
, height
)
159 return data
[graph
].width
, data
[graph
].height
162 --- Add a value to the graph
163 -- @param graph The graph.
164 -- @param value The value between 0 and 1.
165 -- @param group The stack color group index.
166 local function add_value(graph
, value
, group
)
167 if not graph
then return end
169 local value
= value
or 0
170 local values
= data
[graph
].values
171 local max_value
= data
[graph
].max_value
172 value
= math
.max(0, value
)
173 if not data
[graph
].scale
then
174 value
= math
.min(max_value
, value
)
177 if data
[graph
].stack
and group
then
178 if not data
[graph
].values
[group
]
179 or type(data
[graph
].values
[group
]) ~= "table"
181 data
[graph
].values
[group
] = {}
183 values
= data
[graph
].values
[group
]
185 table.insert(values
, value
)
187 local border_width
= 0
188 if data
[graph
].border_color
then border_width
= 2 end
190 -- Ensure we never have more data than we can draw
191 while #values
> data
[graph
].width
- border_width
do
192 table.remove(values
, 1)
195 graph
:emit_signal("widget::updated")
200 --- Set the graph height.
201 -- @param graph The graph.
202 -- @param height The height to set.
203 function set_height(graph
, height
)
205 data
[graph
].height
= height
206 graph
:emit_signal("widget::updated")
211 --- Set the graph width.
212 -- @param graph The graph.
213 -- @param width The width to set.
214 function set_width(graph
, width
)
216 data
[graph
].width
= width
217 graph
:emit_signal("widget::updated")
222 -- Build properties function
223 for _
, prop
in ipairs(properties
) do
224 if not _M
["set_" .. prop
] then
225 _M
["set_" .. prop
] = function(graph
, value
)
226 data
[graph
][prop
] = value
227 graph
:emit_signal("widget::updated")
233 --- Create a graph widget.
234 -- @param args Standard widget() arguments. You should add width and height
235 -- key to set graph geometry.
236 -- @return A graph widget.
238 local args
= args
or {}
240 local width
= args
.width
or 100
241 local height
= args
.height
or 20
243 if width
< 5 or height
< 5 then return end
245 local graph
= base
.make_widget()
247 data
[graph
] = { width
= width
, height
= height
, values
= {}, max_value
= 1 }
250 graph
.add_value
= add_value
254 for _
, prop
in ipairs(properties
) do
255 graph
["set_" .. prop
] = _M
["set_" .. prop
]
261 setmetatable(_M
, { __call
= function(_
, ...) return new(...) end })
263 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80