[gtk+] themingengine: Implement support for multiple border colors



commit 407b3f2cde8ae0807e46a62c53976accdaa20f89
Author: Benjamin Otte <otte redhat com>
Date:   Mon Jun 13 05:04:44 2011 +0200

    themingengine: Implement support for multiple border colors
    
    Also use this support to implement inset and outset border styles
    without cheats.

 gtk/gtkroundedbox.c        |  163 ++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkroundedboxprivate.h |   12 +++
 gtk/gtkthemingengine.c     |  126 +++++++++++++++++++---------------
 3 files changed, 247 insertions(+), 54 deletions(-)
---
diff --git a/gtk/gtkroundedbox.c b/gtk/gtkroundedbox.c
index 3414e48..5b1eefc 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)
@@ -201,6 +220,150 @@ _gtk_rounded_box_path (const GtkRoundedBox *box,
 }
 
 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 bd4adb4..af0854f 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 ceabb69..a779125 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);
-
-      _gtk_rounded_box_path (&border_box, cr);
-      _gtk_rounded_box_path (&padding_box, cr);
-      cairo_clip (cr);
-
-      /* 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));
-
-      /* 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);
 
-      gdk_cairo_set_source_rgba (cr, &border_color);
-      cairo_fill_preserve (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]);
 
-      cairo_rectangle (cr, x, y, width, height);
-      gdk_cairo_set_source_rgba (cr, &lighter);
-      cairo_fill (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;
+
+              gdk_cairo_set_source_rgba (cr, colors[i]);
+
+              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_restore (cr);
+              cairo_fill (cr);
+            }
+        }
+      break;
     }
 
   cairo_restore (cr);
+
+  for (i = 0; i < 4; i++)
+    gdk_rgba_free (colors[i]);
 }
 
 static void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]