diff --git a/common/configopts.c b/common/configopts.c index baba8b8d9..344fc5c43 100644 --- a/common/configopts.c +++ b/common/configopts.c @@ -211,6 +211,7 @@ cfg_opt_t widget_progressbar_opts[] = CFG_INT((char *) "gap", 2, CFGF_NONE), CFG_INT((char *) "padding", 0, CFGF_NONE), CFG_FLOAT((char *) "height", 0.67, CFGF_NONE), + CFG_BOOL((char *) "vertical", cfg_false, CFGF_NONE), CFG_AWESOME_END() }; cfg_opt_t statusbar_opts[] = diff --git a/common/draw.c b/common/draw.c index d3b539c65..c027fce95 100644 --- a/common/draw.c +++ b/common/draw.c @@ -213,45 +213,39 @@ draw_text(DrawCtx *ctx, /** Setup color-source for cairo (gradient or mono) * \param ctx Draw context - * \param x x-offset of pattern start - * \param y y-offset of widget - * \param width pattern width - * \param color color to use at start (x) + * \param rect x,y to x+x_offset,y+y_offset + * \param color color to use at start (x,y) * \param pcolor_center color at 50% of width - * \param pcolor_end color at pattern start (x) + pattern width (width) + * \param pcolor_end color at pattern end (x + x_offset, y + y_offset) * \return pat pattern or NULL; needs to get cairo_pattern_destroy()'ed; */ static cairo_pattern_t * -draw_setup_cairo_color_source(DrawCtx *ctx, int x, int y, int width, +draw_setup_cairo_color_source(DrawCtx *ctx, Area rect, XColor *pcolor, XColor *pcolor_center, XColor *pcolor_end) { cairo_pattern_t *pat = NULL; - /* no need for a real pattern on the next two: */ + /* no need for a real pattern: */ if(!pcolor_end && !pcolor_center) cairo_set_source_rgb(ctx->cr, pcolor->red / 65535.0, pcolor->green / 65535.0, pcolor->blue / 65535.0); - else if(!pcolor && !pcolor_center) - cairo_set_source_rgb(ctx->cr, pcolor_end->red / 65535.0, pcolor_end->green / 65535.0, pcolor_end->blue / 65535.0); else { - pat = cairo_pattern_create_linear(x, y, x + width, y); + pat = cairo_pattern_create_linear(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); - /* use pcolor as pcolor_end (and vice versa) when one is not set */ - if(pcolor) - cairo_pattern_add_color_stop_rgb(pat, 0, pcolor->red / 65535.0, + /* pcolor is always set (so far in awesome) */ + cairo_pattern_add_color_stop_rgb(pat, 0, pcolor->red / 65535.0, pcolor->green / 65535.0, pcolor->blue / 65535.0); - else - cairo_pattern_add_color_stop_rgb(pat, 0, pcolor_end->red / 65535.0, - pcolor_end->green / 65535.0, pcolor_end->blue / 65535.0); + + if(pcolor_center) + cairo_pattern_add_color_stop_rgb(pat, 0.5, pcolor_center->red / 65535.0, + pcolor_center->green / 65535.0, pcolor_center->blue / 65535.0); + if(pcolor_end) cairo_pattern_add_color_stop_rgb(pat, 1, pcolor_end->red / 65535.0, pcolor_end->green / 65535.0, pcolor_end->blue / 65535.0); else cairo_pattern_add_color_stop_rgb(pat, 1, pcolor->red / 65535.0, pcolor->green / 65535.0, pcolor->blue / 65535.0); - if(pcolor_center) - cairo_pattern_add_color_stop_rgb(pat, 0.5, pcolor_center->red / 65535.0, - pcolor_center->green / 65535.0, pcolor_center->blue / 65535.0); cairo_set_source(ctx->cr, pat); } return pat; @@ -284,23 +278,22 @@ draw_rectangle(DrawCtx *ctx, Area geometry, Bool filled, XColor color) * \param ctx Draw context * \param geometry geometry * \param filled filled rectangle? - * \param pattern_start_x pattern start x coord + * \param pattern__x pattern start x coord * \param pattern_width pattern width * \param color color to use at start * \param pcolor_center color at 50% of width * \param pcolor_end color at pattern_start + pattern_width */ void -draw_rectangle_gradient(DrawCtx *ctx, Area geometry, Bool filled, int pattern_start_x, int pattern_width, - XColor *pcolor, XColor *pcolor_center, XColor *pcolor_end) +draw_rectangle_gradient(DrawCtx *ctx, Area geometry, Bool filled, + Area pattern_rect, XColor *pcolor, XColor *pcolor_center, XColor *pcolor_end) { cairo_pattern_t *pat; cairo_set_antialias(ctx->cr, CAIRO_ANTIALIAS_NONE); cairo_set_line_width(ctx->cr, 1.0); - pat = draw_setup_cairo_color_source(ctx, pattern_start_x, geometry.y, pattern_width, - pcolor, pcolor_center, pcolor_end); + pat = draw_setup_cairo_color_source(ctx, pattern_rect, pcolor, pcolor_center, pcolor_end); if(filled) { @@ -347,7 +340,13 @@ draw_graph(DrawCtx *ctx, int x, int y, int w, int *from, int *to, int cur_index, { int i; cairo_pattern_t *pat; - pat = draw_setup_cairo_color_source(ctx, x, y, w, pcolor, pcolor_center, pcolor_end); + Area rect; + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = 0; + + pat = draw_setup_cairo_color_source(ctx, rect, pcolor, pcolor_center, pcolor_end); i = -1; while(++i < w) @@ -385,7 +384,13 @@ draw_graph_line(DrawCtx *ctx, int x, int y, int w, int *to, int cur_index, int flag = 0; /* used to prevent drawing a line from 0 to 0 values */ cairo_pattern_t *pat; - pat = draw_setup_cairo_color_source(ctx, x, y, w, pcolor, pcolor_center, pcolor_end); + Area rect; + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = 0; + + pat = draw_setup_cairo_color_source(ctx, rect, pcolor, pcolor_center, pcolor_end); /* x-1 (on the border), paints *from* the last point (... not included itself) */ /* makes sense when you assume there is already some line drawn to it. */ diff --git a/common/draw.h b/common/draw.h index 4fa152e9c..eac47b2d8 100644 --- a/common/draw.h +++ b/common/draw.h @@ -96,7 +96,7 @@ void draw_context_delete(DrawCtx *); void draw_text(DrawCtx *, Area, Alignment, int, XftFont *, char *, int, XColor fg, XColor bg); void draw_rectangle(DrawCtx *, Area, Bool, XColor); -void draw_rectangle_gradient(DrawCtx *, Area, Bool, int, int, XColor *, XColor *, XColor *); +void draw_rectangle_gradient(DrawCtx *, Area, Bool, Area, XColor *, XColor *, XColor *); void draw_graph_setup(DrawCtx *); void draw_graph(DrawCtx *, int, int, int, int *, int *, int, XColor *, XColor *, XColor *); diff --git a/widgets/progressbar.c b/widgets/progressbar.c index 74c4f4346..cd40f163b 100644 --- a/widgets/progressbar.c +++ b/widgets/progressbar.c @@ -40,6 +40,8 @@ typedef struct int gap; /** reverse drawing */ Bool *reverse; + /** 90 Degree's turned */ + Bool vertical; /** Number of data_items (bars) */ int data_items; /** Height 0-1, where 1 is height of statusbar */ @@ -60,16 +62,14 @@ static int progressbar_draw(Widget *widget, DrawCtx *ctx, int offset, int used __attribute__ ((unused))) { - int i, width, pwidth, margin_top, pb_height, left_offset; - Area rectangle; + int i, pb_x, pb_y, pb_height, pb_width, pb_progress, pb_offset = 0; + Area rectangle, pattern_rect; Data *d = widget->data; if (!d->data_items) return 0; - width = d->width - 2 * d->padding; - if(!widget->user_supplied_x) widget->area.x = widget_calculate_offset(widget->statusbar->width, d->width, @@ -79,51 +79,158 @@ progressbar_draw(Widget *widget, DrawCtx *ctx, int offset, if(!widget->user_supplied_y) widget->area.y = 0; - margin_top = (int) (widget->statusbar->height * (1 - d->height)) / 2 + 0.5 + widget->area.y; - pb_height = (int) ((widget->statusbar->height * d->height - (d->gap * (d->data_items - 1))) / d->data_items + 0.5); - left_offset = widget->area.x + d->padding; - - for(i = 0; i < d->data_items; i++) + /* data for the first rectangle (data-bar) to draw */ + if(d->vertical) { - if(d->reverse[i]) - pwidth = (int)(((width - 2) * (100 - d->percent[i])) / 100); - else - pwidth = (int)(((width - 2) * d->percent[i]) / 100); + pb_width = (int) ((d->width - d->padding - (d->gap * (d->data_items - 1))) / d->data_items + 0.5); + pb_height = (int) (widget->statusbar->height * d->height); + pb_y = widget->area.y + (int)((widget->statusbar->height - pb_height) / 2 + 0.5); + } + else /* horizontal */ + { + pb_width = d->width - d->padding; + pb_height = (int) ((widget->statusbar->height * d->height - (d->gap * (d->data_items - 1))) / d->data_items + 0.5); + pb_y = widget->area.y + (int)((widget->statusbar->height - widget->statusbar->height * d->height) / 2 + 0.5); + } - rectangle.x = left_offset; - rectangle.y = margin_top; - rectangle.width = width; - rectangle.height = pb_height; + pb_x = widget->area.x + d->padding; - draw_rectangle(ctx, rectangle, False, d->bordercolor[i]); - - if(pwidth > 0) /* filled area */ + /* for a 'reversed' progressbar: + * 1. the full space gets the size of the formerly empty one + * 2. the pattern must be mirrored + * 3. the formerly 'empty' side gets drawed with fg colors, the 'full' with bg-color + * + * Might could be put into a single function (removing same/similar code) - feel free + */ + if(d->vertical) + { + for(i = 0; i < d->data_items; i++) { - rectangle.x = left_offset + 1; - rectangle.y = margin_top + 1; - rectangle.width = pwidth; - rectangle.height = pb_height - 2; - if(d->reverse[i]) - draw_rectangle(ctx, rectangle, True, d->bg[i]); - else - draw_rectangle_gradient(ctx, rectangle, True, left_offset + 1, width - 2, - &(d->fg[i]), d->pfg_center[i], d->pfg_end[i]); - } + /* border rectangle */ + rectangle.x = pb_x + pb_offset; + rectangle.y = pb_y; + rectangle.width = pb_width; + rectangle.height = pb_height; + draw_rectangle(ctx, rectangle, False, d->bordercolor[i]); - if(width - 2 - pwidth > 0) /* not filled area */ + /* new value/progress in px + pattern setup */ + if(!d->reverse[i]) + { + pb_progress = (int)(((pb_height - 2) * d->percent[i]) / 100 + 0.5); + /* bottom to top */ + pattern_rect.x = pb_x; + pattern_rect.y = pb_y + 1 + pb_height ; + pattern_rect.width = 0; + pattern_rect.height = -pb_height; + } + else + { + pb_progress = (int)(((pb_height - 2) * (100 - d->percent[i])) / 100 + 0.5); + /* top to bottom */ + pattern_rect.x = pb_x + 1; + pattern_rect.y = pb_y + 1; + pattern_rect.width = 0; + pattern_rect.height = pb_height; + } + + /* bottom part */ + if(pb_progress > 0) + { + rectangle.x = pb_x + pb_offset + 1; + rectangle.y = pb_y + 1 + (pb_height - 2) - pb_progress; + rectangle.width = pb_width - 2; + rectangle.height = pb_progress; + + /* fg color */ + if(!d->reverse[i]) + draw_rectangle_gradient(ctx, rectangle, True, pattern_rect, + &(d->fg[i]), d->pfg_center[i], d->pfg_end[i]); + else /*REV: bg */ + draw_rectangle(ctx, rectangle, True, d->bg[i]); + } + + /* top part */ + if((pb_height - 2) - pb_progress > 0) /* not filled area */ + { + rectangle.x = pb_x + 1 + pb_offset; + rectangle.y = pb_y + 1; + rectangle.width = pb_width - 2; + rectangle.height = pb_height - 2 - pb_progress; + + /* bg color */ + if(!d->reverse[i]) + draw_rectangle(ctx, rectangle, True, d->bg[i]); + else /* REV: bg */ + draw_rectangle_gradient(ctx, rectangle, True, pattern_rect, + &(d->fg[i]), d->pfg_center[i], d->pfg_end[i]); + } + pb_offset += pb_width + d->gap; + } + } + else /* a horizontal progressbar */ + { + for(i = 0; i < d->data_items; i++) { - rectangle.x = left_offset + 1 + pwidth; - rectangle.y = margin_top + 1; - rectangle.width = width - 2 - pwidth; - rectangle.height = pb_height - 2; - if(d->reverse[i]) - draw_rectangle_gradient(ctx, rectangle, True, left_offset + 1, width - 2, - d->pfg_end[i], d->pfg_center[i], &(d->fg[i])); - else - draw_rectangle(ctx, rectangle, True, d->bg[i]); - } + /* border rectangle */ + rectangle.x = pb_x; + rectangle.y = pb_y + pb_offset; + rectangle.width = pb_width; + rectangle.height = pb_height; + draw_rectangle(ctx, rectangle, False, d->bordercolor[i]); - margin_top += (pb_height + d->gap); + /* new value/progress in px + pattern setup */ + if(!d->reverse[i]) + { + pb_progress = (int)(((pb_width - 2) * d->percent[i]) / 100 + 0.5); + /* left to right */ + pattern_rect.x = pb_x + 1; + pattern_rect.y = pb_y + 1; + pattern_rect.width = pb_width; + pattern_rect.height = 0; + } + else + { + pb_progress = (int)(((pb_width - 2) * (100 - d->percent[i])) / 100 + 0.5); + /* REV: right to left */ + pattern_rect.x = pb_x + 1 + pb_width; + pattern_rect.y = pb_y + 1; + pattern_rect.width = -pb_width; + pattern_rect.height = 0; + } + + /* left part */ + if(pb_progress > 0) + { + rectangle.x = pb_x + 1; + rectangle.y = pb_y + 1 + pb_offset; + rectangle.width = pb_progress; + rectangle.height = pb_height - 2; + + /* fg color */ + if(!d->reverse[i]) + draw_rectangle_gradient(ctx, rectangle, True, pattern_rect, + &(d->fg[i]), d->pfg_center[i], d->pfg_end[i]); + else /* REV: bg */ + draw_rectangle(ctx, rectangle, True, d->bg[i]); + } + + /* right part */ + if(pb_width - 2 - pb_progress > 0) + { + rectangle.x = pb_x + 1 + pb_progress; + rectangle.y = pb_y + 1 + pb_offset; + rectangle.width = pb_width - 2 - pb_progress; + rectangle.height = pb_height - 2; + + /* bg color */ + if(!d->reverse[i]) + draw_rectangle(ctx, rectangle, True, d->bg[i]); + else /* REV: fg */ + draw_rectangle_gradient(ctx, rectangle, True, pattern_rect, + &(d->fg[i]), d->pfg_center[i], d->pfg_end[i]); + } + pb_offset += pb_height + d->gap; + } } widget->area.width = d->width; @@ -319,6 +426,9 @@ progressbar_new(Statusbar *statusbar, cfg_t *config) d->height = cfg_getfloat(config, "height"); d->gap = cfg_getint(config, "gap"); + d->padding = cfg_getint(config, "padding"); + if(!(d->vertical = cfg_getbool(config, "vertical"))) + d->vertical = False; w->alignment = draw_get_align(cfg_getstr(config, "align"));