diff --git a/gtk/gtkroundedbox.c b/gtk/gtkroundedbox.c index 3414e484f3..5b1eefcfe1 100644 --- a/gtk/gtkroundedbox.c +++ b/gtk/gtkroundedbox.c @@ -168,6 +168,25 @@ _cairo_ellipsis (cairo_t *cr, cairo_restore (cr); } +static void +_cairo_ellipsis_negative (cairo_t *cr, + double xc, double yc, + double xradius, double yradius, + double angle1, double angle2) +{ + if (xradius <= 0.0 || yradius <= 0.0) + { + cairo_line_to (cr, xc, yc); + return; + } + + cairo_save (cr); + cairo_translate (cr, xc, yc); + cairo_scale (cr, xradius, yradius); + cairo_arc_negative (cr, 0, 0, 1.0, angle1, angle2); + cairo_restore (cr); +} + void _gtk_rounded_box_path (const GtkRoundedBox *box, cairo_t *cr) @@ -200,6 +219,150 @@ _gtk_rounded_box_path (const GtkRoundedBox *box, G_PI / 2, G_PI); } +void +_gtk_rounded_box_path_top (const GtkRoundedBox *outer, + const GtkRoundedBox *inner, + cairo_t *cr) +{ + cairo_new_sub_path (cr); + + _cairo_ellipsis (cr, + outer->box.x + outer->border_radius.top_left.horizontal, + outer->box.y + outer->border_radius.top_left.vertical, + outer->border_radius.top_left.horizontal, + outer->border_radius.top_left.vertical, + 5 * G_PI / 4, 3 * G_PI / 2); + _cairo_ellipsis (cr, + outer->box.x + outer->box.width - outer->border_radius.top_right.horizontal, + outer->box.y + outer->border_radius.top_right.vertical, + outer->border_radius.top_right.horizontal, + outer->border_radius.top_right.vertical, + - G_PI / 2, -G_PI / 4); + + _cairo_ellipsis_negative (cr, + inner->box.x + inner->box.width - inner->border_radius.top_right.horizontal, + inner->box.y + inner->border_radius.top_right.vertical, + inner->border_radius.top_right.horizontal, + inner->border_radius.top_right.vertical, + -G_PI / 4, - G_PI / 2); + _cairo_ellipsis_negative (cr, + inner->box.x + inner->border_radius.top_left.horizontal, + inner->box.y + inner->border_radius.top_left.vertical, + inner->border_radius.top_left.horizontal, + inner->border_radius.top_left.vertical, + 3 * G_PI / 2, 5 * G_PI / 4); + + cairo_close_path (cr); +} + +void +_gtk_rounded_box_path_right (const GtkRoundedBox *outer, + const GtkRoundedBox *inner, + cairo_t *cr) +{ + cairo_new_sub_path (cr); + + _cairo_ellipsis (cr, + outer->box.x + outer->box.width - outer->border_radius.top_right.horizontal, + outer->box.y + outer->border_radius.top_right.vertical, + outer->border_radius.top_right.horizontal, + outer->border_radius.top_right.vertical, + - G_PI / 4, 0); + _cairo_ellipsis (cr, + outer->box.x + outer->box.width - outer->border_radius.bottom_right.horizontal, + outer->box.y + outer->box.height - outer->border_radius.bottom_right.vertical, + outer->border_radius.bottom_right.horizontal, + outer->border_radius.bottom_right.vertical, + 0, G_PI / 4); + + _cairo_ellipsis_negative (cr, + inner->box.x + inner->box.width - inner->border_radius.bottom_right.horizontal, + inner->box.y + inner->box.height - inner->border_radius.bottom_right.vertical, + inner->border_radius.bottom_right.horizontal, + inner->border_radius.bottom_right.vertical, + G_PI / 4, 0); + _cairo_ellipsis_negative (cr, + inner->box.x + inner->box.width - inner->border_radius.top_right.horizontal, + inner->box.y + inner->border_radius.top_right.vertical, + inner->border_radius.top_right.horizontal, + inner->border_radius.top_right.vertical, + 0, - G_PI / 4); + + cairo_close_path (cr); +} + +void +_gtk_rounded_box_path_bottom (const GtkRoundedBox *outer, + const GtkRoundedBox *inner, + cairo_t *cr) +{ + cairo_new_sub_path (cr); + + _cairo_ellipsis (cr, + outer->box.x + outer->box.width - outer->border_radius.bottom_right.horizontal, + outer->box.y + outer->box.height - outer->border_radius.bottom_right.vertical, + outer->border_radius.bottom_right.horizontal, + outer->border_radius.bottom_right.vertical, + G_PI / 4, G_PI / 2); + _cairo_ellipsis (cr, + outer->box.x + outer->border_radius.bottom_left.horizontal, + outer->box.y + outer->box.height - outer->border_radius.bottom_left.vertical, + outer->border_radius.bottom_left.horizontal, + outer->border_radius.bottom_left.vertical, + G_PI / 2, 3 * G_PI / 4); + + _cairo_ellipsis_negative (cr, + inner->box.x + inner->border_radius.bottom_left.horizontal, + inner->box.y + inner->box.height - inner->border_radius.bottom_left.vertical, + inner->border_radius.bottom_left.horizontal, + inner->border_radius.bottom_left.vertical, + 3 * G_PI / 4, G_PI / 2); + _cairo_ellipsis_negative (cr, + inner->box.x + inner->box.width - inner->border_radius.bottom_right.horizontal, + inner->box.y + inner->box.height - inner->border_radius.bottom_right.vertical, + inner->border_radius.bottom_right.horizontal, + inner->border_radius.bottom_right.vertical, + G_PI / 2, G_PI / 4); + + cairo_close_path (cr); +} + +void +_gtk_rounded_box_path_left (const GtkRoundedBox *outer, + const GtkRoundedBox *inner, + cairo_t *cr) +{ + cairo_new_sub_path (cr); + + _cairo_ellipsis (cr, + outer->box.x + outer->border_radius.bottom_left.horizontal, + outer->box.y + outer->box.height - outer->border_radius.bottom_left.vertical, + outer->border_radius.bottom_left.horizontal, + outer->border_radius.bottom_left.vertical, + 3 * G_PI / 4, G_PI); + _cairo_ellipsis (cr, + outer->box.x + outer->border_radius.top_left.horizontal, + outer->box.y + outer->border_radius.top_left.vertical, + outer->border_radius.top_left.horizontal, + outer->border_radius.top_left.vertical, + G_PI, 5 * G_PI / 4); + + _cairo_ellipsis_negative (cr, + inner->box.x + inner->border_radius.top_left.horizontal, + inner->box.y + inner->border_radius.top_left.vertical, + inner->border_radius.top_left.horizontal, + inner->border_radius.top_left.vertical, + 5 * G_PI / 4, G_PI); + _cairo_ellipsis_negative (cr, + inner->box.x + inner->border_radius.bottom_left.horizontal, + inner->box.y + inner->box.height - inner->border_radius.bottom_left.vertical, + inner->border_radius.bottom_left.horizontal, + inner->border_radius.bottom_left.vertical, + G_PI, 3 * G_PI / 4); + + cairo_close_path (cr); +} + void _gtk_rounded_box_clip_path (const GtkRoundedBox *box, cairo_t *cr) diff --git a/gtk/gtkroundedboxprivate.h b/gtk/gtkroundedboxprivate.h index bd4adb4b27..af0854ff08 100644 --- a/gtk/gtkroundedboxprivate.h +++ b/gtk/gtkroundedboxprivate.h @@ -58,6 +58,18 @@ void _gtk_rounded_box_move (GtkRoundedBox void _gtk_rounded_box_path (const GtkRoundedBox *box, cairo_t *cr); +void _gtk_rounded_box_path_top (const GtkRoundedBox *outer, + const GtkRoundedBox *inner, + cairo_t *cr); +void _gtk_rounded_box_path_right (const GtkRoundedBox *outer, + const GtkRoundedBox *inner, + cairo_t *cr); +void _gtk_rounded_box_path_bottom (const GtkRoundedBox *outer, + const GtkRoundedBox *inner, + cairo_t *cr); +void _gtk_rounded_box_path_left (const GtkRoundedBox *outer, + const GtkRoundedBox *inner, + cairo_t *cr); void _gtk_rounded_box_clip_path (const GtkRoundedBox *box, cairo_t *cr); diff --git a/gtk/gtkthemingengine.c b/gtk/gtkthemingengine.c index ceabb69a7a..a779125571 100644 --- a/gtk/gtkthemingengine.c +++ b/gtk/gtkthemingengine.c @@ -1658,23 +1658,26 @@ render_frame_internal (GtkThemingEngine *engine, GtkJunctionSides junction) { GtkStateFlags state; - GdkRGBA lighter; - GdkRGBA border_color; GtkBorderStyle border_style; GtkRoundedBox border_box, padding_box; gdouble progress; gboolean running; GtkBorder border; - double min_size; + static const guint current_side[4] = { SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM, SIDE_LEFT }; + GdkRGBA *colors[4]; + guint i; state = gtk_theming_engine_get_state (engine); - gtk_theming_engine_get_border_color (engine, state, &border_color); gtk_theming_engine_get_border (engine, state, &border); gtk_theming_engine_hide_border_sides (&border, hidden_side); gtk_theming_engine_get (engine, state, "border-style", &border_style, + "border-top-color", &colors[0], + "border-right-color", &colors[1], + "border-bottom-color", &colors[2], + "border-left-color", &colors[3], NULL); running = gtk_theming_engine_state_is_running (engine, GTK_STATE_PRELIGHT, &progress); @@ -1682,7 +1685,7 @@ render_frame_internal (GtkThemingEngine *engine, if (running) { GtkStateFlags other_state; - GdkRGBA other_color; + GdkRGBA *other_colors[4]; if (state & GTK_STATE_FLAG_PRELIGHT) { @@ -1692,12 +1695,38 @@ render_frame_internal (GtkThemingEngine *engine, else other_state = state | GTK_STATE_FLAG_PRELIGHT; - gtk_theming_engine_get_border_color (engine, other_state, &other_color); + gtk_theming_engine_get (engine, other_state, + "border-top-color", &other_colors[0], + "border-right-color", &other_colors[1], + "border-bottom-color", &other_colors[2], + "border-left-color", &other_colors[3], + NULL); - border_color.red = CLAMP (border_color.red + ((other_color.red - border_color.red) * progress), 0, 1); - border_color.green = CLAMP (border_color.green + ((other_color.green - border_color.green) * progress), 0, 1); - border_color.blue = CLAMP (border_color.blue + ((other_color.blue - border_color.blue) * progress), 0, 1); - border_color.alpha = CLAMP (border_color.alpha + ((other_color.alpha - border_color.alpha) * progress), 0, 1); + for (i = 0; i < 4; i++) + { + colors[i]->red = CLAMP (colors[i]->red + ((other_colors[i]->red - colors[i]->red) * progress), 0, 1); + colors[i]->green = CLAMP (colors[i]->green + ((other_colors[i]->green - colors[i]->green) * progress), 0, 1); + colors[i]->blue = CLAMP (colors[i]->blue + ((other_colors[i]->blue - colors[i]->blue) * progress), 0, 1); + colors[i]->alpha = CLAMP (colors[i]->alpha + ((other_colors[i]->alpha - colors[i]->alpha) * progress), 0, 1); + gdk_rgba_free (other_colors[i]); + } + } + + switch (border_style) + { + default: + g_assert_not_reached (); + case GTK_BORDER_STYLE_NONE: + case GTK_BORDER_STYLE_SOLID: + break; + case GTK_BORDER_STYLE_INSET: + color_shade (colors[1], 1.8, colors[1]); + color_shade (colors[2], 1.8, colors[2]); + break; + case GTK_BORDER_STYLE_OUTSET: + color_shade (colors[0], 1.8, colors[0]); + color_shade (colors[3], 1.8, colors[3]); + break; } cairo_save (cr); @@ -1714,58 +1743,47 @@ render_frame_internal (GtkThemingEngine *engine, case GTK_BORDER_STYLE_NONE: break; case GTK_BORDER_STYLE_SOLID: - gdk_cairo_set_source_rgba (cr, &border_color); - - _gtk_rounded_box_path (&border_box, cr); - _gtk_rounded_box_path (&padding_box, cr); - cairo_fill (cr); - - break; case GTK_BORDER_STYLE_INSET: case GTK_BORDER_STYLE_OUTSET: - color_shade (&border_color, 1.8, &lighter); - min_size = MIN (width, height) / 2; - cairo_save (cr); + if (gdk_rgba_equal (colors[0], colors[1]) && + gdk_rgba_equal (colors[0], colors[2]) && + gdk_rgba_equal (colors[0], colors[3])) + { + gdk_cairo_set_source_rgba (cr, colors[0]); - _gtk_rounded_box_path (&border_box, cr); - _gtk_rounded_box_path (&padding_box, cr); - cairo_clip (cr); + _gtk_rounded_box_path (&border_box, cr); + _gtk_rounded_box_path (&padding_box, cr); + cairo_fill (cr); + } + else + { + for (i = 0; i < 4; i++) + { + if (hidden_side & current_side[i]) + continue; - /* Now that we've clipped the border, we split the rectangle like this: - * +----------------------+ - * | · /| - * | ·/ | - * |··+----------------+··| - * | /· | - * |/ · | - * +----------------------+ - * The dots mark how we adapt the area when sides are hidden to not get - * artifacts at the corners. - */ - cairo_move_to (cr, x, y); - cairo_line_to (cr, x, y + height - ((hidden_side & SIDE_LEFT) ? min_size : 0)); - cairo_line_to (cr, x + min_size, y + height - ((hidden_side & SIDE_BOTTOM) ? 0 : min_size)); - cairo_line_to (cr, x + width - ((hidden_side & SIDE_RIGHT) ? 0 : min_size), y + min_size); - cairo_line_to (cr, x + width, y + ((hidden_side & SIDE_TOP) ? min_size : 0)); + gdk_cairo_set_source_rgba (cr, colors[i]); - /* Now we (ab)use the fact that with the EVEN_ODD fill rule one can - * "invert" the filled area by adding it to the path again. - */ - if (border_style == GTK_BORDER_STYLE_OUTSET) - cairo_rectangle (cr, x, y, width, height); + if (i == 0) + _gtk_rounded_box_path_top (&border_box, &padding_box, cr); + else if (i == 1) + _gtk_rounded_box_path_right (&border_box, &padding_box, cr); + else if (i == 2) + _gtk_rounded_box_path_bottom (&border_box, &padding_box, cr); + else if (i == 3) + _gtk_rounded_box_path_left (&border_box, &padding_box, cr); - gdk_cairo_set_source_rgba (cr, &border_color); - cairo_fill_preserve (cr); - - cairo_rectangle (cr, x, y, width, height); - gdk_cairo_set_source_rgba (cr, &lighter); - cairo_fill (cr); - - cairo_restore (cr); + cairo_fill (cr); + } + } + break; } cairo_restore (cr); + + for (i = 0; i < 4; i++) + gdk_rgba_free (colors[i]); } static void