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.
25 #include "common/util.h"
27 extern AwesomeConf globalconf
;
31 /** Percent 0 to 100 */
33 /** data_title of the data */
35 /** Width of the data_items */
39 /** Pixel between data_items (bars) */
41 /** reverse drawing */
43 /** 90 Degree's turned */
45 /** Number of data_items (bars) */
47 /** Height 0-1, where 1 is height of statusbar */
49 /** Foreground color */
51 /** Foreground color when bar is half-full */
53 /** Foreground color when bar is full */
55 /** Background color */
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
;
73 if(!widget
->user_supplied_x
)
74 widget
->area
.x
= widget_calculate_offset(widget
->statusbar
->width
,
78 if(!widget
->user_supplied_y
)
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 */
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);
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
107 for(i
= 0; i
< d
->data_items
; i
++)
109 /* border rectangle */
110 rectangle
.x
= pb_x
+ pb_offset
;
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 */
119 pb_progress
= (int)(((pb_height
- 2) * d
->percent
[i
]) / 100 + 0.5);
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
;
128 pb_progress
= (int)(((pb_height
- 2) * (100 - d
->percent
[i
])) / 100 + 0.5);
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
;
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
;
146 draw_rectangle_gradient(ctx
, rectangle
, True
, pattern_rect
,
147 &(d
->fg
[i
]), d
->pfg_center
[i
], d
->pfg_end
[i
]);
149 draw_rectangle(ctx
, rectangle
, True
, d
->bg
[i
]);
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
;
162 draw_rectangle(ctx
, rectangle
, True
, d
->bg
[i
]);
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 */
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 */
184 pb_progress
= (int)(((pb_width
- 2) * d
->percent
[i
]) / 100 + 0.5);
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;
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;
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;
211 draw_rectangle_gradient(ctx
, rectangle
, True
, pattern_rect
,
212 &(d
->fg
[i
]), d
->pfg_center
[i
], d
->pfg_end
[i
]);
214 draw_rectangle(ctx
, rectangle
, True
, d
->bg
[i
]);
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;
227 draw_rectangle(ctx
, rectangle
, True
, d
->bg
[i
]);
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
;
247 char *title
, *setting
;
250 return WIDGET_ERROR_CUSTOM
; /* error already printed on _new */
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
),
279 return WIDGET_NOERROR
;
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
),
295 return WIDGET_NOERROR
;
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
]))
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
]))
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
;
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"))
377 if(tmp
- d
->padding
< 3)
379 warn("progressbar widget needs: (width - padding) >= 3. Ignoring command.\n");
380 return WIDGET_ERROR_CUSTOM
;
385 else if(!a_strcmp(property
, "height"))
386 d
->height
= atof(command
);
387 else if(!a_strcmp(property
, "padding"))
390 if(d
->width
- tmp
< 3)
392 warn("progressbar widget needs: (width - padding) >= 3. Ignoring command.\n");
393 return WIDGET_ERROR_CUSTOM
;
401 return WIDGET_NOERROR
;
405 progressbar_new(Statusbar
*statusbar
, cfg_t
*config
)
410 int i
, phys_screen
= get_phys_screen(statusbar
->screen
);
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");
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")))
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");
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
]);
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
]);
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
]);
484 d
->bordercolor
[i
] = d
->fg
[i
];
489 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80