1
0
Fork 0
mirror of https://github.com/davatorium/rofi.git synced 2024-11-25 13:55:34 -05:00

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
This commit is contained in:
nick87720z 2020-06-17 17:10:48 +05:00 committed by GitHub
parent 6bf823267e
commit e52094ee7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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 );
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 ) ) {
int j = ( ( vspace ) / 2.0 );
radius_br = MIN ( radius_br, j );
radius_tr = MIN ( radius_tr, j );
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 ) ) {
int j = ( ( hspace ) / 2.0 );
radius_tr = MIN ( radius_tr, j );
radius_tl = MIN ( radius_tl, j );
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 );
}
if ( ( radius_bl + radius_br ) > ( hspace ) ) {
int j = ( ( hspace ) / 2.0 );
radius_br = MIN ( radius_br, j );
radius_bl = MIN ( radius_bl, j );
}
// 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;
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 ( 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 );
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 );
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 );
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 );
radius_out_bl = radius_bl + minof_bl ,
radius_int_bl = radius_bl - minof_bl;
} else {
radius_out_bl = radius_int_bl = 0;
}
cairo_line_to ( d, margin_left + offset_lbl, widget->h - margin_bottom );
cairo_close_path ( d );
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 );
}
}