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:
parent
6bf823267e
commit
e52094ee7a
1 changed files with 122 additions and 166 deletions
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue