diff --git a/common/configopts.c b/common/configopts.c index 0f9f3321e..fa1f2b1a6 100644 --- a/common/configopts.c +++ b/common/configopts.c @@ -134,6 +134,8 @@ cfg_opt_t widget_graph_data_opts[] = CFG_FLOAT((char *) "max", 100.0f, CFGF_NONE), CFG_BOOL((char *) "scale", cfg_false, CFGF_NONE), CFG_STR((char *) "fg", (char *) NULL, CFGF_NONE), + CFG_STR((char *) "fg_middle", (char *) NULL, CFGF_NONE), + CFG_STR((char *) "fg_end", (char *) NULL, CFGF_NONE), CFG_STR((char *) "style", (char *) "bottom", CFGF_NONE), CFG_END() }; diff --git a/common/draw.c b/common/draw.c index cf91fad15..1d4a691ed 100644 --- a/common/draw.c +++ b/common/draw.c @@ -182,6 +182,47 @@ draw_text(DrawCtx *ctx, cairo_font_face_destroy(font_face); } +/** Setup color-source for cairo (gradient or mono) + * \param ctx Draw context + * \param x x-offset of widget + * \param y y-offset of widget + * \param width width in pixels + * \param color color to use from 0% + * \param pcolor_middle color at 50% of width + * \param pcolor_end color at 100% of width + * \return pat pattern or NULL; needs to get cairo_pattern_destroy()'ed; + */ +cairo_pattern_t * +setup_cairo_color_source(DrawCtx *ctx, int x, int y, int width, + XColor color, XColor *pcolor_middle, XColor *pcolor_end) +{ + cairo_pattern_t *pat; + + if(pcolor_middle || pcolor_end) /* draw a gradient */ + { + pat = cairo_pattern_create_linear(x, y, x + width, y); + + cairo_pattern_add_color_stop_rgb(pat, 0, color.red / 65535.0, + color.green / 65535.0, color.blue / 65535.0); + if(pcolor_middle) + cairo_pattern_add_color_stop_rgb(pat, 0.5, pcolor_middle->red / 65535.0, + pcolor_middle->green / 65535.0, pcolor_middle->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, color.red / 65535.0, + color.green / 65535.0, color.blue / 65535.0); + cairo_set_source(ctx->cr, pat); + return pat; + } + else /* no gradient */ + { + cairo_set_source_rgb(ctx->cr, color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0); + return NULL; + } +} + /** Draw rectangle * \param ctx Draw context * \param geometry geometry @@ -205,39 +246,26 @@ draw_rectangle(DrawCtx *ctx, Area geometry, Bool filled, XColor color) cairo_stroke(ctx->cr); } } - /** Draw rectangle with gradient colors * \param ctx Draw context * \param geometry geometry * \param fullwidth width of full bar in pixels * \param filled filled rectangle? * \param color color to use from 0% - * \param color_half color at 50% - * \param color_full color at 100% + * \param pcolor_half color at 50% + * \param pcolor_full color at 100% */ void draw_rectangle_gradient(DrawCtx *ctx, Area geometry, int fullwidth, Bool filled, - XColor color, XColor * color_half, XColor * color_full) + XColor color, XColor *pcolor_half, XColor *pcolor_full) { cairo_pattern_t *pat; cairo_set_antialias(ctx->cr, CAIRO_ANTIALIAS_NONE); cairo_set_line_width(ctx->cr, 1.0); - pat = cairo_pattern_create_linear(geometry.x, geometry.y, geometry.x + fullwidth, geometry.y); - cairo_pattern_add_color_stop_rgb(pat, 0, color.red / 65535.0, - color.green / 65535.0, color.blue / 65535.0); - if(color_half) - cairo_pattern_add_color_stop_rgb(pat, 0.5, color_half->red / 65535.0, - color_half->green / 65535.0, color_half->blue / 65535.0); - if(color_full) - cairo_pattern_add_color_stop_rgb(pat, 1, color_full->red / 65535.0, - color_full->green / 65535.0, color_full->blue / 65535.0); - else - cairo_pattern_add_color_stop_rgb(pat, 1, color.red / 65535.0, - color.green / 65535.0, color.blue / 65535.0); - - cairo_set_source(ctx->cr, pat); + pat = setup_cairo_color_source(ctx, geometry.x, geometry.y, fullwidth, + color, pcolor_half, pcolor_full); if(filled) { @@ -250,10 +278,13 @@ draw_rectangle_gradient(DrawCtx *ctx, Area geometry, int fullwidth, Bool filled, cairo_stroke(ctx->cr); } - cairo_pattern_destroy(pat); + if(pat) + cairo_pattern_destroy(pat); } -/* draw_graph functions */ +/** Setup some cairo-things for drawing a graph + * \param ctx Draw context + */ void draw_graph_setup(DrawCtx *ctx) { @@ -262,16 +293,25 @@ draw_graph_setup(DrawCtx *ctx) /* without it, it can draw over the path on sharp angles (...too long lines) */ cairo_set_line_join (ctx->cr, CAIRO_LINE_JOIN_ROUND); } - -/* draws a graph; it takes the line-lengths from *from and *to. It cycles - * backwards through those arrays (what have the length of w), beginning at - * position cur_index, until cur_index is reached again (wrapped around). */ +/** Draw a graph + * \param ctx Draw context + * \param x x-offset of widget + * \param y y-offset of widget + * \param w width in pixels + * \param from array of starting-point offsets to draw a graph-lines + * \param to array of end-point offsets to draw a graph-lines + * \param cur_index current position in data-array (cycles around) + * \param color color to use from 0% + * \param pcolor_middle color at 50% + * \param pcolor_end color at 100% + */ void -draw_graph(DrawCtx *ctx, int x, int y, int w, int *from, int *to, int cur_index, XColor color) +draw_graph(DrawCtx *ctx, int x, int y, int w, int *from, int *to, int cur_index, + XColor color, XColor *pcolor_middle, XColor *pcolor_end) { int i; - - cairo_set_source_rgb(ctx->cr, color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0); + cairo_pattern_t *pat; + pat = setup_cairo_color_source(ctx, x, y, w, color, pcolor_middle, pcolor_end); i = -1; while(++i < w) @@ -285,13 +325,30 @@ draw_graph(DrawCtx *ctx, int x, int y, int w, int *from, int *to, int cur_index, } cairo_stroke(ctx->cr); + + if(pat) + cairo_pattern_destroy(pat); } +/** Draw a line into a graph-widget + * \param ctx Draw context + * \param x x-offset of widget + * \param y y-offset of widget + * \param w width in pixels + * \param to array of offsets to draw the line through... + * \param cur_index current position in data-array (cycles around) + * \param color color to use from 0% + * \param pcolor_middle color at 50% + * \param pcolor_end color at 100% + */ void -draw_graph_line(DrawCtx *ctx, int x, int y, int w, int *to, int cur_index, XColor color) +draw_graph_line(DrawCtx *ctx, int x, int y, int w, int *to, int cur_index, + XColor color, XColor *pcolor_middle, XColor *pcolor_end) { int i; int flag = 0; /* used to prevent drawing a line from 0 to 0 values */ - cairo_set_source_rgb(ctx->cr, color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0); + cairo_pattern_t *pat; + + pat = setup_cairo_color_source(ctx, x, y, w, color, pcolor_middle, 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. */ @@ -320,6 +377,9 @@ draw_graph_line(DrawCtx *ctx, int x, int y, int w, int *to, int cur_index, XColo x++; } cairo_stroke(ctx->cr); + + if(pat) + cairo_pattern_destroy(pat); } void diff --git a/common/draw.h b/common/draw.h index a5df5c185..695518f6f 100644 --- a/common/draw.h +++ b/common/draw.h @@ -97,10 +97,10 @@ void draw_text(DrawCtx *, Area, Alignment, int, XftFont *, char *, XColor fg, XC void draw_rectangle(DrawCtx *, Area, Bool, XColor); void draw_rectangle_gradient(DrawCtx *, Area, int, Bool, XColor, XColor *, XColor *); +cairo_pattern_t * setup_cairo_color_source(DrawCtx *, int, int, int, XColor, XColor *, XColor *); void draw_graph_setup(DrawCtx *); -void draw_graph(DrawCtx *, int, int, int, int *, int *, int, XColor); -void draw_graph_line(DrawCtx *, int, int, int, int *, int, XColor); - +void draw_graph(DrawCtx *, int, int, int, int *, int *, int, XColor, XColor *, XColor *); +void draw_graph_line(DrawCtx *, int, int, int, int *, int, XColor, XColor *, XColor *); void draw_circle(DrawCtx *, int, int, int, Bool, XColor); void draw_image(DrawCtx *, int, int, int, const char *); void draw_image_from_argb_data(DrawCtx *, int, int, int, int, int, unsigned char *); diff --git a/widgets/graph.c b/widgets/graph.c index da213a329..e9c01c932 100644 --- a/widgets/graph.c +++ b/widgets/graph.c @@ -30,38 +30,44 @@ extern AwesomeConf globalconf; typedef struct { /* general layout */ - float *max; /* Represents a full graph */ - int width; /* Width of the widget */ - float height; /* Height of graph (0-1, where 1 is height of statusbar) */ - int box_height; /* Height of the innerbox in pixels */ - int padding_left; /* Left padding */ - int size; /* Size of lines-array (also innerbox-lenght) */ - XColor bg; /* Background color */ - XColor bordercolor; /* Border color */ + float *max; /** Represents a full graph */ + int width; /** Width of the widget */ + float height; /** Height of graph (0-1; 1 = height of statusbar) */ + int box_height; /** Height of the innerbox in pixels */ + int padding_left; /** Left padding */ + int size; /** Size of lines-array (also innerbox-lenght) */ + XColor bg; /** Background color */ + XColor bordercolor; /** Border color */ /* markers... */ - int index; /* Index of current (new) value */ - int *max_index; /* Index of the actual maximum value */ - float *current_max; /* Pointer to current maximum value itself */ + int index; /** Index of current (new) value */ + int *max_index; /** Index of the actual maximum value */ + float *current_max; /** Pointer to current maximum value itself */ /* all data is stored here */ - int data_items; /* Number of data-input items */ - int **lines; /* Keeps the calculated values (line-length); */ - float **values; /* Actual values */ + int data_items; /** Number of data-input items */ + int **lines; /** Keeps the calculated values (line-length); */ + float **values; /** Actual values */ /* additional data + a pointer to **lines accordingly */ - int **fillbottom; /* datatypes holder (same as some **lines pointer) */ - int fillbottom_total; /* total of them */ - XColor *fillbottom_color; /* color of them */ - int **filltop; /* datatypes holder */ - int filltop_total; /* total of them */ - XColor *filltop_color; /* color of them */ - int **drawline; /* datatypes holder */ - int drawline_total; /* total of them */ - XColor *drawline_color; /* color of them */ + int **fillbottom; /** Datatypes holder (data equal to **lines) */ + int fillbottom_total; /** Total of them */ + XColor *fillbottom_color; /** Color of them */ + XColor **fillbottom_pcolor_middle; /** Color at middle of graph */ + XColor **fillbottom_pcolor_end; /** Color at end of graph */ + int **filltop; /** Datatypes holder */ + int filltop_total; /** Total of them */ + XColor *filltop_color; /** Color of them */ + XColor **filltop_pcolor_middle; /** Color at middle of graph */ + XColor **filltop_pcolor_end; /** Color at end of graph */ + int **drawline; /** Datatypes holder */ + int drawline_total; /** Total of them */ + XColor *drawline_color; /** Color of them */ + XColor **drawline_pcolor_middle; /** Color at middle of graph */ + XColor **drawline_pcolor_end; /** Color at end of graph */ - int *draw_from; /* Preparation/tmp array for draw_graph(); */ - int *draw_to; /* Preparation/tmp array for draw_graph(); */ + int *draw_from; /** Preparation/tmp array for draw_graph(); */ + int *draw_to; /** Preparation/tmp array for draw_graph(); */ } Data; @@ -124,7 +130,7 @@ graph_draw(Widget *widget, DrawCtx *ctx, int offset, draw_graph(ctx, left_offset + 2, margin_top + d->box_height + 1, d->size, d->draw_from, d->draw_to, d->index, - d->filltop_color[z]); + d->filltop_color[z], d->filltop_pcolor_middle[z], d->filltop_pcolor_end[z]); } /* draw style = bottom */ @@ -146,7 +152,7 @@ graph_draw(Widget *widget, DrawCtx *ctx, int offset, draw_graph(ctx, left_offset + 2, margin_top + d->box_height + 1, d->size, d->draw_from, d->fillbottom[z], d->index, - d->fillbottom_color[z]); + d->fillbottom_color[z], d->fillbottom_pcolor_middle[z], d->fillbottom_pcolor_end[z]); } /* draw style = line */ @@ -155,7 +161,7 @@ graph_draw(Widget *widget, DrawCtx *ctx, int offset, draw_graph_line(ctx, left_offset + 2, margin_top + d->box_height + 1, d->size, d->drawline[z], d->index, - d->drawline_color[z]); + d->drawline_color[z], d->drawline_pcolor_middle[z], d->drawline_pcolor_end[z]); } widget->area.width = d->width; @@ -236,6 +242,8 @@ graph_new(Statusbar *statusbar, cfg_t *config) int i; char *type; XColor tmp_color; + XColor *ptmp_color_middle; + XColor *ptmp_color_end; w = p_new(Widget, 1); widget_common_new(w, statusbar, config); @@ -272,18 +280,24 @@ graph_new(Statusbar *statusbar, cfg_t *config) d->lines = p_new(int *, d->data_items); d->filltop_color = p_new(XColor, d->data_items); + d->filltop_pcolor_middle = p_new(XColor *, d->data_items); + d->filltop_pcolor_end = p_new(XColor *, d->data_items); d->fillbottom_color = p_new(XColor, d->data_items); + d->fillbottom_pcolor_middle = p_new(XColor *, d->data_items); + d->fillbottom_pcolor_end = p_new(XColor *, d->data_items); d->drawline_color = p_new(XColor, d->data_items); + d->drawline_pcolor_middle = p_new(XColor *, d->data_items); + d->drawline_pcolor_end = p_new(XColor *, d->data_items); d->max_index = p_new(int, d->data_items); d->current_max = p_new(float, d->data_items); d->max = p_new(float, d->data_items); - tmp_color = globalconf.screens[statusbar->screen].colors_normal[ColFG]; - for(i = 0; i < d->data_items; i++) { + ptmp_color_middle = ptmp_color_end = NULL; + cfg = cfg_getnsec(config, "data", i); if((color = cfg_getstr(cfg, "fg"))) @@ -291,6 +305,18 @@ graph_new(Statusbar *statusbar, cfg_t *config) else tmp_color = globalconf.screens[statusbar->screen].colors_normal[ColFG]; + if((color = cfg_getstr(cfg, "fg_middle"))) + { + ptmp_color_middle = p_new(XColor, 1); + *ptmp_color_middle = draw_color_new(globalconf.display, phys_screen, color); + } + + if((color = cfg_getstr(cfg, "fg_end"))) + { + ptmp_color_end = p_new(XColor, 1); + *ptmp_color_end = draw_color_new(globalconf.display, phys_screen, color); + } + if (cfg_getbool(cfg, "scale")) d->values[i] = p_new(float, d->size); /* not null -> scale = true */ @@ -313,18 +339,24 @@ graph_new(Statusbar *statusbar, cfg_t *config) { d->fillbottom[d->fillbottom_total] = d->lines[i]; d->fillbottom_color[d->fillbottom_total] = tmp_color; + d->fillbottom_pcolor_middle[d->fillbottom_total] = ptmp_color_middle; + d->fillbottom_pcolor_end[d->fillbottom_total] = ptmp_color_end; d->fillbottom_total++; } else if (!a_strncmp(type, "top", sizeof("top"))) { d->filltop[d->filltop_total] = d->lines[i]; d->filltop_color[d->filltop_total] = tmp_color; + d->filltop_pcolor_middle[d->fillbottom_total] = ptmp_color_middle; + d->filltop_pcolor_end[d->fillbottom_total] = ptmp_color_end; d->filltop_total++; } else if (!a_strncmp(type, "line", sizeof("line"))) { d->drawline[d->drawline_total] = d->lines[i]; d->drawline_color[d->drawline_total] = tmp_color; + d->drawline_pcolor_middle[d->fillbottom_total] = ptmp_color_middle; + d->drawline_pcolor_end[d->fillbottom_total] = ptmp_color_end; d->drawline_total++; } }