Font removed where style should be used now
[awesome.git] / widgets / progressbar.c
blob7e5365f1cec350874d6f5d062b7e6ab4f24547d6
1 /*
2 * progressbar.c - progress bar widget
4 * Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <string.h>
23 #include "widget.h"
24 #include "screen.h"
25 #include "common/util.h"
27 extern AwesomeConf globalconf;
29 typedef struct
31 /** Percent 0 to 100 */
32 int *percent;
33 /** data_title of the data */
34 char **data_title;
35 /** Width of the data_items */
36 int width;
37 /** Padding */
38 int padding;
39 /** Pixel between data_items (bars) */
40 int gap;
41 /** reverse drawing */
42 Bool *reverse;
43 /** 90 Degree's turned */
44 Bool vertical;
45 /** Number of data_items (bars) */
46 int data_items;
47 /** Height 0-1, where 1 is height of statusbar */
48 float height;
49 /** Foreground color */
50 XColor *fg;
51 /** Foreground color when bar is half-full */
52 XColor **pfg_center;
53 /** Foreground color when bar is full */
54 XColor **pfg_end;
55 /** Background color */
56 XColor *bg;
57 /** Border color */
58 XColor *bordercolor;
59 } Data;
61 static int
62 progressbar_draw(Widget *widget, DrawCtx *ctx, int offset,
63 int used __attribute__ ((unused)))
65 int i, pb_x, pb_y, pb_height, pb_width, pb_progress, pb_offset = 0;
66 area_t rectangle, pattern_rect;
68 Data *d = widget->data;
70 if (!d->data_items)
71 return 0;
73 if(!widget->user_supplied_x)
74 widget->area.x = widget_calculate_offset(widget->statusbar->width,
75 d->width,
76 offset,
77 widget->alignment);
78 if(!widget->user_supplied_y)
79 widget->area.y = 0;
81 /* TODO: maybe prevent (use Data-values) to calculate that stuff below over and over again */
82 /* data for the first rectangle (data-bar) to draw */
83 if(d->vertical)
85 pb_width = (int) ((d->width - d->padding - (d->gap * (d->data_items - 1))) / d->data_items + 0.5);
86 pb_height = (int) (widget->statusbar->height * d->height + 0.5);
87 pb_y = widget->area.y + (int)((widget->statusbar->height - pb_height) / 2 + 0.5);
89 else /* horizontal */
91 pb_width = d->width - d->padding;
92 pb_height = (int) ((widget->statusbar->height * d->height - (d->gap * (d->data_items - 1))) / d->data_items + 0.5);
93 pb_y = widget->area.y + (int)((widget->statusbar->height - widget->statusbar->height * d->height) / 2 + 0.5);
96 pb_x = widget->area.x + d->padding;
98 /* for a 'reversed' progressbar:
99 * 1. the full space gets the size of the formerly empty one
100 * 2. the pattern must be mirrored
101 * 3. the formerly 'empty' side gets drawed with fg colors, the 'full' with bg-color
103 * Might could be put into a single function (removing same/similar code) - feel free
105 if(d->vertical)
107 for(i = 0; i < d->data_items; i++)
109 /* border rectangle */
110 rectangle.x = pb_x + pb_offset;
111 rectangle.y = pb_y;
112 rectangle.width = pb_width;
113 rectangle.height = pb_height;
114 draw_rectangle(ctx, rectangle, False, d->bordercolor[i]);
116 /* new value/progress in px + pattern setup */
117 if(!d->reverse[i])
119 pb_progress = (int)(((pb_height - 2) * d->percent[i]) / 100 + 0.5);
120 /* bottom to top */
121 pattern_rect.x = pb_x;
122 pattern_rect.y = pb_y + 1 + pb_height ;
123 pattern_rect.width = 0;
124 pattern_rect.height = -pb_height;
126 else
128 pb_progress = (int)(((pb_height - 2) * (100 - d->percent[i])) / 100 + 0.5);
129 /* top to bottom */
130 pattern_rect.x = pb_x + 1;
131 pattern_rect.y = pb_y + 1;
132 pattern_rect.width = 0;
133 pattern_rect.height = pb_height;
136 /* bottom part */
137 if(pb_progress > 0)
139 rectangle.x = pb_x + pb_offset + 1;
140 rectangle.y = pb_y + 1 + (pb_height - 2) - pb_progress;
141 rectangle.width = pb_width - 2;
142 rectangle.height = pb_progress;
144 /* fg color */
145 if(!d->reverse[i])
146 draw_rectangle_gradient(ctx, rectangle, True, pattern_rect,
147 &(d->fg[i]), d->pfg_center[i], d->pfg_end[i]);
148 else /*REV: bg */
149 draw_rectangle(ctx, rectangle, True, d->bg[i]);
152 /* top part */
153 if((pb_height - 2) - pb_progress > 0) /* not filled area */
155 rectangle.x = pb_x + 1 + pb_offset;
156 rectangle.y = pb_y + 1;
157 rectangle.width = pb_width - 2;
158 rectangle.height = pb_height - 2 - pb_progress;
160 /* bg color */
161 if(!d->reverse[i])
162 draw_rectangle(ctx, rectangle, True, d->bg[i]);
163 else /* REV: bg */
164 draw_rectangle_gradient(ctx, rectangle, True, pattern_rect,
165 &(d->fg[i]), d->pfg_center[i], d->pfg_end[i]);
167 pb_offset += pb_width + d->gap;
170 else /* a horizontal progressbar */
172 for(i = 0; i < d->data_items; i++)
174 /* border rectangle */
175 rectangle.x = pb_x;
176 rectangle.y = pb_y + pb_offset;
177 rectangle.width = pb_width;
178 rectangle.height = pb_height;
179 draw_rectangle(ctx, rectangle, False, d->bordercolor[i]);
181 /* new value/progress in px + pattern setup */
182 if(!d->reverse[i])
184 pb_progress = (int)(((pb_width - 2) * d->percent[i]) / 100 + 0.5);
185 /* left to right */
186 pattern_rect.x = pb_x + 1;
187 pattern_rect.y = pb_y + 1;
188 pattern_rect.width = pb_width;
189 pattern_rect.height = 0;
191 else
193 pb_progress = (int)(((pb_width - 2) * (100 - d->percent[i])) / 100 + 0.5);
194 /* REV: right to left */
195 pattern_rect.x = pb_x + 1 + pb_width;
196 pattern_rect.y = pb_y + 1;
197 pattern_rect.width = -pb_width;
198 pattern_rect.height = 0;
201 /* left part */
202 if(pb_progress > 0)
204 rectangle.x = pb_x + 1;
205 rectangle.y = pb_y + 1 + pb_offset;
206 rectangle.width = pb_progress;
207 rectangle.height = pb_height - 2;
209 /* fg color */
210 if(!d->reverse[i])
211 draw_rectangle_gradient(ctx, rectangle, True, pattern_rect,
212 &(d->fg[i]), d->pfg_center[i], d->pfg_end[i]);
213 else /* REV: bg */
214 draw_rectangle(ctx, rectangle, True, d->bg[i]);
217 /* right part */
218 if(pb_width - 2 - pb_progress > 0)
220 rectangle.x = pb_x + 1 + pb_progress;
221 rectangle.y = pb_y + 1 + pb_offset;
222 rectangle.width = pb_width - 2 - pb_progress;
223 rectangle.height = pb_height - 2;
225 /* bg color */
226 if(!d->reverse[i])
227 draw_rectangle(ctx, rectangle, True, d->bg[i]);
228 else /* REV: fg */
229 draw_rectangle_gradient(ctx, rectangle, True, pattern_rect,
230 &(d->fg[i]), d->pfg_center[i], d->pfg_end[i]);
232 pb_offset += pb_height + d->gap;
236 widget->area.width = d->width;
237 widget->area.height = widget->statusbar->height;
238 return widget->area.width;
241 static widget_tell_status_t
242 progressbar_tell(Widget *widget, char *property, char *command)
244 Data *d = widget->data;
245 int i = 0, percent, tmp;
246 Bool flag;
247 char *title, *setting;
249 if(!d->data_items)
250 return WIDGET_ERROR_CUSTOM; /* error already printed on _new */
252 if(!command)
253 return WIDGET_ERROR_NOVALUE;
255 if(!a_strcmp(property, "data"))
257 title = strtok(command, " ");
258 if(!(setting = strtok(NULL, " ")))
259 return WIDGET_ERROR_NOVALUE;
260 for(i = 0; i < d->data_items; i++)
261 if(!a_strcmp(title, d->data_title[i]))
263 percent = atoi(setting);
264 d->percent[i] = (percent < 0 ? 0 : (percent > 100 ? 100 : percent));
265 return WIDGET_NOERROR;
267 return WIDGET_ERROR_FORMAT_SECTION;
269 else if(!a_strcmp(property, "fg"))
271 title = strtok(command, " ");
272 if(!(setting = strtok(NULL, " ")))
273 return WIDGET_ERROR_NOVALUE;
274 for(i = 0; i < d->data_items; i++)
275 if(!a_strcmp(title, d->data_title[i]))
277 if(draw_color_new(globalconf.display, get_phys_screen(widget->statusbar->screen),
278 setting, &d->fg[i]))
279 return WIDGET_NOERROR;
280 else
281 return WIDGET_ERROR_FORMAT_COLOR;
283 return WIDGET_ERROR_FORMAT_SECTION;
285 else if(!a_strcmp(property, "bg"))
287 title = strtok(command, " ");
288 if(!(setting = strtok(NULL, " ")))
289 return WIDGET_ERROR_NOVALUE;
290 for(i = 0; i < d->data_items; i++)
291 if(!a_strcmp(title, d->data_title[i]))
293 if(draw_color_new(globalconf.display, get_phys_screen(widget->statusbar->screen),
294 setting, &d->bg[i]))
295 return WIDGET_NOERROR;
296 else
297 return WIDGET_ERROR_FORMAT_COLOR;
299 return WIDGET_ERROR_FORMAT_SECTION;
301 else if(!a_strcmp(property, "fg_center"))
303 title = strtok(command, " ");
304 if(!(setting = strtok(NULL, " ")))
305 return WIDGET_ERROR_NOVALUE;
306 for(i = 0; i < d->data_items; i++)
307 if(!a_strcmp(title, d->data_title[i]))
309 flag = False;
310 if(!d->pfg_center[i])
312 flag = True; /* p_delete && restore to NULL, if draw_color_new unsuccessful */
313 d->pfg_center[i] = p_new(XColor, 1);
315 if(!(draw_color_new(globalconf.display, get_phys_screen(widget->statusbar->screen),
316 setting, d->pfg_center[i])))
318 if(flag) /* restore */
320 p_delete(&d->pfg_center[i]);
321 d->pfg_center[i] = NULL;
323 return WIDGET_ERROR_FORMAT_COLOR;
325 return WIDGET_NOERROR;
327 return WIDGET_ERROR_FORMAT_SECTION;
329 else if(!a_strcmp(property, "fg_end"))
331 title = strtok(command, " ");
332 if(!(setting = strtok(NULL, " ")))
333 return WIDGET_ERROR_NOVALUE;
334 for(i = 0; i < d->data_items; i++)
335 if(!a_strcmp(title, d->data_title[i]))
337 flag = False;
338 if(!d->pfg_end[i])
340 flag = True;
341 d->pfg_end[i] = p_new(XColor, 1);
343 if(!(draw_color_new(globalconf.display, get_phys_screen(widget->statusbar->screen),
344 setting, d->pfg_end[i])))
346 if(flag) /* restore */
348 p_delete(&d->pfg_end[i]);
349 d->pfg_end[i] = NULL;
351 return WIDGET_ERROR_FORMAT_COLOR;
353 return WIDGET_NOERROR;
356 else if(!a_strcmp(property, "bordercolor"))
358 title = strtok(command, " ");
359 if(!(setting = strtok(NULL, " ")))
360 return WIDGET_ERROR_NOVALUE;
361 for(i = 0; i < d->data_items; i++)
362 if(!a_strcmp(title, d->data_title[i]))
364 if(draw_color_new(globalconf.display, get_phys_screen(widget->statusbar->screen),
365 setting, &d->bordercolor[i]))
366 return WIDGET_NOERROR;
367 else
368 return WIDGET_ERROR_FORMAT_COLOR;
370 return WIDGET_ERROR_FORMAT_SECTION;
372 else if(!a_strcmp(property, "gap"))
373 d->gap = atoi(command);
374 else if(!a_strcmp(property, "width"))
376 tmp = atoi(command);
377 if(tmp - d->padding < 3)
379 warn("progressbar widget needs: (width - padding) >= 3. Ignoring command.\n");
380 return WIDGET_ERROR_CUSTOM;
382 else
383 d->width = tmp;
385 else if(!a_strcmp(property, "height"))
386 d->height = atof(command);
387 else if(!a_strcmp(property, "padding"))
389 tmp = atoi(command);
390 if(d->width - tmp < 3)
392 warn("progressbar widget needs: (width - padding) >= 3. Ignoring command.\n");
393 return WIDGET_ERROR_CUSTOM;
395 else
396 d->padding = tmp;
398 else
399 return WIDGET_ERROR;
401 return WIDGET_NOERROR;
404 Widget *
405 progressbar_new(Statusbar *statusbar, cfg_t *config)
407 Widget *w;
408 Data *d;
409 char *color;
410 int i, phys_screen = get_phys_screen(statusbar->screen);
411 cfg_t *cfg;
413 w = p_new(Widget, 1);
414 widget_common_new(w, statusbar, config);
415 w->draw = progressbar_draw;
416 w->tell = progressbar_tell;
417 d = w->data = p_new(Data, 1);
418 d->width = cfg_getint(config, "width");
419 d->padding = cfg_getint(config, "padding");
421 if(d->width - d->padding < 3)
423 warn("progressbar widget needs: (width - padding) >= 3\n");
424 return w;
427 d->height = cfg_getfloat(config, "height");
428 d->gap = cfg_getint(config, "gap");
429 d->padding = cfg_getint(config, "padding");
430 if(!(d->vertical = cfg_getbool(config, "vertical")))
431 d->vertical = False;
433 w->alignment = draw_get_align(cfg_getstr(config, "align"));
435 if(!(d->data_items = cfg_size(config, "data")))
437 warn("progressbar widget needs at least one bar section\n");
438 return w;
441 d->fg = p_new(XColor, d->data_items);
442 d->pfg_end = p_new(XColor *, d->data_items);
443 d->pfg_center = p_new(XColor *, d->data_items);
444 d->bg = p_new(XColor, d->data_items);
445 d->bordercolor = p_new(XColor, d->data_items);
446 d->percent = p_new(int, d->data_items);
447 d->reverse = p_new(Bool, d->data_items);
448 d->data_title = p_new(char *, d->data_items);
450 for(i = 0; i < d->data_items; i++)
452 cfg = cfg_getnsec(config, "data", i);
454 d->data_title[i] = a_strdup(cfg_title(cfg));
456 if(!(d->reverse[i] = cfg_getbool(cfg, "reverse")))
457 d->reverse[i] = False;
459 if((color = cfg_getstr(cfg, "fg")))
460 draw_color_new(globalconf.display, phys_screen, color, &d->fg[i]);
461 else
462 d->fg[i] = globalconf.screens[statusbar->screen].styles.normal.fg;
464 if((color = cfg_getstr(cfg, "fg_center")))
466 d->pfg_center[i] = p_new(XColor, 1);
467 draw_color_new(globalconf.display, phys_screen, color, d->pfg_center[i]);
470 if((color = cfg_getstr(cfg, "fg_end")))
472 d->pfg_end[i] = p_new(XColor, 1);
473 draw_color_new(globalconf.display, phys_screen, color, d->pfg_end[i]);
476 if((color = cfg_getstr(cfg, "bg")))
477 draw_color_new(globalconf.display, phys_screen, color, &d->bg[i]);
478 else
479 d->bg[i] = globalconf.screens[statusbar->screen].styles.normal.bg;
481 if((color = cfg_getstr(cfg, "bordercolor")))
482 draw_color_new(globalconf.display, phys_screen, color, &d->bordercolor[i]);
483 else
484 d->bordercolor[i] = d->fg[i];
487 return w;
489 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80