2 * progressbar.c - progressbar 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.
25 #include "common/tokenize.h"
27 /** Progressbar bar data structure */
30 /** Title of the data/bar */
32 /** These or lower values won't fill the bar at all*/
34 /** These or higher values fill the bar fully */
36 /** Pointer to value */
38 /** Reverse filling */
40 /** Foreground color */
42 /** Foreground color of turned-off ticks */
44 /** Foreground color when bar is half-full */
46 /** Foreground color when bar is full */
48 /** Background color */
55 * \param bar The bar to annihilate.
58 bar_delete(bar_t
*bar
)
60 p_delete(&bar
->title
);
63 DO_ARRAY(bar_t
, bar
, bar_delete
)
65 /** Progressbar private data structure */
68 /** Width of the data_items */
70 /** Pixel between data items (bars) */
72 /** Border width in pixels */
74 /** Padding between border and ticks/bar */
76 /** Gap/distance between the individual ticks */
78 /** Total number of ticks */
80 /** 90 Degree's turned */
82 /** Height 0-1, where 1.0 is height of bar */
88 /** Add a new bar to the progressbar private data structure.
89 * \param bars The bar array.
90 * \param title The bar title.
91 * \return The new bar.
94 progressbar_bar_add(bar_array_t
*bars
, const char *title
)
100 bar
.title
= a_strdup(title
);
101 bar
.max_value
= 100.0;
103 xcolor_to_color(&globalconf
.colors
.fg
, &bar
.fg
);
104 xcolor_to_color(&globalconf
.colors
.bg
, &bar
.bg
);
105 xcolor_to_color(&globalconf
.colors
.bg
, &bar
.fg_off
);
106 xcolor_to_color(&globalconf
.colors
.fg
, &bar
.border_color
);
108 /* append the bar in the list */
109 bar_array_append(bars
, bar
);
111 return &bars
->tab
[bars
->len
- 1];
114 /** Get the bar, and create one if it does not exist.
115 * \param bars The bar array.
116 * \param title The bar title.
117 * \return A maybe new bar.
120 progressbar_bar_get(bar_array_t
*bars
, const char *title
)
124 /* check if this section is defined already */
125 for(int j
= 0; j
< bars
->len
; j
++)
128 if(!a_strcmp(title
, bar
->title
))
132 /* no bar found -> create one */
133 return progressbar_bar_add(bars
, title
);
137 progressbar_geometry(widget_t
*widget
, int screen
)
140 progressbar_data_t
*d
= widget
->data
;
145 int pb_width
= (int) ((d
->width
- 2 * (d
->border_width
+ d
->border_padding
) * d
->bars
.len
146 - d
->gap
* (d
->bars
.len
- 1)) / d
->bars
.len
);
147 geometry
.width
= d
->bars
.len
* (pb_width
+ 2 * (d
->border_width
+ d
->border_padding
)
152 int pb_width
= d
->width
- 2 * (d
->border_width
+ d
->border_padding
);
153 if(d
->ticks_count
&& d
->ticks_gap
)
155 int unit
= (pb_width
+ d
->ticks_gap
) / d
->ticks_count
;
156 pb_width
= unit
* d
->ticks_count
- d
->ticks_gap
; /* rounded to match ticks... */
158 geometry
.width
= pb_width
+ 2 * (d
->border_width
+ d
->border_padding
);
160 geometry
.height
= geometry
.width
;
162 geometry
.x
= geometry
.y
= 0;
168 progressbar_extents(lua_State
*L
, widget_t
*widget
)
170 return progressbar_geometry(widget
, 0);
173 /** Draw a progressbar.
174 * \param ctx The draw context.
175 * \param w The widget node we're drawing for.
176 * \param offset Offset to draw at.
177 * \param used Space already used.
178 * \param object The object pointer we're drawing onto.
179 * \return The width used.
182 progressbar_draw(widget_t
*widget
, draw_context_t
*ctx
, area_t geometry
, wibox_t
*p
)
184 /* pb_.. values points to the widget inside a potential border */
185 int values_ticks
, pb_x
, pb_y
, pb_height
, pb_width
, pb_progress
, pb_offset
;
186 int unit
= 0; /* tick + gap */
188 vector_t color_gradient
;
189 progressbar_data_t
*d
= widget
->data
;
194 /* for a 'reversed' progressbar:
196 * 1. the full space gets the size of the formerly empty one
197 * 2. the pattern must be mirrored
198 * 3. the formerly 'empty' side gets drawed with fg colors, the 'full' with bg-color
201 * 1. round the values to a full tick accordingly
202 * 2. finally draw the gaps
205 pb_x
= geometry
.x
+ d
->border_width
+ d
->border_padding
;
210 pb_width
= (int) ((d
->width
- 2 * (d
->border_width
+ d
->border_padding
) * d
->bars
.len
211 - d
->gap
* (d
->bars
.len
- 1)) / d
->bars
.len
);
213 /** \todo maybe prevent to calculate that stuff below over and over again
214 * (->use static-values) */
215 pb_height
= (int) (ctx
->height
* d
->height
+ 0.5)
216 - 2 * (d
->border_width
+ d
->border_padding
);
217 if(d
->ticks_count
&& d
->ticks_gap
)
219 /* '+ d->ticks_gap' because a unit includes a ticks + ticks_gap */
220 unit
= (pb_height
+ d
->ticks_gap
) / d
->ticks_count
;
221 pb_height
= unit
* d
->ticks_count
- d
->ticks_gap
;
224 pb_y
= geometry
.y
+ ((int) (ctx
->height
* (1 - d
->height
)) / 2)
225 + d
->border_width
+ d
->border_padding
;
227 for(int i
= 0; i
< d
->bars
.len
; i
++)
229 bar_t
*bar
= &d
->bars
.tab
[i
];
231 if(d
->ticks_count
&& d
->ticks_gap
)
233 values_ticks
= (int)(d
->ticks_count
* (bar
->value
- bar
->min_value
)
234 / (bar
->max_value
- bar
->min_value
) + 0.5);
236 pb_progress
= values_ticks
* unit
- d
->ticks_gap
;
241 /* e.g.: min = 50; max = 56; 53 should show 50% graph
242 * (53(val) - 50(min) / (56(max) - 50(min) = 3 / 5 = 0.5 = 50%
243 * round that ( + 0.5 and (int)) and finally multiply with height
245 pb_progress
= (int) (pb_height
* (bar
->value
- bar
->min_value
)
246 / (bar
->max_value
- bar
->min_value
) + 0.5);
250 /* border rectangle */
251 rectangle
.x
= pb_x
+ pb_offset
- d
->border_width
- d
->border_padding
;
252 rectangle
.y
= pb_y
- d
->border_width
- d
->border_padding
;
253 rectangle
.width
= pb_width
+ 2 * (d
->border_padding
+ d
->border_width
);
254 rectangle
.height
= pb_height
+ 2 * (d
->border_padding
+ d
->border_width
);
256 if(d
->border_padding
)
257 draw_rectangle(ctx
, rectangle
, 1.0, true, &bar
->bg
);
258 draw_rectangle(ctx
, rectangle
, d
->border_width
, false, &bar
->border_color
);
261 color_gradient
.x
= pb_x
;
262 color_gradient
.x_offset
= 0;
263 color_gradient
.y
= pb_y
;
265 /* new value/progress in px + pattern setup */
268 /* invert: top with bottom part */
269 pb_progress
= pb_height
- pb_progress
;
270 color_gradient
.y_offset
= pb_height
;
275 color_gradient
.y
+= pb_height
;
276 color_gradient
.y_offset
= - pb_height
;
282 rectangle
.x
= pb_x
+ pb_offset
;
283 rectangle
.y
= pb_y
+ pb_height
- pb_progress
;
284 rectangle
.width
= pb_width
;
285 rectangle
.height
= pb_progress
;
289 draw_rectangle(ctx
, rectangle
, 1.0, true, &bar
->fg_off
);
291 draw_rectangle_gradient(ctx
, rectangle
, 1.0, true, color_gradient
,
292 &bar
->fg
, &bar
->fg_center
, &bar
->fg_end
);
296 if(pb_height
- pb_progress
> 0) /* not filled area */
298 rectangle
.x
= pb_x
+ pb_offset
;
300 rectangle
.width
= pb_width
;
301 rectangle
.height
= pb_height
- pb_progress
;
305 draw_rectangle_gradient(ctx
, rectangle
, 1.0, true, color_gradient
,
306 &bar
->fg
, &bar
->fg_center
, &bar
->fg_end
);
308 draw_rectangle(ctx
, rectangle
, 1.0, true, &bar
->fg_off
);
310 /* draw gaps TODO: improve e.g all in one */
311 if(d
->ticks_count
&& d
->ticks_gap
)
313 rectangle
.width
= pb_width
;
314 rectangle
.height
= d
->ticks_gap
;
315 rectangle
.x
= pb_x
+ pb_offset
;
316 for(rectangle
.y
= pb_y
+ (unit
- d
->ticks_gap
);
317 pb_y
+ pb_height
- d
->ticks_gap
>= rectangle
.y
;
319 draw_rectangle(ctx
, rectangle
, 1.0, true, &bar
->bg
);
321 pb_offset
+= pb_width
+ d
->gap
+ 2 * (d
->border_width
+ d
->border_padding
);
324 else /* a horizontal progressbar */
326 pb_width
= d
->width
- 2 * (d
->border_width
+ d
->border_padding
);
328 if(d
->ticks_count
&& d
->ticks_gap
)
330 unit
= (pb_width
+ d
->ticks_gap
) / d
->ticks_count
;
331 pb_width
= unit
* d
->ticks_count
- d
->ticks_gap
; /* rounded to match ticks... */
334 pb_height
= (int) ((ctx
->height
* d
->height
335 - d
->bars
.len
* 2 * (d
->border_width
+ d
->border_padding
)
336 - (d
->gap
* (d
->bars
.len
- 1))) / d
->bars
.len
+ 0.5);
337 pb_y
= geometry
.y
+ ((int) (ctx
->height
* (1 - d
->height
)) / 2)
338 + d
->border_width
+ d
->border_padding
;
340 for(int i
= 0; i
< d
->bars
.len
; i
++)
342 bar_t
*bar
= &d
->bars
.tab
[i
];
344 if(d
->ticks_count
&& d
->ticks_gap
)
346 /* +0.5 rounds up ticks -> turn on a tick when half of it is reached */
347 values_ticks
= (int)(d
->ticks_count
* (bar
->value
- bar
->min_value
)
348 / (bar
->max_value
- bar
->min_value
) + 0.5);
350 pb_progress
= values_ticks
* unit
- d
->ticks_gap
;
355 pb_progress
= (int) (pb_width
* (bar
->value
- bar
->min_value
)
356 / (bar
->max_value
- bar
->min_value
) + 0.5);
360 /* border rectangle */
361 rectangle
.x
= pb_x
- d
->border_width
- d
->border_padding
;
362 rectangle
.y
= pb_y
+ pb_offset
- d
->border_width
- d
->border_padding
;
363 rectangle
.width
= pb_width
+ 2 * (d
->border_padding
+ d
->border_width
);
364 rectangle
.height
= pb_height
+ 2 * (d
->border_padding
+ d
->border_width
);
366 if(d
->border_padding
)
367 draw_rectangle(ctx
, rectangle
, 1.0, true, &bar
->bg
);
368 draw_rectangle(ctx
, rectangle
, d
->border_width
, false, &bar
->border_color
);
371 color_gradient
.y
= pb_y
;
372 color_gradient
.y_offset
= 0;
373 color_gradient
.x
= pb_x
;
375 /* new value/progress in px + pattern setup */
378 /* reverse: right to left */
379 pb_progress
= pb_width
- pb_progress
;
380 color_gradient
.x
+= pb_width
;
381 color_gradient
.x_offset
= - pb_width
;
385 color_gradient
.x_offset
= pb_width
;
391 rectangle
.y
= pb_y
+ pb_offset
;
392 rectangle
.width
= pb_progress
;
393 rectangle
.height
= pb_height
;
397 draw_rectangle(ctx
, rectangle
, 1.0, true, &bar
->fg_off
);
399 draw_rectangle_gradient(ctx
, rectangle
, 1.0, true, color_gradient
,
400 &bar
->fg
, &bar
->fg_center
, &bar
->fg_end
);
404 if(pb_width
- pb_progress
> 0)
406 rectangle
.x
= pb_x
+ pb_progress
;
407 rectangle
.y
= pb_y
+ pb_offset
;
408 rectangle
.width
= pb_width
- pb_progress
;
409 rectangle
.height
= pb_height
;
413 draw_rectangle_gradient(ctx
, rectangle
, 1.0, true, color_gradient
,
414 &bar
->fg
, &bar
->fg_center
, &bar
->fg_end
);
416 draw_rectangle(ctx
, rectangle
, 1.0, true, &bar
->fg_off
);
418 /* draw gaps TODO: improve e.g all in one */
419 if(d
->ticks_count
&& d
->ticks_gap
)
421 rectangle
.width
= d
->ticks_gap
;
422 rectangle
.height
= pb_height
;
423 rectangle
.y
= pb_y
+ pb_offset
;
424 for(rectangle
.x
= pb_x
+ (unit
- d
->ticks_gap
);
425 pb_x
+ pb_width
- d
->ticks_gap
>= rectangle
.x
;
427 draw_rectangle(ctx
, rectangle
, 1.0, true, &bar
->bg
);
430 pb_offset
+= pb_height
+ d
->gap
+ 2 * (d
->border_width
+ d
->border_padding
);
435 /** Set various progressbar bars properties:
436 * \param L The Lua VM state.
437 * \return The number of elements pushed on the stack.
440 * \lparam A bar name.
441 * \lparam A table with keys as properties names.
444 luaA_progressbar_bar_properties_set(lua_State
*L
)
447 widget_t
*widget
= luaA_checkudata(L
, 1, &widget_class
);
448 const char *buf
, *title
= luaL_checkstring(L
, 2);
450 progressbar_data_t
*d
= widget
->data
;
451 color_init_cookie_t reqs
[6];
452 int i
, reqs_nbr
= -1;
454 luaA_checktable(L
, 3);
456 bar
= progressbar_bar_get(&d
->bars
, title
);
458 if((buf
= luaA_getopt_lstring(L
, 3, "fg", NULL
, &len
)))
459 reqs
[++reqs_nbr
] = color_init_unchecked(&bar
->fg
, buf
, len
);
461 if((buf
= luaA_getopt_lstring(L
, 3, "fg_off", NULL
, &len
)))
462 reqs
[++reqs_nbr
] = color_init_unchecked(&bar
->fg_off
, buf
, len
);
464 if((buf
= luaA_getopt_lstring(L
, 3, "bg", NULL
, &len
)))
465 reqs
[++reqs_nbr
] = color_init_unchecked(&bar
->bg
, buf
, len
);
467 if((buf
= luaA_getopt_lstring(L
, 3, "border_color", NULL
, &len
)))
468 reqs
[++reqs_nbr
] = color_init_unchecked(&bar
->border_color
, buf
, len
);
470 if((buf
= luaA_getopt_lstring(L
, 3, "fg_center", NULL
, &len
)))
471 reqs
[++reqs_nbr
] = color_init_unchecked(&bar
->fg_center
, buf
, len
);
473 if((buf
= luaA_getopt_lstring(L
, 3, "fg_end", NULL
, &len
)))
474 reqs
[++reqs_nbr
] = color_init_unchecked(&bar
->fg_end
, buf
, len
);
476 bar
->min_value
= luaA_getopt_number(L
, 3, "min_value", bar
->min_value
);
477 /* hack to prevent max_value beeing less than min_value
478 * and also preventing a division by zero when both are equal */
479 if(bar
->max_value
<= bar
->min_value
)
480 bar
->max_value
= bar
->max_value
+ 0.0001;
481 /* force a actual value into the newly possible range */
482 if(bar
->value
< bar
->min_value
)
483 bar
->value
= bar
->min_value
;
485 bar
->max_value
= luaA_getopt_number(L
, 3, "max_value", bar
->max_value
);
486 if(bar
->min_value
>= bar
->max_value
)
487 bar
->min_value
= bar
->max_value
- 0.0001;
488 if(bar
->value
> bar
->max_value
)
489 bar
->value
= bar
->max_value
;
491 bar
->reverse
= luaA_getopt_boolean(L
, 3, "reverse", bar
->reverse
);
493 for(i
= 0; i
<= reqs_nbr
; i
++)
494 color_init_reply(reqs
[i
]);
496 widget_invalidate_bywidget(widget
);
501 /** Add a value to a progressbar bar.
502 * \param L The Lua VM state.
503 * \return The number of elements pushed on the stack.
506 * \lparam A bar name.
507 * \lparam A data value.
510 luaA_progressbar_bar_data_add(lua_State
*L
)
512 widget_t
*widget
= luaA_checkudata(L
, 1, &widget_class
);
513 const char *title
= luaL_checkstring(L
, 2);
514 progressbar_data_t
*d
= widget
->data
;
517 bar
= progressbar_bar_get(&d
->bars
, title
);
519 bar
->value
= luaL_checknumber(L
, 3);
520 bar
->value
= MAX(bar
->min_value
, MIN(bar
->max_value
, bar
->value
));
522 widget_invalidate_bywidget(widget
);
527 /** Progressbar widget.
528 * DEPRECATED, see awful.widget.progressbar.
529 * \param L The Lua VM state.
530 * \param token The key token.
531 * \return The number of elements pushed on the stack.
533 * \lfield bar_properties_set Set the properties of a bar.
534 * \lfield bar_data_add Add data to a bar.
535 * \lfield gap Gap betweens bars.
536 * \lfield ticks_gap Gap between ticks.
537 * \lfield ticks_count Number of ticks.
538 * \lfield border_padding Border padding.
539 * \lfield border_width Border width.
540 * \lfield width Bars width.
541 * \lfield height Bars height.
542 * \lfield vertical True: draw bar vertically, false: horizontally.
545 luaA_progressbar_index(lua_State
*L
, awesome_token_t token
)
547 widget_t
*widget
= luaA_checkudata(L
, 1, &widget_class
);
548 progressbar_data_t
*d
= widget
->data
;
552 case A_TK_BAR_PROPERTIES_SET
:
553 lua_pushcfunction(L
, luaA_progressbar_bar_properties_set
);
555 case A_TK_BAR_DATA_ADD
:
556 lua_pushcfunction(L
, luaA_progressbar_bar_data_add
);
559 lua_pushnumber(L
, d
->gap
);
562 lua_pushnumber(L
, d
->ticks_gap
);
564 case A_TK_TICKS_COUNT
:
565 lua_pushnumber(L
, d
->ticks_count
);
567 case A_TK_BORDER_PADDING
:
568 lua_pushnumber(L
, d
->border_padding
);
570 case A_TK_BORDER_WIDTH
:
571 lua_pushnumber(L
, d
->border_width
);
574 lua_pushnumber(L
, d
->width
);
577 lua_pushnumber(L
, d
->height
);
580 lua_pushboolean(L
, d
->vertical
);
589 /** Newindex function for progressbar.
590 * \param L The Lua VM state.
591 * \param token The key token.
592 * \return The number of elements pushed on the stack.
595 luaA_progressbar_newindex(lua_State
*L
, awesome_token_t token
)
597 widget_t
*widget
= luaA_checkudata(L
, 1, &widget_class
);
598 progressbar_data_t
*d
= widget
->data
;
603 d
->gap
= luaL_checknumber(L
, 3);
605 case A_TK_TICKS_COUNT
:
606 d
->ticks_count
= luaL_checknumber(L
, 3);
609 d
->ticks_gap
= luaL_checknumber(L
, 3);
611 case A_TK_BORDER_PADDING
:
612 d
->border_padding
= luaL_checknumber(L
, 3);
614 case A_TK_BORDER_WIDTH
:
615 d
->border_width
= luaL_checknumber(L
, 3);
618 d
->width
= luaL_checknumber(L
, 3);
621 d
->height
= luaL_checknumber(L
, 3);
624 d
->vertical
= luaA_checkboolean(L
, 3);
630 widget_invalidate_bywidget(widget
);
635 /** Destroy a progressbar.
636 * \param widget The widget to kill.
639 progressbar_destructor(widget_t
*widget
)
641 progressbar_data_t
*d
= widget
->data
;
643 bar_array_wipe(&d
->bars
);
647 /** Create a new progressbar.
648 * \param w The widget to initialize.
649 * \return A brand new progressbar.
652 widget_progressbar(widget_t
*w
)
654 luaA_deprecate(globalconf
.L
, "awful.widget.progressbar");
655 w
->draw
= progressbar_draw
;
656 w
->index
= luaA_progressbar_index
;
657 w
->newindex
= luaA_progressbar_newindex
;
658 w
->destructor
= progressbar_destructor
;
659 w
->extents
= progressbar_extents
;
661 progressbar_data_t
*d
= w
->data
= p_new(progressbar_data_t
, 1);
673 /* This is used for building documentation. */
674 static const struct luaL_reg awesome_progressbar_meta
[] __attribute__ ((unused
)) =
676 { "bar_properties_set", luaA_progressbar_bar_properties_set
},
677 { "bar_data_add", luaA_progressbar_bar_data_add
},
680 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80