Add a common error infratructure for widget_tell
[awesome.git] / widgets / progressbar.c
blob0f05e14ce7916f413dec65ceba2058d003ce22a3
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 /** Number of data_items (bars) */
42 int data_items;
43 /** Height 0-1, where 1 is height of statusbar */
44 float height;
45 /** Foreground color */
46 XColor *fg;
47 /** Foreground color when bar is half-full */
48 XColor **pfg_center;
49 /** Foreground color when bar is full */
50 XColor **pfg_end;
51 /** Background color */
52 XColor *bg;
53 /** Border color */
54 XColor *bordercolor;
55 } Data;
57 static int
58 progressbar_draw(Widget *widget, DrawCtx *ctx, int offset,
59 int used __attribute__ ((unused)))
61 int i, width, pwidth, margin_top, pb_height, left_offset;
62 Area rectangle;
64 Data *d = widget->data;
66 if (!(d->data_items) || (d->width - d->padding < 3))
67 return 0;
69 width = d->width - 2 * d->padding;
71 if(!widget->user_supplied_x)
72 widget->area.x = widget_calculate_offset(widget->statusbar->width,
73 d->width,
74 offset,
75 widget->alignment);
77 if(!widget->user_supplied_y)
78 widget->area.y = 0;
80 margin_top = (int) (widget->statusbar->height * (1 - d->height)) / 2 + 0.5 + widget->area.y;
81 pb_height = (int) ((widget->statusbar->height * d->height - (d->gap * (d->data_items - 1))) / d->data_items + 0.5);
82 left_offset = widget->area.x + d->padding;
84 for(i = 0; i < d->data_items; i++)
86 pwidth = (int) d->percent[i] ? ((width - 2) * d->percent[i]) / 100 : 0;
88 rectangle.x = left_offset;
89 rectangle.y = margin_top;
90 rectangle.width = width;
91 rectangle.height = pb_height;
93 draw_rectangle(ctx, rectangle, False, d->bordercolor[i]);
95 if(pwidth > 0)
97 rectangle.x = left_offset + 1;
98 rectangle.y = margin_top + 1;
99 rectangle.width = pwidth;
100 rectangle.height = pb_height - 2;
101 draw_rectangle_gradient(ctx, rectangle, width - 2, True, d->fg[i],
102 d->pfg_center[i], d->pfg_end[i]);
105 if(width - 2 - pwidth > 0) /* not filled area */
107 rectangle.x = left_offset + 1 + pwidth;
108 rectangle.y = margin_top + 1;
109 rectangle.width = width - 2 - pwidth;
110 rectangle.height = pb_height - 2;
111 draw_rectangle(ctx, rectangle, True, d->bg[i]);
114 margin_top += (pb_height + d->gap);
117 widget->area.width = d->width;
118 widget->area.height = widget->statusbar->height;
119 return widget->area.width;
122 static widget_tell_status_t
123 progressbar_tell(Widget *widget, char *property, char *command)
125 Data *d = widget->data;
126 int i = 0, percent;
127 Bool flag;
128 char *title, *setting;
130 if(!property || !command || !d->data_items)
131 return WIDGET_ERROR;
133 if(!a_strcmp(property, "data"))
135 title = strtok(command, " ");
136 setting = strtok(NULL, " ");
137 for(i = 0; i < d->data_items; i++)
138 if(!a_strcmp(title, d->data_title[i]))
140 percent = atoi(setting);
141 d->percent[i] = (percent < 0 ? 0 : (percent > 100 ? 100 : percent));
142 return WIDGET_NOERROR;
144 return WIDGET_ERROR_FORMAT_SECTION;
146 else if(!a_strcmp(property, "fg"))
148 title = strtok(command, " ");
149 setting = strtok(NULL, " ");
150 for(i = 0; i < d->data_items; i++)
151 if(!a_strcmp(title, d->data_title[i]))
153 draw_color_new(globalconf.display, get_phys_screen(widget->statusbar->screen),
154 setting, &d->fg[i]);
155 return WIDGET_NOERROR;
157 return WIDGET_ERROR_FORMAT_SECTION;
159 else if(!a_strcmp(property, "bg"))
161 title = strtok(command, " ");
162 setting = strtok(NULL, " ");
163 for(i = 0; i < d->data_items; i++)
164 if(!a_strcmp(title, d->data_title[i]))
166 draw_color_new(globalconf.display, get_phys_screen(widget->statusbar->screen),
167 setting, &d->bg[i]);
168 return WIDGET_NOERROR;
170 return WIDGET_ERROR_FORMAT_SECTION;
172 else if(!a_strcmp(property, "fg_center"))
174 title = strtok(command, " ");
175 setting = strtok(NULL, " ");
176 for(i = 0; i < d->data_items; i++)
177 if(!a_strcmp(title, d->data_title[i]))
179 flag = False;
180 if(!d->pfg_center[i])
182 flag = True; /* restore to NULL & p_delete */
183 d->pfg_center[i] = p_new(XColor, 1);
185 if(!(draw_color_new(globalconf.display, get_phys_screen(widget->statusbar->screen),
186 setting, d->pfg_center[i])))
187 if(flag) /* restore */
189 p_delete(&d->pfg_center[i]);
190 d->pfg_center[i] = NULL;
192 return WIDGET_NOERROR;
194 return WIDGET_ERROR_FORMAT_SECTION;
196 else if(!a_strcmp(property, "fg_end"))
198 title = strtok(command, " ");
199 setting = strtok(NULL, " ");
200 for(i = 0; i < d->data_items; i++)
201 if(!a_strcmp(title, d->data_title[i]))
203 flag = False;
204 if(!d->pfg_end[i])
206 flag = True; /* restore to NULL & p_delete */
207 d->pfg_end[i] = p_new(XColor, 1);
209 if(!(draw_color_new(globalconf.display, get_phys_screen(widget->statusbar->screen),
210 setting, d->pfg_end[i])))
211 if(flag) /* restore */
213 p_delete(&d->pfg_end[i]);
214 d->pfg_end[i] = NULL;
216 return WIDGET_NOERROR;
219 else if(!a_strcmp(property, "bordercolor"))
221 title = strtok(command, " ");
222 setting = strtok(NULL, " ");
223 for(i = 0; i < d->data_items; i++)
224 if(!a_strcmp(title, d->data_title[i]))
226 draw_color_new(globalconf.display, get_phys_screen(widget->statusbar->screen),
227 setting, &d->bordercolor[i]);
228 return WIDGET_NOERROR;
230 return WIDGET_ERROR_FORMAT_SECTION;
232 else if(!a_strcmp(property, "gap"))
233 d->gap = atoi(command);
234 else if(!a_strcmp(property, "width"))
236 d->width = atoi(command);
237 if(d->width - d->padding < 3)
238 warn("progressbar widget needs: (width - padding) >= 3\n");
239 return WIDGET_ERROR_CUSTOM;
241 else if(!a_strcmp(property, "height"))
242 d->height = atof(command);
243 else if(!a_strcmp(property, "padding"))
244 d->padding = atoi(command);
245 else
246 return WIDGET_ERROR;
248 return WIDGET_NOERROR;
251 Widget *
252 progressbar_new(Statusbar *statusbar, cfg_t *config)
254 Widget *w;
255 Data *d;
256 char *color;
257 int i, phys_screen = get_phys_screen(statusbar->screen);
258 cfg_t *cfg;
260 w = p_new(Widget, 1);
261 widget_common_new(w, statusbar, config);
262 w->draw = progressbar_draw;
263 w->tell = progressbar_tell;
264 d = w->data = p_new(Data, 1);
265 d->width = cfg_getint(config, "width");
266 d->height = cfg_getfloat(config, "height");
267 d->gap = cfg_getint(config, "gap");
268 d->padding = cfg_getint(config, "padding");
270 w->alignment = draw_get_align(cfg_getstr(config, "align"));
273 if(!(d->data_items = cfg_size(config, "data")))
275 warn("progressbar widget needs at least one bar section\n");
276 return w;
279 d->fg = p_new(XColor, d->data_items);
280 d->pfg_end = p_new(XColor *, d->data_items);
281 d->pfg_center = p_new(XColor *, d->data_items);
282 d->bg = p_new(XColor, d->data_items);
283 d->bordercolor = p_new(XColor, d->data_items);
284 d->percent = p_new(int, d->data_items);
285 d->data_title = p_new(char *, d->data_items);
287 for(i = 0; i < d->data_items; i++)
289 cfg = cfg_getnsec(config, "data", i);
291 d->data_title[i] = a_strdup(cfg_title(cfg));
293 if((color = cfg_getstr(cfg, "fg")))
294 draw_color_new(globalconf.display, phys_screen, color, &d->fg[i]);
295 else
296 d->fg[i] = globalconf.screens[statusbar->screen].colors_normal[ColFG];
298 if((color = cfg_getstr(cfg, "fg_center")))
300 d->pfg_center[i] = p_new(XColor, 1);
301 draw_color_new(globalconf.display, phys_screen, color, d->pfg_center[i]);
304 if((color = cfg_getstr(cfg, "fg_end")))
306 d->pfg_end[i] = p_new(XColor, 1);
307 draw_color_new(globalconf.display, phys_screen, color, d->pfg_end[i]);
310 if((color = cfg_getstr(cfg, "bg")))
311 draw_color_new(globalconf.display, phys_screen, color, &d->bg[i]);
312 else
313 d->bg[i] = globalconf.screens[statusbar->screen].colors_normal[ColBG];
315 if((color = cfg_getstr(cfg, "bordercolor")))
316 draw_color_new(globalconf.display, phys_screen, color, &d->bordercolor[i]);
317 else
318 d->bordercolor[i] = d->fg[i];
321 /* complete setup, since someone might 'enable' it with increasing the width with widget_tell */
322 if(d->width - d->padding < 3)
324 warn("progressbar widget needs: (width - padding) >= 3\n");
325 return w;
328 return w;
330 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80