[gtk+] themingengine: Implement 'dotted' and 'dashed'
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] themingengine: Implement 'dotted' and 'dashed'
- Date: Mon, 9 Jan 2012 17:56:02 +0000 (UTC)
commit 1b9e15485ee6ff07d044dc256339ed5bc2b6f401
Author: Benjamin Otte <otte redhat com>
Date: Sun Jan 8 01:17:48 2012 +0100
themingengine: Implement 'dotted' and 'dashed'
gtk/gtkroundedbox.c | 96 +++++++++++++++++++++++++
gtk/gtkroundedboxprivate.h | 6 ++
gtk/gtkthemingengine.c | 165 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 267 insertions(+), 0 deletions(-)
---
diff --git a/gtk/gtkroundedbox.c b/gtk/gtkroundedbox.c
index 0519bfe..4e7c19d 100644
--- a/gtk/gtkroundedbox.c
+++ b/gtk/gtkroundedbox.c
@@ -246,6 +246,102 @@ _gtk_rounded_box_path (const GtkRoundedBox *box,
G_PI / 2, G_PI);
}
+double
+_gtk_rounded_box_guess_length (const GtkRoundedBox *box,
+ GtkCssSide side)
+{
+ double length;
+ GtkCssCorner before, after;
+
+ before = side;
+ after = (side + 1) % 4;
+
+ if (side & 1)
+ length = box->box.height
+ - box->corner[before].vertical
+ - box->corner[after].vertical;
+ else
+ length = box->box.width
+ - box->corner[before].horizontal
+ - box->corner[after].horizontal;
+
+ length += G_PI * 0.125 * (box->corner[before].horizontal
+ + box->corner[before].vertical
+ + box->corner[after].horizontal
+ + box->corner[after].vertical);
+
+ return length;
+}
+
+void
+_gtk_rounded_box_path_side (const GtkRoundedBox *box,
+ cairo_t *cr,
+ GtkCssSide side)
+{
+ switch (side)
+ {
+ case GTK_CSS_TOP:
+ _cairo_ellipsis (cr,
+ box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
+ box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
+ box->corner[GTK_CSS_TOP_LEFT].horizontal,
+ box->corner[GTK_CSS_TOP_LEFT].vertical,
+ 5 * G_PI / 4, 3 * G_PI / 2);
+ _cairo_ellipsis (cr,
+ box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
+ box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
+ box->corner[GTK_CSS_TOP_RIGHT].horizontal,
+ box->corner[GTK_CSS_TOP_RIGHT].vertical,
+ - G_PI / 2, -G_PI / 4);
+ break;
+ case GTK_CSS_RIGHT:
+ _cairo_ellipsis (cr,
+ box->box.x + box->box.width - box->corner[GTK_CSS_TOP_RIGHT].horizontal,
+ box->box.y + box->corner[GTK_CSS_TOP_RIGHT].vertical,
+ box->corner[GTK_CSS_TOP_RIGHT].horizontal,
+ box->corner[GTK_CSS_TOP_RIGHT].vertical,
+ - G_PI / 4, 0);
+ _cairo_ellipsis (cr,
+ box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
+ box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
+ box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
+ box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
+ 0, G_PI / 4);
+ break;
+ case GTK_CSS_BOTTOM:
+ _cairo_ellipsis (cr,
+ box->box.x + box->box.width - box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
+ box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
+ box->corner[GTK_CSS_BOTTOM_RIGHT].horizontal,
+ box->corner[GTK_CSS_BOTTOM_RIGHT].vertical,
+ G_PI / 4, G_PI / 2);
+ _cairo_ellipsis (cr,
+ box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
+ box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
+ box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
+ box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
+ G_PI / 2, 3 * G_PI / 4);
+ break;
+ case GTK_CSS_LEFT:
+ _cairo_ellipsis (cr,
+ box->box.x + box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
+ box->box.y + box->box.height - box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
+ box->corner[GTK_CSS_BOTTOM_LEFT].horizontal,
+ box->corner[GTK_CSS_BOTTOM_LEFT].vertical,
+ 3 * G_PI / 4, G_PI);
+ _cairo_ellipsis (cr,
+ box->box.x + box->corner[GTK_CSS_TOP_LEFT].horizontal,
+ box->box.y + box->corner[GTK_CSS_TOP_LEFT].vertical,
+ box->corner[GTK_CSS_TOP_LEFT].horizontal,
+ box->corner[GTK_CSS_TOP_LEFT].vertical,
+ G_PI, 5 * G_PI / 4);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
void
_gtk_rounded_box_path_top (const GtkRoundedBox *outer,
const GtkRoundedBox *inner,
diff --git a/gtk/gtkroundedboxprivate.h b/gtk/gtkroundedboxprivate.h
index a832b9b..98309e7 100644
--- a/gtk/gtkroundedboxprivate.h
+++ b/gtk/gtkroundedboxprivate.h
@@ -56,8 +56,14 @@ void _gtk_rounded_box_move (GtkRoundedBox
double dx,
double dy);
+double _gtk_rounded_box_guess_length (const GtkRoundedBox *box,
+ GtkCssSide side);
+
void _gtk_rounded_box_path (const GtkRoundedBox *box,
cairo_t *cr);
+void _gtk_rounded_box_path_side (const GtkRoundedBox *box,
+ cairo_t *cr,
+ GtkCssSide side);
void _gtk_rounded_box_path_top (const GtkRoundedBox *outer,
const GtkRoundedBox *inner,
cairo_t *cr);
diff --git a/gtk/gtkthemingengine.c b/gtk/gtkthemingengine.c
index b9e2e38..149c5b3 100644
--- a/gtk/gtkthemingengine.c
+++ b/gtk/gtkthemingengine.c
@@ -1435,6 +1435,158 @@ render_frame_fill (cairo_t *cr,
}
static void
+set_stroke_style (cairo_t *cr,
+ double line_width,
+ GtkBorderStyle style,
+ double length)
+{
+ double segments[2];
+ double n;
+
+ cairo_set_line_width (cr, line_width);
+
+ if (style == GTK_BORDER_STYLE_DOTTED)
+ {
+ n = round (0.5 * length / line_width);
+
+ segments[0] = 0;
+ segments[1] = n ? length / n : 2;
+ cairo_set_dash (cr, segments, G_N_ELEMENTS (segments), 0);
+
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+ }
+ else
+ {
+ n = length / line_width;
+ /* Optimize the common case of an integer-sized rectangle
+ * Again, we care about focus rectangles.
+ */
+ if (n == nearbyint (n))
+ {
+ segments[0] = 1;
+ segments[1] = 2;
+ }
+ else
+ {
+ n = round ((1. / 3) * n);
+
+ segments[0] = n ? (1. / 3) * length / n : 1;
+ segments[1] = 2 * segments[1];
+ }
+ cairo_set_dash (cr, segments, G_N_ELEMENTS (segments), 0);
+
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
+ }
+}
+
+static int
+get_border_side (GtkBorder *border,
+ GtkCssSide side)
+{
+ switch (side)
+ {
+ case GTK_CSS_TOP:
+ return border->top;
+ case GTK_CSS_RIGHT:
+ return border->right;
+ case GTK_CSS_BOTTOM:
+ return border->bottom;
+ case GTK_CSS_LEFT:
+ return border->left;
+ default:
+ g_assert_not_reached ();
+ return 0;
+ }
+}
+
+static void
+render_frame_stroke (cairo_t *cr,
+ GtkRoundedBox *border_box,
+ GtkBorder *border,
+ GdkRGBA colors[4],
+ guint hidden_side,
+ GtkBorderStyle stroke_style)
+{
+ gboolean different_colors, different_borders;
+ GtkRoundedBox stroke_box;
+ guint i;
+
+ different_colors = !gdk_rgba_equal (&colors[0], &colors[1]) ||
+ !gdk_rgba_equal (&colors[0], &colors[2]) ||
+ !gdk_rgba_equal (&colors[0], &colors[3]);
+ different_borders = border->top != border->right ||
+ border->top != border->bottom ||
+ border->top != border->left;
+
+ stroke_box = *border_box;
+ _gtk_rounded_box_shrink (&stroke_box,
+ border->top / 2.0,
+ border->right / 2.0,
+ border->bottom / 2.0,
+ border->left / 2.0);
+
+ if (!different_colors && !different_borders && hidden_side == 0)
+ {
+ double length = 0;
+
+ /* FAST PATH:
+ * Mostly expected to trigger for focus rectangles */
+ for (i = 0; i < 4; i++)
+ {
+ length += _gtk_rounded_box_guess_length (&stroke_box, i);
+ _gtk_rounded_box_path_side (&stroke_box, cr, i);
+ }
+
+ gdk_cairo_set_source_rgba (cr, &colors[0]);
+ set_stroke_style (cr, border->top, stroke_style, length);
+ cairo_stroke (cr);
+ }
+ else
+ {
+ GtkRoundedBox padding_box;
+
+ padding_box = *border_box;
+ _gtk_rounded_box_path (&padding_box, cr);
+ _gtk_rounded_box_shrink (&padding_box,
+ border->top,
+ border->right,
+ border->bottom,
+ border->left);
+
+ for (i = 0; i < 4; i++)
+ {
+ if (hidden_side & (1 << i))
+ continue;
+
+ cairo_save (cr);
+
+ 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);
+ cairo_clip (cr);
+
+ _gtk_rounded_box_path_side (&stroke_box, cr, i);
+
+ gdk_cairo_set_source_rgba (cr, &colors[i]);
+ set_stroke_style (cr,
+ get_border_side (border, i),
+ stroke_style,
+ _gtk_rounded_box_guess_length (&stroke_box, i));
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+ }
+ }
+}
+
+static void
render_frame_internal (GtkThemingEngine *engine,
cairo_t *cr,
gdouble x,
@@ -1539,6 +1691,19 @@ render_frame_internal (GtkThemingEngine *engine,
break;
case GTK_BORDER_STYLE_DOTTED:
case GTK_BORDER_STYLE_DASHED:
+ {
+ guint dont_draw = hidden_side;
+
+ for (j = 0; j < 4; j++)
+ {
+ if (border_style[j] == border_style[i])
+ hidden_side |= (1 << j);
+ else
+ dont_draw |= (1 << j);
+ }
+
+ render_frame_stroke (cr, &border_box, &border, colors, dont_draw, border_style[i]);
+ }
break;
case GTK_BORDER_STYLE_DOUBLE:
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]