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.
23 #include "common/draw.h"
26 #include "common/util.h"
28 extern AwesomeConf globalconf
;
33 float *max
; /** Represents a full graph */
34 int width
; /** Width of the widget */
35 float height
; /** Height of graph (0-1; 1 = height of statusbar) */
36 int box_height
; /** Height of the innerbox in pixels */
37 int padding_left
; /** Left padding */
38 int size
; /** Size of lines-array (also innerbox-lenght) */
39 XColor bg
; /** Background color */
40 XColor bordercolor
; /** Border color */
43 int index
; /** Index of current (new) value */
44 int *max_index
; /** Index of the actual maximum value */
45 float *current_max
; /** Pointer to current maximum value itself */
47 /* all data is stored here */
48 int data_items
; /** Number of data-input items */
49 int **lines
; /** Keeps the calculated values (line-length); */
50 float **values
; /** Actual values */
52 /* additional data + a pointer to **lines accordingly */
53 int **fillbottom
; /** Datatypes holder (data equal to **lines) */
54 int fillbottom_total
; /** Total of them */
55 XColor
*fillbottom_color
; /** Color of them */
56 XColor
**fillbottom_pcolor_center
; /** Color at middle of graph */
57 XColor
**fillbottom_pcolor_end
; /** Color at end of graph */
58 int **filltop
; /** Datatypes holder */
59 int filltop_total
; /** Total of them */
60 XColor
*filltop_color
; /** Color of them */
61 XColor
**filltop_pcolor_center
; /** Color at center of graph */
62 XColor
**filltop_pcolor_end
; /** Color at end of graph */
63 int **drawline
; /** Datatypes holder */
64 int drawline_total
; /** Total of them */
65 XColor
*drawline_color
; /** Color of them */
66 XColor
**drawline_pcolor_center
; /** Color at middle of graph */
67 XColor
**drawline_pcolor_end
; /** Color at end of graph */
69 int *draw_from
; /** Preparation/tmp array for draw_graph(); */
70 int *draw_to
; /** Preparation/tmp array for draw_graph(); */
75 graph_draw(Widget
*widget
, DrawCtx
*ctx
, int offset
,
76 int used
__attribute__ ((unused
)))
78 int margin_top
, left_offset
;
80 Data
*d
= widget
->data
;
83 if(d
->width
< 1 || !d
->data_items
)
86 if(!widget
->user_supplied_x
)
87 widget
->area
.x
= widget_calculate_offset(widget
->statusbar
->width
,
91 if(!widget
->user_supplied_y
)
94 margin_top
= (int) (widget
->statusbar
->height
* (1 - d
->height
)) / 2 + 0.5 + widget
->area
.y
;
95 left_offset
= widget
->area
.x
+ d
->padding_left
;
98 d
->box_height
= (int) (widget
->statusbar
->height
* d
->height
+ 0.5) - 2;
100 rectangle
.x
= left_offset
;
101 rectangle
.y
= margin_top
;
102 rectangle
.width
= d
->size
+ 2;
103 rectangle
.height
= d
->box_height
+ 2;
104 draw_rectangle(ctx
, rectangle
, False
, d
->bordercolor
);
108 rectangle
.width
-= 2;
109 rectangle
.height
-= 2;
110 draw_rectangle(ctx
, rectangle
, True
, d
->bg
);
112 draw_graph_setup(ctx
); /* setup some drawing options */
114 /* draw style = top */
115 for(z
= 0; z
< d
->filltop_total
; z
++)
117 for(y
= 0; y
< d
->size
; y
++)
119 for(tmp
= 0, x
= 0; x
< d
->filltop_total
; x
++) /* find largest smaller value */
124 if(d
->filltop
[x
][y
] > tmp
&& d
->filltop
[x
][y
] < d
->filltop
[z
][y
])
125 tmp
= d
->filltop
[x
][y
];
127 d
->draw_from
[y
] = d
->box_height
- tmp
;
128 d
->draw_to
[y
] = d
->box_height
- d
->filltop
[z
][y
];
131 left_offset
+ 2, margin_top
+ d
->box_height
+ 1,
132 d
->size
, d
->draw_from
, d
->draw_to
, d
->index
,
133 d
->filltop_color
[z
], d
->filltop_pcolor_center
[z
], d
->filltop_pcolor_end
[z
]);
136 /* draw style = bottom */
137 for(z
= 0; z
< d
->fillbottom_total
; z
++)
139 for(y
= 0; y
< d
->size
; y
++)
141 for(tmp
= 0, x
= 0; x
< d
->fillbottom_total
; x
++) /* find largest smaller value */
146 if(d
->fillbottom
[x
][y
] > tmp
&& d
->fillbottom
[x
][y
] < d
->fillbottom
[z
][y
])
147 tmp
= d
->fillbottom
[x
][y
];
149 d
->draw_from
[y
] = tmp
;
153 left_offset
+ 2, margin_top
+ d
->box_height
+ 1,
154 d
->size
, d
->draw_from
, d
->fillbottom
[z
], d
->index
,
155 d
->fillbottom_color
[z
], d
->fillbottom_pcolor_center
[z
], d
->fillbottom_pcolor_end
[z
]);
158 /* draw style = line */
159 for(z
= 0; z
< d
->drawline_total
; z
++)
162 left_offset
+ 2, margin_top
+ d
->box_height
+ 1,
163 d
->size
, d
->drawline
[z
], d
->index
,
164 d
->drawline_color
[z
], d
->drawline_pcolor_center
[z
], d
->drawline_pcolor_end
[z
]);
167 widget
->area
.width
= d
->width
;
168 widget
->area
.height
= widget
->statusbar
->height
;
169 return widget
->area
.width
;
173 graph_tell(Widget
*widget
, char *command
)
175 Data
*d
= widget
->data
;
180 if(!command
|| d
->width
< 1 || !(d
->data_items
> 0))
183 value
= p_new(float, d
->data_items
);
185 for (i
= 0, tok
= strtok(command
, ","); tok
&& i
< d
->data_items
; tok
= strtok(NULL
, ","), i
++)
186 value
[i
] = MAX(atof(tok
), 0);
188 if(++d
->index
>= d
->size
) /* cycle inside the arrays (all-in-one) */
191 /* add according values and to-draw-line-lenghts to the according data_items */
192 for(z
= 0; z
< d
->data_items
; z
++)
194 if(d
->values
[z
]) /* scale option is true */
196 d
->values
[z
][d
->index
] = value
[z
];
198 if(value
[z
] > d
->current_max
[z
]) /* a new maximum value found */
200 d
->max_index
[z
] = d
->index
;
201 d
->current_max
[z
] = value
[z
];
204 for (i
= 0; i
< d
->size
; i
++)
205 d
->lines
[z
][i
] = (int) (d
->values
[z
][i
] * (d
->box_height
) / d
->current_max
[z
] + 0.5);
207 else if(d
->max_index
[z
] == d
->index
) /* old max_index reached, re-check/generate */
209 /* find the new max */
210 for (i
= 0; i
< d
->size
; i
++)
211 if (d
->values
[z
][i
] > d
->values
[z
][d
->max_index
[z
]])
214 d
->current_max
[z
] = MAX(d
->values
[z
][d
->max_index
[z
]], d
->max
[z
]);
217 for (i
= 0; i
< d
->size
; i
++)
218 d
->lines
[z
][i
] = (int) (d
->values
[z
][i
] * d
->box_height
/ d
->current_max
[z
] + 0.5);
221 d
->lines
[z
][d
->index
] = (int) (value
[z
] * d
->box_height
/ d
->current_max
[z
] + 0.5);
224 else /* scale option is false - limit to d->box_height */
226 if (value
[z
] < d
->current_max
[z
])
227 d
->lines
[z
][d
->index
] = (int) (value
[z
] * d
->box_height
/ d
->current_max
[z
] + 0.5);
229 d
->lines
[z
][d
->index
] = d
->box_height
;
236 graph_new(Statusbar
*statusbar
, cfg_t
*config
)
242 int phys_screen
= get_phys_screen(statusbar
->screen
);
245 XColor tmp_color
= { 0, 0, 0, 0, 0, 0 };
246 XColor
*ptmp_color_center
;
247 XColor
*ptmp_color_end
;
249 w
= p_new(Widget
, 1);
250 widget_common_new(w
, statusbar
, config
);
252 w
->draw
= graph_draw
;
253 w
->tell
= graph_tell
;
254 w
->alignment
= draw_get_align(cfg_getstr(config
, "align"));
255 d
= w
->data
= p_new(Data
, 1);
257 d
->width
= cfg_getint(config
, "width");
258 d
->height
= cfg_getfloat(config
, "height");
259 d
->padding_left
= cfg_getint(config
, "padding_left");
260 d
->size
= d
->width
- d
->padding_left
- 2;
264 warn("graph widget needs: (width - padding_left) >= 3\n");
268 if(!(d
->data_items
= cfg_size(config
, "data")))
270 warn("graph widget needs at least one data section\n");
274 d
->draw_from
= p_new(int, d
->size
);
275 d
->draw_to
= p_new(int, d
->size
);
277 d
->fillbottom
= p_new(int *, d
->size
);
278 d
->filltop
= p_new(int *, d
->size
);
279 d
->drawline
= p_new(int *, d
->size
);
281 d
->values
= p_new(float *, d
->data_items
);
282 d
->lines
= p_new(int *, d
->data_items
);
284 d
->filltop_color
= p_new(XColor
, d
->data_items
);
285 d
->filltop_pcolor_center
= p_new(XColor
*, d
->data_items
);
286 d
->filltop_pcolor_end
= p_new(XColor
*, d
->data_items
);
287 d
->fillbottom_color
= p_new(XColor
, d
->data_items
);
288 d
->fillbottom_pcolor_center
= p_new(XColor
*, d
->data_items
);
289 d
->fillbottom_pcolor_end
= p_new(XColor
*, d
->data_items
);
290 d
->drawline_color
= p_new(XColor
, d
->data_items
);
291 d
->drawline_pcolor_center
= p_new(XColor
*, d
->data_items
);
292 d
->drawline_pcolor_end
= p_new(XColor
*, d
->data_items
);
294 d
->max_index
= p_new(int, d
->data_items
);
296 d
->current_max
= p_new(float, d
->data_items
);
297 d
->max
= p_new(float, d
->data_items
);
299 for(i
= 0; i
< d
->data_items
; i
++)
301 ptmp_color_center
= ptmp_color_end
= NULL
;
303 cfg
= cfg_getnsec(config
, "data", i
);
305 if((color
= cfg_getstr(cfg
, "fg")))
306 draw_color_new(globalconf
.display
, phys_screen
, color
, &tmp_color
);
308 tmp_color
= globalconf
.screens
[statusbar
->screen
].colors_normal
[ColFG
];
310 if((color
= cfg_getstr(cfg
, "fg_center")))
312 ptmp_color_center
= p_new(XColor
, 1);
313 draw_color_new(globalconf
.display
, phys_screen
, color
, ptmp_color_center
);
316 if((color
= cfg_getstr(cfg
, "fg_end")))
318 ptmp_color_end
= p_new(XColor
, 1);
319 draw_color_new(globalconf
.display
, phys_screen
, color
, ptmp_color_center
);
322 if (cfg_getbool(cfg
, "scale"))
323 d
->values
[i
] = p_new(float, d
->size
); /* not null -> scale = true */
325 /* prevent: division by zero */
326 d
->current_max
[i
] = d
->max
[i
] = cfg_getfloat(cfg
, "max");
329 warn("all graph widget needs a 'max' value greater than zero\n");
334 d
->lines
[i
] = p_new(int, d
->size
);
336 /* filter each style-typ into it's own array (for easy looping later)*/
338 if ((type
= cfg_getstr(cfg
, "style")))
340 if(!a_strncmp(type
, "bottom", sizeof("bottom")))
342 d
->fillbottom
[d
->fillbottom_total
] = d
->lines
[i
];
343 d
->fillbottom_color
[d
->fillbottom_total
] = tmp_color
;
344 d
->fillbottom_pcolor_center
[d
->fillbottom_total
] = ptmp_color_center
;
345 d
->fillbottom_pcolor_end
[d
->fillbottom_total
] = ptmp_color_end
;
346 d
->fillbottom_total
++;
348 else if (!a_strncmp(type
, "top", sizeof("top")))
350 d
->filltop
[d
->filltop_total
] = d
->lines
[i
];
351 d
->filltop_color
[d
->filltop_total
] = tmp_color
;
352 d
->filltop_pcolor_center
[d
->fillbottom_total
] = ptmp_color_center
;
353 d
->filltop_pcolor_end
[d
->fillbottom_total
] = ptmp_color_end
;
356 else if (!a_strncmp(type
, "line", sizeof("line")))
358 d
->drawline
[d
->drawline_total
] = d
->lines
[i
];
359 d
->drawline_color
[d
->drawline_total
] = tmp_color
;
360 d
->drawline_pcolor_center
[d
->fillbottom_total
] = ptmp_color_center
;
361 d
->drawline_pcolor_end
[d
->fillbottom_total
] = ptmp_color_end
;
367 if((color
= cfg_getstr(config
, "bg")))
368 draw_color_new(globalconf
.display
, phys_screen
, color
, &d
->bg
);
370 d
->bg
= globalconf
.screens
[statusbar
->screen
].colors_normal
[ColBG
];
372 if((color
= cfg_getstr(config
, "bordercolor")))
373 draw_color_new(globalconf
.display
, phys_screen
, color
, &d
->bordercolor
);
375 d
->bordercolor
= tmp_color
;
379 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80