2 * graph.c - a graph widget
4 * Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
5 * Copyright © 2007-2008 Marco Candrian <mac@calmar.ws>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "common/draw.h"
27 #include "common/util.h"
29 extern AwesomeConf globalconf
;
34 float *max
; /* Represents a full graph */
35 int width
; /* Width of the widget */
36 float height
; /* Height of graph (0-1, where 1 is height of statusbar) */
37 int box_height
; /* Height of the innerbox in pixels */
38 int padding_left
; /* Left padding */
39 int size
; /* Size of lines-array (also innerbox-lenght) */
40 XColor bg
; /* Background color */
41 XColor bordercolor
; /* Border color */
44 int index
; /* Index of current (new) value */
45 int *max_index
; /* Index of the actual maximum value */
46 float *current_max
; /* Pointer to current maximum value itself */
48 /* all data is stored here */
49 int data_items
; /* Number of data-input items */
50 int **lines
; /* Keeps the calculated values (line-length); */
51 float **values
; /* Actual values */
53 /* additional data + a pointer to **lines accordingly */
54 int **fillbottom
; /* datatypes holder (same as some **lines pointer) */
55 int fillbottom_total
; /* total of them */
56 XColor
*fillbottom_color
; /* color of them */
57 int **filltop
; /* datatypes holder */
58 int filltop_total
; /* total of them */
59 XColor
*filltop_color
; /* color of them */
60 int **drawline
; /* datatypes holder */
61 int drawline_total
; /* total of them */
62 XColor
*drawline_color
; /* color of them */
64 int *draw_from
; /* Preparation/tmp array for draw_graph(); */
65 int *draw_to
; /* Preparation/tmp array for draw_graph(); */
70 graph_draw(Widget
*widget
, DrawCtx
*ctx
, int offset
,
71 int used
__attribute__ ((unused
)))
73 int margin_top
, left_offset
;
75 Data
*d
= widget
->data
;
77 cairo_surface_t
*surface
;
80 if(d
->width
< 1 || !d
->data_items
)
83 if(!widget
->user_supplied_x
)
84 widget
->area
.x
= widget_calculate_offset(widget
->statusbar
->width
,
88 if(!widget
->user_supplied_y
)
91 margin_top
= (int) (widget
->statusbar
->height
* (1 - d
->height
)) / 2 + 0.5 + widget
->area
.y
;
92 left_offset
= widget
->area
.x
+ d
->padding_left
;
95 d
->box_height
= (int) (widget
->statusbar
->height
* d
->height
+ 0.5) - 2;
97 rectangle
.x
= left_offset
;
98 rectangle
.y
= margin_top
;
99 rectangle
.width
= d
->size
+ 2;
100 rectangle
.height
= d
->box_height
+ 2;
101 draw_rectangle(ctx
, rectangle
, False
, d
->bordercolor
);
105 rectangle
.width
-= 2;
106 rectangle
.height
-= 2;
107 draw_rectangle(ctx
, rectangle
, True
, d
->bg
);
109 draw_graph_init(ctx
, &surface
, &cr
); /* setup drawing surface etc */
111 /* draw style = top */
112 for(z
= 0; z
< d
->filltop_total
; z
++)
114 for(y
= 0; y
< d
->size
; y
++)
116 for(tmp
= 0, x
= 0; x
< d
->filltop_total
; x
++) /* find largest smaller value */
121 if(d
->filltop
[x
][y
] > tmp
&& d
->filltop
[x
][y
] < d
->filltop
[z
][y
])
122 tmp
= d
->filltop
[x
][y
];
124 d
->draw_from
[y
] = d
->box_height
- tmp
;
125 d
->draw_to
[y
] = d
->box_height
- d
->filltop
[z
][y
];
128 left_offset
+ 2, margin_top
+ d
->box_height
+ 1,
129 d
->size
, d
->draw_from
, d
->draw_to
, d
->index
,
130 d
->filltop_color
[z
]);
133 /* draw style = bottom */
134 for(z
= 0; z
< d
->fillbottom_total
; z
++)
136 for(y
= 0; y
< d
->size
; y
++)
138 for(tmp
= 0, x
= 0; x
< d
->fillbottom_total
; x
++) /* find largest smaller value */
143 if(d
->fillbottom
[x
][y
] > tmp
&& d
->fillbottom
[x
][y
] < d
->fillbottom
[z
][y
])
144 tmp
= d
->fillbottom
[x
][y
];
146 d
->draw_from
[y
] = tmp
;
150 left_offset
+ 2, margin_top
+ d
->box_height
+ 1,
151 d
->size
, d
->draw_from
, d
->fillbottom
[z
], d
->index
,
152 d
->fillbottom_color
[z
]);
155 /* draw style = line */
156 for(z
= 0; z
< d
->drawline_total
; z
++)
159 left_offset
+ 2, margin_top
+ d
->box_height
+ 1,
160 d
->size
, d
->drawline
[z
], d
->index
,
161 d
->drawline_color
[z
]);
164 draw_graph_end(surface
, cr
);
166 widget
->area
.width
= d
->width
;
167 widget
->area
.height
= widget
->statusbar
->height
;
168 return widget
->area
.width
;
172 graph_tell(Widget
*widget
, char *command
)
174 Data
*d
= widget
->data
;
179 if(!command
|| d
->width
< 1 || !(d
->data_items
> 0))
182 value
= p_new(float, d
->data_items
);
184 for (i
= 0, tok
= strtok(command
, ","); tok
&& i
< d
->data_items
; tok
= strtok(NULL
, ","), i
++)
185 value
[i
] = MAX(atof(tok
), 0);
187 if(++d
->index
>= d
->size
) /* cycle inside the arrays (all-in-one) */
190 /* add according values and to-draw-line-lenghts to the according data_items */
191 for(z
= 0; z
< d
->data_items
; z
++)
193 if(d
->values
[z
]) /* scale option is true */
195 d
->values
[z
][d
->index
] = value
[z
];
197 if(value
[z
] > d
->current_max
[z
]) /* a new maximum value found */
199 d
->max_index
[z
] = d
->index
;
200 d
->current_max
[z
] = value
[z
];
203 for (i
= 0; i
< d
->size
; i
++)
204 d
->lines
[z
][i
] = (int) (d
->values
[z
][i
] * (d
->box_height
) / d
->current_max
[z
] + 0.5);
206 else if(d
->max_index
[z
] == d
->index
) /* old max_index reached, re-check/generate */
208 /* find the new max */
209 for (i
= 0; i
< d
->size
; i
++)
210 if (d
->values
[z
][i
] > d
->values
[z
][d
->max_index
[z
]])
213 d
->current_max
[z
] = MAX(d
->values
[z
][d
->max_index
[z
]], d
->max
[z
]);
216 for (i
= 0; i
< d
->size
; i
++)
217 d
->lines
[z
][i
] = (int) (d
->values
[z
][i
] * d
->box_height
/ d
->current_max
[z
] + 0.5);
220 d
->lines
[z
][d
->index
] = (int) (value
[z
] * d
->box_height
/ d
->current_max
[z
] + 0.5);
223 else /* scale option is false - limit to d->box_height */
225 if (value
[z
] < d
->current_max
[z
])
226 d
->lines
[z
][d
->index
] = (int) (value
[z
] * d
->box_height
/ d
->current_max
[z
] + 0.5);
228 d
->lines
[z
][d
->index
] = d
->box_height
;
234 graph_new(Statusbar
*statusbar
, cfg_t
*config
)
240 int phys_screen
= get_phys_screen(statusbar
->screen
);
245 w
= p_new(Widget
, 1);
246 widget_common_new(w
, statusbar
, config
);
248 w
->draw
= graph_draw
;
249 w
->tell
= graph_tell
;
250 d
= w
->data
= p_new(Data
, 1);
252 d
->width
= cfg_getint(config
, "width");
253 d
->height
= cfg_getfloat(config
, "height");
254 d
->padding_left
= cfg_getint(config
, "padding_left");
255 d
->size
= d
->width
- d
->padding_left
- 2;
259 warn("graph widget needs: (width - padding_left) >= 3\n");
263 if(!(d
->data_items
= cfg_size(config
, "data")))
265 warn("graph widget needs at least one data section\n");
269 d
->draw_from
= p_new(int, d
->size
);
270 d
->draw_to
= p_new(int, d
->size
);
272 d
->fillbottom
= p_new(int *, d
->size
);
273 d
->filltop
= p_new(int *, d
->size
);
274 d
->drawline
= p_new(int *, d
->size
);
276 d
->values
= p_new(float *, d
->data_items
);
277 d
->lines
= p_new(int *, d
->data_items
);
279 d
->filltop_color
= p_new(XColor
, d
->data_items
);
280 d
->fillbottom_color
= p_new(XColor
, d
->data_items
);
281 d
->drawline_color
= p_new(XColor
, d
->data_items
);
283 d
->max_index
= p_new(int, d
->data_items
);
285 d
->current_max
= p_new(float, d
->data_items
);
286 d
->max
= p_new(float, d
->data_items
);
288 for(i
= 0; i
< d
->data_items
; i
++)
290 cfg
= cfg_getnsec(config
, "data", i
);
292 if((color
= cfg_getstr(cfg
, "fg")))
293 tmp_color
= draw_color_new(globalconf
.display
, phys_screen
, color
);
295 tmp_color
= globalconf
.screens
[statusbar
->screen
].colors_normal
[ColFG
];
297 if (cfg_getbool(cfg
, "scale"))
298 d
->values
[i
] = p_new(float, d
->size
); /* not null -> scale = true */
300 /* prevent: division by zero */
301 d
->current_max
[i
] = d
->max
[i
] = cfg_getfloat(cfg
, "max");
304 warn("all graph widget needs a 'max' value greater than zero\n");
309 d
->lines
[i
] = p_new(int, d
->size
);
311 /* filter each style-typ into it's own array (for easy looping later)*/
313 if ((type
= cfg_getstr(cfg
, "style")))
315 if(!strncmp(type
, "bottom", sizeof("bottom")))
317 d
->fillbottom
[d
->fillbottom_total
] = d
->lines
[i
];
318 d
->fillbottom_color
[d
->fillbottom_total
] = tmp_color
;
319 d
->fillbottom_total
++;
321 else if (!strncmp(type
, "top", sizeof("top")))
323 d
->filltop
[d
->filltop_total
] = d
->lines
[i
];
324 d
->filltop_color
[d
->filltop_total
] = tmp_color
;
327 else if (!strncmp(type
, "line", sizeof("line")))
329 d
->drawline
[d
->drawline_total
] = d
->lines
[i
];
330 d
->drawline_color
[d
->drawline_total
] = tmp_color
;
336 if((color
= cfg_getstr(config
, "bg")))
337 d
->bg
= draw_color_new(globalconf
.display
, phys_screen
, color
);
339 d
->bg
= globalconf
.screens
[statusbar
->screen
].colors_normal
[ColBG
];
341 if((color
= cfg_getstr(config
, "bordercolor")))
342 d
->bordercolor
= draw_color_new(globalconf
.display
, phys_screen
, color
);
344 d
->bordercolor
= tmp_color
;
348 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80