From c1eaeba393e56182821a2d567f4acd864cc5caf7 Mon Sep 17 00:00:00 2001 From: bynect <68197565+bynect@users.noreply.github.com> Date: Sun, 22 Oct 2023 17:09:10 +0200 Subject: [PATCH 1/5] Improve draw_rounded_rect and fix progress bar --- src/draw.c | 262 +++++++++++++++++++++++++++++++++++----------------- src/draw.h | 24 ++++- src/x11/x.c | 2 +- 3 files changed, 203 insertions(+), 85 deletions(-) diff --git a/src/draw.c b/src/draw.c index 9cf3e86a9..1837906d1 100644 --- a/src/draw.c +++ b/src/draw.c @@ -492,6 +492,14 @@ static int frame_internal_radius (int r, int w, int h) return ret / s; } +/** + * A small wrapper around cairo_rectange for drawing a scaled rectangle. + */ +static inline void draw_rect(cairo_t *c, double x, double y, double width, double height, double scale) +{ + cairo_rectangle(c, round(x * scale), round(y * scale), round(width * scale), round(height * scale)); +} + /** * Create a path on the given cairo context to draw the background of a notification. * The top corners will get rounded by `corner_radius`, if `first` is set. @@ -500,66 +508,158 @@ static int frame_internal_radius (int r, int w, int h) * TODO: Pass additional frame width information to fix blurry lines due to fractional scaling * X and Y can then be calculated as: x = round(x*scale) + half_frame_width */ -void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int corner_radius, double scale, bool first, bool last) +void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int corner_radius, double scale, enum corner_pos corners) { + // Fast path for simple rects + if (corners == C_NONE || corner_radius <= 0) + return draw_rect(c, x, y, width, height, scale); + width = round(width * scale); height = round(height * scale); x *= scale; y *= scale; corner_radius = round(corner_radius * scale); + if (width <= 0 || height <= 0 || scale <= 0) + return; + const double degrees = M_PI / 180.0; + enum corner_pos skip = C_NONE; + + float top_y_off = 0, bot_y_off = 0; + float top_x_off = MAX(width - corner_radius, corner_radius), + bot_x_off = MAX(width - corner_radius, corner_radius); + + double bot_left_angle1 = degrees * 90; + double bot_left_angle2 = degrees * 180; + + double top_left_angle1 = degrees * 180; + double top_left_angle2 = degrees * 270; + + double top_right_angle1 = degrees * 270; + double top_right_angle2 = degrees * 360; + + double bot_right_angle1 = degrees * 0; + double bot_right_angle2 = degrees * 90; + + // The trickiest cases to handle are when the width is less than corner_radius and corner_radius * 2, + // because we have to split the angle for the arc in the rounded corner + if (width <= corner_radius) { + double angle1 = 0, angle2 = 0; + + // If there are two corners on the top/bottom they occupy half of the width + if ((corners & C_TOP) == C_TOP) + angle1 = acos(1.0 - ((double)width / 2.0) / (double)corner_radius); + else + angle1 = acos(1.0 - (double)width / (double)corner_radius); + + if ((corners & C_BOT) == C_BOT) + angle2 = acos(1.0 - ((double)width / 2.0) / (double)corner_radius); + else + angle2 = acos(1.0 - (double)width / (double)corner_radius); + + if ((corners & (C_TOP_RIGHT | C_BOT_LEFT)) == (C_TOP_RIGHT | C_BOT_LEFT) + && !(corners & C_TOP_LEFT)) { + top_y_off -= corner_radius * (1.0 - sin(angle1)); + } + + if ((corners & (C_TOP_LEFT | C_BOT_RIGHT)) == (C_TOP_LEFT | C_BOT_RIGHT) + && !(corners & C_BOT_LEFT)) { + bot_y_off = corner_radius * (1.0 - sin(angle2)); + } + + top_left_angle2 = degrees * 180 + angle1; + top_right_angle1 = degrees * 360 - angle1; + bot_left_angle1 = degrees * 180 - angle2; + bot_right_angle2 = angle2; + + top_x_off = -(corner_radius - width); + bot_x_off = -(corner_radius - width); + skip = ~corners; + } else if (width <= corner_radius * 2 && (corners & C_LEFT && corners & C_RIGHT)) { + double angle1 = 0, angle2 = 0; + if (!(corners & C_TOP_LEFT) && corners & C_TOP_RIGHT) + top_x_off = width - corner_radius; + else + angle1 = acos((double)width / (double)corner_radius - 1.0); + + if (!(corners & C_BOT_LEFT) && corners & C_BOT_RIGHT) + bot_x_off = width - corner_radius; + else + angle2 = acos((double)width / (double)corner_radius - 1.0); + + top_right_angle2 = degrees * 360 - angle1; + bot_right_angle1 = angle2; + } + cairo_new_sub_path(c); - if (last) { - // bottom right - cairo_arc(c, - x + width - corner_radius, - y + height - corner_radius, - corner_radius, - degrees * 0, - degrees * 90); - // bottom left - cairo_arc(c, - x + corner_radius, - y + height - corner_radius, - corner_radius, - degrees * 90, - degrees * 180); - } else { - cairo_line_to(c, x + width, y + height); - cairo_line_to(c, x, y + height); - } - - if (first) { - // top left - cairo_arc(c, - x + corner_radius, - y + corner_radius, - corner_radius, - degrees * 180, - degrees * 270); - // top right - cairo_arc(c, - x + width - corner_radius, - y + corner_radius, - corner_radius, - degrees * 270, - degrees * 360); - } else { - cairo_line_to(c, x, y); - cairo_line_to(c, x + width, y); + // bottom left + if (!(skip & C_BOT_LEFT)) { + if (corners & C_BOT_LEFT) { + cairo_arc(c, + x + corner_radius, + y + height - corner_radius, + corner_radius, + bot_left_angle1, + bot_left_angle2); + } else { + cairo_line_to(c, x, y + height); + if (width <= corner_radius*2) + printf("LINE BOT LEFT\n"); + } } - cairo_close_path(c); -} + // top left + if (!(skip & C_TOP_LEFT)) { + if (corners & C_TOP_LEFT) { + cairo_arc(c, + x + corner_radius, + y + corner_radius, + corner_radius, + top_left_angle1, + top_left_angle2); + } else { + cairo_line_to(c, x, y); + if (width <= corner_radius*2) + printf("LINE TOP LEFT\n"); + } + } -/** - * A small wrapper around cairo_rectange for drawing a scaled rectangle. - */ -static void draw_rect(cairo_t *c, double x, double y, double width, double height, double scale) { - cairo_rectangle(c, round(x * scale), round(y * scale), round(width * scale), round(height * scale)); + // top right + if (!(skip & C_TOP_RIGHT)) { + if (corners & C_TOP_RIGHT) { + cairo_arc(c, + x + top_x_off, + y + corner_radius + top_y_off, + corner_radius, + top_right_angle1, + top_right_angle2); + } else { + cairo_line_to(c, x + width, y); + if (width <= corner_radius*2) + printf("LINE TOP RIGHT\n"); + } + } + + // bottom right + if (!(skip & C_BOT_RIGHT)) { + if (corners & C_BOT_RIGHT) { + cairo_arc(c, + x + bot_x_off, + y + height - corner_radius + bot_y_off, + corner_radius, + bot_right_angle1, + bot_right_angle2); + } else { + cairo_line_to(c, x + width, y + height); + if (width <= corner_radius*2) + printf("LINE BOT RIGHT\n"); + } + } + + cairo_close_path(c); } static cairo_surface_t *render_background(cairo_surface_t *srf, @@ -569,8 +669,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, int width, int height, int corner_radius, - bool first, - bool last, + enum corner_pos corners, int *ret_width, double scale) { @@ -585,36 +684,36 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, /* for correct combination of adjacent areas */ cairo_set_operator(c, CAIRO_OPERATOR_ADD); - if (first) + if (corners & C_TOP) height += settings.frame_width; - if (last) + if (corners & C_BOT) height += settings.frame_width; else height += settings.separator_height; - draw_rounded_rect(c, x, y, width, height, corner_radius, scale, first, last); + draw_rounded_rect(c, x, y, width, height, corner_radius, scale, corners); /* adding frame */ x += settings.frame_width; - if (first) { + if (corners & C_TOP) { y += settings.frame_width; height -= settings.frame_width; } width -= 2 * settings.frame_width; - if (last) + if (corners & C_BOT) height -= settings.frame_width; else height -= settings.separator_height; radius_int = frame_internal_radius(corner_radius, settings.frame_width, height); - draw_rounded_rect(c, x, y, width, height, radius_int, scale, first, last); + draw_rounded_rect(c, x, y, width, height, radius_int, scale, corners); cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a); cairo_fill(c); - draw_rounded_rect(c, x, y, width, height, radius_int, scale, first, last); + draw_rounded_rect(c, x, y, width, height, radius_int, scale, corners); cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a); cairo_fill(c); @@ -622,7 +721,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, if ( settings.sep_color.type != SEP_FRAME && settings.separator_height > 0 - && !last) { + && !(corners & C_BOT)) { struct color sep_color = layout_get_sepcolor(cl, cl_next); cairo_set_source_rgba(c, sep_color.r, sep_color.g, sep_color.b, sep_color.a); @@ -711,7 +810,7 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou } // else ICON_RIGHT cairo_set_source_surface(c, cl->icon, round(image_x * scale), round(image_y * scale)); - draw_rounded_rect(c, image_x, image_y, image_width, image_height, settings.icon_corner_radius, scale, true, true); + draw_rounded_rect(c, image_x, image_y, image_width, image_height, settings.icon_corner_radius, scale, C_ALL); cairo_fill(c); } @@ -741,22 +840,23 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou unsigned int x_bar_1 = frame_x + frame_width, x_bar_2 = x_bar_1 + progress_width_1; - double half_frame_width = frame_width / 2.0; + float half_frame_width = (float)frame_width / 2.0f; /* Draw progress bar * TODO: Modify draw_rounded_rect to fix blurry lines due to fractional scaling - * Note: the bar could be drawn a bit smaller, because the frame is drawn on top + * Note: the bar could be drawn a bit smaller, because the frame is drawn on top */ - // left side (fill) - cairo_set_source_rgba(c, cl->highlight.r, cl->highlight.g, cl->highlight.b, cl->highlight.a); - draw_rounded_rect(c, x_bar_1, frame_y, progress_width_1, progress_height, - settings.progress_bar_corner_radius, scale, true, true); - cairo_fill(c); + // right side (background) cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a); - draw_rounded_rect(c, x_bar_2, frame_y, progress_width_2, progress_height, - settings.progress_bar_corner_radius, scale, true, true); + draw_rounded_rect(c, x_bar_1, frame_y, progress_width_without_frame, progress_height, + settings.progress_bar_corner_radius, scale, C_ALL); + cairo_fill(c); + // left side (fill) + cairo_set_source_rgba(c, cl->highlight.r, cl->highlight.g, cl->highlight.b, cl->highlight.a); + draw_rounded_rect(c, x_bar_1, frame_y, progress_width_1, progress_height, + settings.progress_bar_corner_radius, scale, C_ALL); cairo_fill(c); // border @@ -764,11 +864,11 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou cairo_set_line_width(c, frame_width * scale); draw_rounded_rect(c, frame_x + half_frame_width, - frame_y + half_frame_width, + frame_y, progress_width - frame_width, progress_height, settings.progress_bar_corner_radius, - scale, true, true); + scale, C_ALL); cairo_stroke(c); } } @@ -777,8 +877,7 @@ static struct dimensions layout_render(cairo_surface_t *srf, struct colored_layout *cl, struct colored_layout *cl_next, struct dimensions dim, - bool first, - bool last) + enum corner_pos corners) { double scale = output->get_scale(); const int cl_h = layout_get_height(cl, scale); @@ -789,16 +888,16 @@ static struct dimensions layout_render(cairo_surface_t *srf, int bg_width = 0; int bg_height = MIN(settings.height, (2 * settings.padding) + cl_h); - cairo_surface_t *content = render_background(srf, cl, cl_next, dim.y, dim.w, bg_height, dim.corner_radius, first, last, &bg_width, scale); + cairo_surface_t *content = render_background(srf, cl, cl_next, dim.y, dim.w, bg_height, dim.corner_radius, corners, &bg_width, scale); cairo_t *c = cairo_create(content); render_content(c, cl, bg_width, scale); /* adding frame */ - if (first) + if (corners & C_TOP) dim.y += settings.frame_width; - if (last) + if (corners & C_BOT) dim.y += settings.frame_width; if ((2 * settings.padding + cl_h) < settings.height) @@ -886,22 +985,19 @@ void draw(void) round(dim.w * scale), round(dim.h * scale)); - bool first = true; - bool last; + enum corner_pos corners = C_TOP; for (GSList *iter = layouts; iter; iter = iter->next) { struct colored_layout *cl_this = iter->data; struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; - last = !cl_next; - - if (settings.gap_size) { - first = true; - last = true; - } - dim = layout_render(image_surface, cl_this, cl_next, dim, first, last); + if (settings.gap_size) + corners = C_ALL; + else if (!cl_next) + corners = C_BOT; - first = false; + dim = layout_render(image_surface, cl_this, cl_next, dim, corners); + corners &= ~C_TOP; } output->display_surface(image_surface, win, &dim); diff --git a/src/draw.h b/src/draw.h index 0f8231701..59f8d501a 100644 --- a/src/draw.h +++ b/src/draw.h @@ -12,7 +12,29 @@ void draw_setup(void); void draw(void); -void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int corner_radius, double scale, bool first, bool last); +/** + * Specify which corner to draw in draw_rouned_rect + * + * C_TOP_LEFT 0001 + * C_TOP_RIGHT 0010 + * C_BOT_LEFT 0100 + * C_BOT_RIGHT 1000 + */ +enum corner_pos { + C_NONE = 0, + C_TOP_LEFT = 1 << 0, + C_TOP_RIGHT = 1 << 1, + C_BOT_LEFT = 1 << 2, + C_BOT_RIGHT = 1 << 3, + + C_TOP = C_TOP_LEFT | C_TOP_RIGHT, + C_BOT = C_BOT_LEFT | C_BOT_RIGHT, + C_LEFT = C_TOP_LEFT | C_BOT_LEFT, + C_RIGHT = C_TOP_RIGHT | C_BOT_RIGHT, + C_ALL = C_TOP | C_BOT, +}; + +void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int corner_radius, double scale, enum corner_pos corners); // TODO get rid of this function by passing scale to everything that needs it. double draw_get_scale(void); diff --git a/src/x11/x.c b/src/x11/x.c index 00ae6ff98..6176605ce 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -114,7 +114,7 @@ static void x_win_corners_shape(struct window_x11 *win, const int rad) draw_rounded_rect(cr, 0, 0, width, height, rad, 1, - true, true); + C_ALL); cairo_fill(cr); cairo_show_page(cr); From 8196ed70095dd03b848c2057736b50833675ba4f Mon Sep 17 00:00:00 2001 From: bynect <68197565+bynect@users.noreply.github.com> Date: Tue, 24 Oct 2023 18:17:19 +0200 Subject: [PATCH 2/5] Refactor `draw_rounded_rect` and handle degenerate cases --- src/draw.c | 48 ++++++++++++++++++++++-------------------------- src/draw.h | 6 ++++++ 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/draw.c b/src/draw.c index 1837906d1..db6313f04 100644 --- a/src/draw.c +++ b/src/draw.c @@ -520,16 +520,19 @@ void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int y *= scale; corner_radius = round(corner_radius * scale); + // Nothing valid to draw if (width <= 0 || height <= 0 || scale <= 0) return; const double degrees = M_PI / 180.0; + // This seems to be needed for a problem that occurs mostly when using cairo_stroke + // and not cairo_fill. Since the only case where we have partial angles is the progress + // bar and there we use fill, maybe this can be removed completely? enum corner_pos skip = C_NONE; - float top_y_off = 0, bot_y_off = 0; - float top_x_off = MAX(width - corner_radius, corner_radius), - bot_x_off = MAX(width - corner_radius, corner_radius); + float top_y_off = 0, bot_y_off = 0, top_x_off, bot_x_off; + top_x_off = bot_x_off = MAX(width - corner_radius, corner_radius); double bot_left_angle1 = degrees * 90; double bot_left_angle2 = degrees * 180; @@ -559,13 +562,11 @@ void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int else angle2 = acos(1.0 - (double)width / (double)corner_radius); - if ((corners & (C_TOP_RIGHT | C_BOT_LEFT)) == (C_TOP_RIGHT | C_BOT_LEFT) - && !(corners & C_TOP_LEFT)) { + if ((corners & (C_TOP_RIGHT | C_BOT_LEFT)) == (C_TOP_RIGHT | C_BOT_LEFT) && !(corners & C_TOP_LEFT)) { top_y_off -= corner_radius * (1.0 - sin(angle1)); } - if ((corners & (C_TOP_LEFT | C_BOT_RIGHT)) == (C_TOP_LEFT | C_BOT_RIGHT) - && !(corners & C_BOT_LEFT)) { + if ((corners & (C_TOP_LEFT | C_BOT_RIGHT)) == (C_TOP_LEFT | C_BOT_RIGHT) && !(corners & C_BOT_LEFT)) { bot_y_off = corner_radius * (1.0 - sin(angle2)); } @@ -576,7 +577,10 @@ void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int top_x_off = -(corner_radius - width); bot_x_off = -(corner_radius - width); - skip = ~corners; + + if (corners != C_TOP && corners != C_BOT) + skip = ~corners; + } else if (width <= corner_radius * 2 && (corners & C_LEFT && corners & C_RIGHT)) { double angle1 = 0, angle2 = 0; if (!(corners & C_TOP_LEFT) && corners & C_TOP_RIGHT) @@ -606,8 +610,6 @@ void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int bot_left_angle2); } else { cairo_line_to(c, x, y + height); - if (width <= corner_radius*2) - printf("LINE BOT LEFT\n"); } } @@ -622,8 +624,6 @@ void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int top_left_angle2); } else { cairo_line_to(c, x, y); - if (width <= corner_radius*2) - printf("LINE TOP LEFT\n"); } } @@ -638,8 +638,6 @@ void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int top_right_angle2); } else { cairo_line_to(c, x + width, y); - if (width <= corner_radius*2) - printf("LINE TOP RIGHT\n"); } } @@ -654,8 +652,6 @@ void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int bot_right_angle2); } else { cairo_line_to(c, x + width, y + height); - if (width <= corner_radius*2) - printf("LINE BOT RIGHT\n"); } } @@ -684,9 +680,9 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, /* for correct combination of adjacent areas */ cairo_set_operator(c, CAIRO_OPERATOR_ADD); - if (corners & C_TOP) + if (corners & (C_TOP | _C_FIRST)) height += settings.frame_width; - if (corners & C_BOT) + if (corners & (C_BOT | _C_LAST)) height += settings.frame_width; else height += settings.separator_height; @@ -695,14 +691,14 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, /* adding frame */ x += settings.frame_width; - if (corners & C_TOP) { + if (corners & (C_TOP | _C_FIRST)) { y += settings.frame_width; height -= settings.frame_width; } width -= 2 * settings.frame_width; - if (corners & C_BOT) + if (corners & (C_BOT | _C_LAST)) height -= settings.frame_width; else height -= settings.separator_height; @@ -721,7 +717,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, if ( settings.sep_color.type != SEP_FRAME && settings.separator_height > 0 - && !(corners & C_BOT)) { + && (corners & (C_BOT | _C_LAST)) == 0) { struct color sep_color = layout_get_sepcolor(cl, cl_next); cairo_set_source_rgba(c, sep_color.r, sep_color.g, sep_color.b, sep_color.a); @@ -894,10 +890,10 @@ static struct dimensions layout_render(cairo_surface_t *srf, render_content(c, cl, bg_width, scale); /* adding frame */ - if (corners & C_TOP) + if (corners & (C_TOP | _C_FIRST)) dim.y += settings.frame_width; - if (corners & C_BOT) + if (corners & (C_BOT | _C_LAST)) dim.y += settings.frame_width; if ((2 * settings.padding + cl_h) < settings.height) @@ -985,7 +981,7 @@ void draw(void) round(dim.w * scale), round(dim.h * scale)); - enum corner_pos corners = C_TOP; + enum corner_pos corners = C_TOP | _C_FIRST; for (GSList *iter = layouts; iter; iter = iter->next) { struct colored_layout *cl_this = iter->data; @@ -994,10 +990,10 @@ void draw(void) if (settings.gap_size) corners = C_ALL; else if (!cl_next) - corners = C_BOT; + corners |= C_BOT | _C_LAST; dim = layout_render(image_surface, cl_this, cl_next, dim, corners); - corners &= ~C_TOP; + corners &= ~(C_TOP | _C_FIRST); } output->display_surface(image_surface, win, &dim); diff --git a/src/draw.h b/src/draw.h index 59f8d501a..3b4b5a7e4 100644 --- a/src/draw.h +++ b/src/draw.h @@ -27,11 +27,17 @@ enum corner_pos { C_BOT_LEFT = 1 << 2, C_BOT_RIGHT = 1 << 3, + // Handy combinations of the corners C_TOP = C_TOP_LEFT | C_TOP_RIGHT, C_BOT = C_BOT_LEFT | C_BOT_RIGHT, C_LEFT = C_TOP_LEFT | C_BOT_LEFT, C_RIGHT = C_TOP_RIGHT | C_BOT_RIGHT, C_ALL = C_TOP | C_BOT, + + // These two values are internal only and + // should not be used outside of draw.c ! + _C_FIRST = 1 << 4, + _C_LAST = 1 << 5, }; void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int corner_radius, double scale, enum corner_pos corners); From 934f75984605a7868117411bdfbe4478a6d31284 Mon Sep 17 00:00:00 2001 From: bynect <68197565+bynect@users.noreply.github.com> Date: Tue, 24 Oct 2023 18:20:45 +0200 Subject: [PATCH 3/5] Update tests --- src/draw.c | 6 ++++-- test/draw.c | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/draw.c b/src/draw.c index db6313f04..548faacbf 100644 --- a/src/draw.c +++ b/src/draw.c @@ -511,8 +511,10 @@ static inline void draw_rect(cairo_t *c, double x, double y, double width, doubl void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int corner_radius, double scale, enum corner_pos corners) { // Fast path for simple rects - if (corners == C_NONE || corner_radius <= 0) - return draw_rect(c, x, y, width, height, scale); + if (corners == C_NONE || corner_radius <= 0) { + draw_rect(c, x, y, width, height, scale); + return; + } width = round(width * scale); height = round(height * scale); diff --git a/test/draw.c b/test/draw.c index cc564cac5..e835d9593 100644 --- a/test/draw.c +++ b/test/draw.c @@ -240,14 +240,16 @@ TEST test_layout_render_no_gaps(void) dim = calculate_dimensions(layouts); image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - bool first = true; + enum corner_pos corners = C_TOP | _C_FIRST; for (GSList *iter = layouts; iter; iter = iter->next) { struct colored_layout *cl_this = iter->data; struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; - dim = layout_render(image_surface, cl_this, cl_next, dim, first, !cl_next); + if (!cl_next) + corners |= C_BOT | _C_LAST; + dim = layout_render(image_surface, cl_this, cl_next, dim, corners); - first = false; + corners &= ~(C_TOP | _C_FIRST); } expected_y = get_expected_dimension_y_offset(layout_count); @@ -286,7 +288,7 @@ TEST test_layout_render_gaps(void) struct colored_layout *cl_this = iter->data; struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; - dim = layout_render(image_surface, cl_this, cl_next, dim, true, true); + dim = layout_render(image_surface, cl_this, cl_next, dim, C_ALL); } expected_y = get_expected_dimension_y_offset(layout_count); From 44499d7e5903cb31ff6a5db20aac0fb38b3bd669 Mon Sep 17 00:00:00 2001 From: bynect <68197565+bynect@users.noreply.github.com> Date: Tue, 24 Oct 2023 18:35:55 +0200 Subject: [PATCH 4/5] Decrease the size of the progress_bar background --- src/draw.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/draw.c b/src/draw.c index 548faacbf..8d2b997e3 100644 --- a/src/draw.c +++ b/src/draw.c @@ -822,7 +822,7 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou frame_y = settings.padding + h - settings.progress_bar_height, progress_width_without_frame = progress_width - 2 * frame_width, progress_width_1 = progress_width_without_frame * progress / 100, - progress_width_2 = progress_width_without_frame - progress_width_1; + progress_width_2 = progress_width_without_frame - 1; switch (cl->n->progress_bar_alignment) { case PANGO_ALIGN_LEFT: @@ -836,22 +836,23 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou break; } unsigned int x_bar_1 = frame_x + frame_width, - x_bar_2 = x_bar_1 + progress_width_1; + x_bar_2 = x_bar_1 + 0.5; - float half_frame_width = (float)frame_width / 2.0f; + double half_frame_width = (double)frame_width / 2.0; /* Draw progress bar * TODO: Modify draw_rounded_rect to fix blurry lines due to fractional scaling - * Note: the bar could be drawn a bit smaller, because the frame is drawn on top + * Note: for now the bar background is drawn a little bit smaller than the fill, however + * this solution is not particularly solid (basically subracting a pixel or two) */ - // right side (background) + // back layer (background) cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a); - draw_rounded_rect(c, x_bar_1, frame_y, progress_width_without_frame, progress_height, + draw_rounded_rect(c, x_bar_2, frame_y, progress_width_2, progress_height, settings.progress_bar_corner_radius, scale, C_ALL); cairo_fill(c); - // left side (fill) + // top layer (fill) cairo_set_source_rgba(c, cl->highlight.r, cl->highlight.g, cl->highlight.b, cl->highlight.a); draw_rounded_rect(c, x_bar_1, frame_y, progress_width_1, progress_height, settings.progress_bar_corner_radius, scale, C_ALL); @@ -861,9 +862,9 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a); cairo_set_line_width(c, frame_width * scale); draw_rounded_rect(c, - frame_x + half_frame_width, + frame_x + half_frame_width + 1, frame_y, - progress_width - frame_width, + progress_width - frame_width - 2, progress_height, settings.progress_bar_corner_radius, scale, C_ALL); From a697e8ca8b34a1c1258c986492fa41b15ce18a9b Mon Sep 17 00:00:00 2001 From: bynect <68197565+bynect@users.noreply.github.com> Date: Tue, 24 Oct 2023 18:42:54 +0200 Subject: [PATCH 5/5] Fix spacing --- test/draw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/draw.c b/test/draw.c index e835d9593..08f662b97 100644 --- a/test/draw.c +++ b/test/draw.c @@ -240,16 +240,16 @@ TEST test_layout_render_no_gaps(void) dim = calculate_dimensions(layouts); image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - enum corner_pos corners = C_TOP | _C_FIRST; + enum corner_pos corners = C_TOP | _C_FIRST; for (GSList *iter = layouts; iter; iter = iter->next) { struct colored_layout *cl_this = iter->data; struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; - if (!cl_next) + if (!cl_next) corners |= C_BOT | _C_LAST; dim = layout_render(image_surface, cl_this, cl_next, dim, corners); - corners &= ~(C_TOP | _C_FIRST); + corners &= ~(C_TOP | _C_FIRST); } expected_y = get_expected_dimension_y_offset(layout_count);