summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornick87720z <nick87720z@gmail.com>2020-06-17 17:10:48 +0500
committerGitHub <noreply@github.com>2020-06-17 14:10:48 +0200
commite52094ee7a2c216ddf74660a0b4a2e51d7433948 (patch)
treee1d8aade50b6335202e8021022495cfe77db2da0
parent6bf823267e52d96b9f8fe6e152d55e9bd715a629 (diff)
Widget bg draw (#1147)
* Improved background draw code - Better to read (precalculated coordinates) - Unnecessary line_to in the end - Don't use radius in calculations if zero * Background draw - separate rounded rect function * Limit background & border overlap size Overlap is too good against artifacts when stiching antialiased areas to be avoided, unless intermediate image is used for additive stiching. But it doesn't look good with transparent borders, when overlaping background is visible. It seems, that 1px overlap is right enough to completely prevent artifacts. Though things may differ if one if side is 1px or even 0px, while adjacent is still enough thick. * Style: alignment, less noise, limit var scope
-rw-r--r--source/widgets/widget.c292
1 files changed, 124 insertions, 168 deletions
diff --git a/source/widgets/widget.c b/source/widgets/widget.c
index b35b60ab..ac2e0230 100644
--- a/source/widgets/widget.c
+++ b/source/widgets/widget.c
@@ -34,6 +34,38 @@
/** Default padding. */
#define WIDGET_DEFAULT_PADDING 0
+/* Corner radius - tl, tr, br, bl */
+static void draw_rounded_rect ( cairo_t * d,
+ double x1, double y1, double x2, double y2,
+ double r0, double r1, double r2, double r3 )
+{
+ if ( r0 > 0 ) {
+ cairo_move_to ( d, x1, y1+r0 );
+ cairo_arc ( d, x1+r0, y1+r0, r0, -G_PI, -G_PI_2 );
+ } else {
+ cairo_move_to ( d, x1, y1 );
+ }
+ if ( r1 > 0 ) {
+ cairo_line_to ( d, x2-r1, y1 );
+ cairo_arc ( d, x2-r1, y1+r1, r1, -G_PI_2, 0.0 );
+ } else {
+ cairo_line_to ( d, x2, y1 );
+ }
+ if ( r2 > 0 ) {
+ cairo_line_to ( d, x2, y2-r2 );
+ cairo_arc ( d, x2-r2, y2-r2, r2, 0.0, G_PI_2 );
+ } else {
+ cairo_line_to ( d, x2, y2 );
+ }
+ if ( r3 > 0 ) {
+ cairo_line_to ( d, x1+r3, y2 );
+ cairo_arc ( d, x1+r3, y2-r3, r3, G_PI_2, G_PI );
+ } else {
+ cairo_line_to ( d, x1, y2 );
+ }
+ cairo_close_path ( d );
+}
+
void widget_init ( widget *wid, widget *parent, WidgetType type, const char *name )
{
wid->type = type;
@@ -173,52 +205,58 @@ void widget_draw ( widget *widget, cairo_t *d )
int radius_tl = distance_get_pixel ( widget->border_radius.top, ROFI_ORIENTATION_VERTICAL );
int radius_br = distance_get_pixel ( widget->border_radius.bottom, ROFI_ORIENTATION_VERTICAL );
- double vspace = widget->h - margin_top - margin_bottom - top / 2.0 - bottom / 2.0;
- double hspace = widget->w - margin_left - margin_right - left / 2.0 - right / 2.0;
- if ( ( radius_bl + radius_tl ) > ( vspace ) ) {
- int j = ( ( vspace ) / 2.0 );
- radius_bl = MIN ( radius_bl, j );
- radius_tl = MIN ( radius_tl, j );
- }
- if ( ( radius_br + radius_tr ) > ( vspace ) ) {
- int j = ( ( vspace ) / 2.0 );
- radius_br = MIN ( radius_br, j );
- radius_tr = MIN ( radius_tr, j );
- }
- if ( ( radius_tl + radius_tr ) > ( hspace ) ) {
- int j = ( ( hspace ) / 2.0 );
- radius_tr = MIN ( radius_tr, j );
- radius_tl = MIN ( radius_tl, j );
- }
- if ( ( radius_bl + radius_br ) > ( hspace ) ) {
- int j = ( ( hspace ) / 2.0 );
- radius_br = MIN ( radius_br, j );
- radius_bl = MIN ( radius_bl, j );
+ double minof_tl, minof_tr, minof_br, minof_bl;
+ {
+ double left_2 = (double) left / 2;
+ double top_2 = (double) top / 2;
+ double right_2 = (double) right / 2;
+ double bottom_2 = (double) bottom / 2;
+
+ // Calculate the different offsets for the corners.
+ minof_tl = MIN ( left_2, top_2 );
+ minof_tr = MIN ( right_2, top_2 );
+ minof_br = MIN ( right_2, bottom_2 );
+ minof_bl = MIN ( left_2, bottom_2 );
+
+ // Contain border radius in widget space
+ double vspace, vspace_2, hspace, hspace_2;
+ vspace = widget->h - ( margin_top + margin_bottom ) - ( top_2 + bottom_2 );
+ hspace = widget->w - ( margin_left + margin_right ) - ( left_2 + right_2 );
+ vspace_2 = vspace / 2;
+ hspace_2 = hspace / 2;
+
+ if ( radius_bl + radius_tl > vspace ) {
+ radius_bl = MIN ( radius_bl, vspace_2 );
+ radius_tl = MIN ( radius_tl, vspace_2 );
+ }
+ if ( radius_br + radius_tr > vspace ) {
+ radius_br = MIN ( radius_br, vspace_2 );
+ radius_tr = MIN ( radius_tr, vspace_2 );
+ }
+ if ( radius_tl + radius_tr > hspace ) {
+ radius_tr = MIN ( radius_tr, hspace_2 );
+ radius_tl = MIN ( radius_tl, hspace_2 );
+ }
+ if ( radius_bl + radius_br > hspace ) {
+ radius_br = MIN ( radius_br, hspace_2 );
+ radius_bl = MIN ( radius_bl, hspace_2 );
+ }
}
// Background painting.
// Set new x/y position.
cairo_translate ( d, widget->x, widget->y );
cairo_set_line_width ( d, 0 );
- // Set outlines.
- cairo_move_to ( d, margin_left + radius_tl + left / 2.0, margin_top + radius_tl + top / 2.0 );
- if ( radius_tl ) {
- cairo_arc ( d, margin_left + radius_tl + left / 2.0, margin_top + radius_tl + top / 2.0, radius_tl, -1.0 * G_PI, -G_PI_2 );
- }
- cairo_line_to ( d, widget->w - margin_right - radius_tr - right / 2.0, margin_top + top / 2.0 );
- if ( radius_tr ) {
- cairo_arc ( d, widget->w - margin_right - radius_tr - right / 2.0, margin_top + radius_tr + top / 2.0, radius_tr, -G_PI_2, 0 * G_PI );
- }
- cairo_line_to ( d, widget->w - margin_right - right / 2.0, widget->h - margin_bottom - radius_br - bottom / 2.0 );
- if ( radius_br ) {
- cairo_arc ( d, widget->w - margin_right - radius_br - right / 2.0, widget->h - margin_bottom - radius_br - bottom / 2.0, radius_br, 0.0 * G_PI, G_PI_2 );
- }
- cairo_line_to ( d, margin_left + radius_bl + left / 2.0, widget->h - margin_bottom - bottom / 2.0 );
- if ( radius_bl ) {
- cairo_arc ( d, margin_left + radius_bl + left / 2.0, widget->h - margin_bottom - radius_bl - bottom / 2.0, radius_bl, G_PI_2, 1.0 * G_PI );
- }
- cairo_line_to ( d, margin_left + left / 2.0, margin_top + radius_tl + top / 2.0 );
- cairo_close_path ( d );
+
+ draw_rounded_rect ( d,
+ margin_left + ( left > 2 ? left - 1 : left == 1 ? 0.5 : 0 ),
+ margin_top + ( top > 2 ? top - 1 : top == 1 ? 0.5 : 0 ),
+ widget->w - margin_right - ( right > 2 ? right - 1 : right == 1 ? 0.5 : 0 ),
+ widget->h - margin_bottom - ( bottom > 2 ? bottom - 1 : bottom == 1 ? 0.5 : 0 ),
+ radius_tl - ( minof_tl > 1 ? minof_tl - 1 : 0 ),
+ radius_tr - ( minof_tr > 1 ? minof_tr - 1 : 0 ),
+ radius_br - ( minof_br > 1 ? minof_br - 1 : 0 ),
+ radius_bl - ( minof_bl > 1 ? minof_bl - 1 : 0 ) );
cairo_set_source_rgba ( d, 1.0, 1.0, 1.0, 1.0 );
rofi_theme_get_color ( widget, "background-color", d );
@@ -235,138 +273,56 @@ void widget_draw ( widget *widget, cairo_t *d )
cairo_translate ( d, widget->x, widget->y );
cairo_new_path ( d );
rofi_theme_get_color ( widget, "border-color", d );
- // Calculate the different offsets for the corners.
- double minof_tr = MIN ( right / 2.0, top / 2.0 );
- double minof_tl = MIN ( left / 2.0, top / 2.0 );
- double minof_br = MIN ( right / 2.0, bottom / 2.0 );
- double minof_bl = MIN ( left / 2.0, bottom / 2.0 );
- // Inner radius
- double radius_inner_tl = radius_tl - minof_tl;
- double radius_inner_tr = radius_tr - minof_tr;
- double radius_inner_bl = radius_bl - minof_bl;
- double radius_inner_br = radius_br - minof_br;
-
- // Offsets of the different lines in each corner.
- //
- // | |
- // ttl ttr
- // | |
- // -ltl-###############-rtr-
- // $ $
- // $ $
- // -lbl-###############-rbr-
- // | |
- // bbl bbr
- // | |
- //
- // The left and right part ($) start at thinkness top bottom when no radius
- double offset_ltl = ( radius_inner_tl > 0 ) ? ( left ) + radius_inner_tl : left;
- double offset_rtr = ( radius_inner_tr > 0 ) ? ( right ) + radius_inner_tr : right;
- double offset_lbl = ( radius_inner_bl > 0 ) ? ( left ) + radius_inner_bl : left;
- double offset_rbr = ( radius_inner_br > 0 ) ? ( right ) + radius_inner_br : right;
- // The top and bottom part (#) go into the corner when no radius
- double offset_ttl = ( radius_inner_tl > 0 ) ? ( top ) + radius_inner_tl : ( radius_tl > 0 ) ? top : 0;
- double offset_ttr = ( radius_inner_tr > 0 ) ? ( top ) + radius_inner_tr : ( radius_tr > 0 ) ? top : 0;
- double offset_bbl = ( radius_inner_bl > 0 ) ? ( bottom ) + radius_inner_bl : ( radius_bl > 0 ) ? bottom : 0;
- double offset_bbr = ( radius_inner_br > 0 ) ? ( bottom ) + radius_inner_br : ( radius_br > 0 ) ? bottom : 0;
-
- if ( left > 0 ) {
- cairo_set_line_width ( d, left );
- distance_get_linestyle ( widget->border.left, d );
- cairo_move_to ( d, margin_left + ( left / 2.0 ), margin_top + offset_ttl );
- cairo_line_to ( d, margin_left + left / 2.0, widget->h - margin_bottom - offset_bbl );
- cairo_stroke ( d );
- }
- if ( right > 0 ) {
- cairo_set_line_width ( d, right );
- distance_get_linestyle ( widget->border.right, d );
- cairo_move_to ( d, widget->w - margin_right - right / 2.0, margin_top + offset_ttr );
- cairo_line_to ( d, widget->w - margin_right - right / 2.0, widget->h - margin_bottom - offset_bbr );
- cairo_stroke ( d );
- }
- if ( top > 0 ) {
- cairo_set_line_width ( d, top );
- distance_get_linestyle ( widget->border.top, d );
- cairo_move_to ( d, margin_left + offset_ltl, margin_top + top / 2.0 );
- cairo_line_to ( d, widget->w - margin_right - offset_rtr, margin_top + top / 2.0 );
- cairo_stroke ( d );
- }
- if ( bottom > 0 ) {
- cairo_set_line_width ( d, bottom );
- distance_get_linestyle ( widget->border.bottom, d );
- cairo_move_to ( d, margin_left + offset_lbl, widget->h - ( bottom / 2.0 ) - margin_bottom );
- cairo_line_to ( d, widget->w - margin_right - offset_rbr, widget->h - bottom / 2.0 - margin_bottom );
- cairo_stroke ( d );
- }
- if ( radius_tl > 0 ) {
- distance_get_linestyle ( widget->border.left, d );
- cairo_set_line_width ( d, 0 );
- double radius_outer = radius_tl + minof_tl;
- cairo_arc ( d, margin_left + radius_outer, margin_top + radius_outer, radius_outer, -G_PI, -G_PI_2 );
- cairo_line_to ( d, margin_left + offset_ltl, margin_top );
- cairo_line_to ( d, margin_left + offset_ltl, margin_top + top );
- if ( radius_inner_tl > 0 ) {
- cairo_arc_negative ( d,
- margin_left + left + radius_inner_tl,
- margin_top + top + radius_inner_tl,
- radius_inner_tl, -G_PI_2, G_PI );
- cairo_line_to ( d, margin_left + left, margin_top + offset_ttl );
- }
- cairo_line_to ( d, margin_left, margin_top + offset_ttl );
- cairo_close_path ( d );
- cairo_fill ( d );
+
+ double radius_int_tl, radius_int_tr, radius_int_br, radius_int_bl;
+ double radius_out_tl, radius_out_tr, radius_out_br, radius_out_bl;
+
+ if (radius_tl > 0) {
+ radius_out_tl = radius_tl + minof_tl ,
+ radius_int_tl = radius_tl - minof_tl;
+ } else {
+ radius_out_tl = radius_int_tl = 0;
}
- if ( radius_tr > 0 ) {
- distance_get_linestyle ( widget->border.right, d );
- cairo_set_line_width ( d, 0 );
- double radius_outer = radius_tr + minof_tr;
- cairo_arc ( d, widget->w - margin_right - radius_outer, margin_top + radius_outer, radius_outer, -G_PI_2, 0 );
- cairo_line_to ( d, widget->w - margin_right, margin_top + offset_ttr );
- cairo_line_to ( d, widget->w - margin_right - right, margin_top + offset_ttr );
- if ( radius_inner_tr > 0 ) {
- cairo_arc_negative ( d, widget->w - margin_right - right - radius_inner_tr,
- margin_top + top + radius_inner_tr,
- radius_inner_tr, 0, -G_PI_2 );
- cairo_line_to ( d, widget->w - margin_right - offset_rtr, margin_top + top );
- }
- cairo_line_to ( d, widget->w - margin_right - offset_rtr, margin_top );
- cairo_close_path ( d );
- cairo_fill ( d );
+ if (radius_tr > 0) {
+ radius_out_tr = radius_tr + minof_tr ,
+ radius_int_tr = radius_tr - minof_tr;
+ } else {
+ radius_out_tr = radius_int_tr = 0;
}
- if ( radius_br > 0 ) {
- distance_get_linestyle ( widget->border.right, d );
- cairo_set_line_width ( d, 1 );
- double radius_outer = radius_br + minof_br;
- cairo_arc ( d, widget->w - margin_right - radius_outer, widget->h - margin_bottom - radius_outer, radius_outer, 0.0, G_PI_2 );
- cairo_line_to ( d, widget->w - margin_right - offset_rbr, widget->h - margin_bottom );
- cairo_line_to ( d, widget->w - margin_right - offset_rbr, widget->h - margin_bottom - bottom );
- if ( radius_inner_br > 0 ) {
- cairo_arc_negative ( d, widget->w - margin_right - right - radius_inner_br,
- widget->h - margin_bottom - bottom - radius_inner_br,
- radius_inner_br, G_PI_2, 0.0 );
- cairo_line_to ( d, widget->w - margin_right - right, widget->h - margin_bottom - offset_bbr );
- }
- cairo_line_to ( d, widget->w - margin_right, widget->h - margin_bottom - offset_bbr );
- cairo_close_path ( d );
- cairo_fill ( d );
+ if (radius_br > 0) {
+ radius_out_br = radius_br + minof_br ,
+ radius_int_br = radius_br - minof_br;
+ } else {
+ radius_out_br = radius_int_br = 0;
}
- if ( radius_bl > 0 ) {
- distance_get_linestyle ( widget->border.left, d );
- cairo_set_line_width ( d, 1.0 );
- double radius_outer = radius_bl + minof_bl;
- cairo_arc ( d, margin_left + radius_outer, widget->h - margin_bottom - radius_outer, radius_outer, G_PI_2, G_PI );
- cairo_line_to ( d, margin_left, widget->h - margin_bottom - offset_bbl );
- cairo_line_to ( d, margin_left + left, widget->h - margin_bottom - offset_bbl );
- if ( radius_inner_bl > 0 ) {
- cairo_arc_negative ( d, margin_left + left + radius_inner_bl,
- widget->h - margin_bottom - bottom - radius_inner_bl,
- radius_inner_bl, G_PI, G_PI_2 );
- cairo_line_to ( d, margin_left + offset_lbl, widget->h - margin_bottom - bottom );
- }
- cairo_line_to ( d, margin_left + offset_lbl, widget->h - margin_bottom );
- cairo_close_path ( d );
- cairo_fill ( d );
+ if (radius_bl > 0) {
+ radius_out_bl = radius_bl + minof_bl ,
+ radius_int_bl = radius_bl - minof_bl;
+ } else {
+ radius_out_bl = radius_int_bl = 0;
}
+
+ draw_rounded_rect ( d,
+ margin_left,
+ margin_top,
+ widget->w - margin_right,
+ widget->h - margin_top,
+ radius_out_tl,
+ radius_out_tr,
+ radius_out_br,
+ radius_out_bl );
+ cairo_new_sub_path ( d );
+ draw_rounded_rect ( d,
+ margin_left + left,
+ margin_top + top,
+ widget->w - margin_right - right,
+ widget->h - margin_bottom - bottom,
+ radius_int_tl,
+ radius_int_tr,
+ radius_int_br,
+ radius_int_bl );
+ cairo_set_fill_rule ( d, CAIRO_FILL_RULE_EVEN_ODD );
+ cairo_fill ( d );
cairo_restore ( d );
}
}