[gnome-shell] Implement non-uniform borders (when not using corner_radius)



commit 4f456b968959669ce299ffcb6deee47cd0dda00d
Author: Colin Walters <walters verbum org>
Date:   Wed Oct 28 12:53:26 2009 -0400

    Implement non-uniform borders (when not using corner_radius)
    
    StTheme CSS supports different border widths for different sides.  Implement
    it for StWidget by drawing the border internally.  However, we don't support
    a nonzero corner-radius with nonuniform borders.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=599442

 src/st/st-widget.c |  178 ++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 138 insertions(+), 40 deletions(-)
---
diff --git a/src/st/st-widget.c b/src/st/st-widget.c
index c2488ec..d606497 100644
--- a/src/st/st-widget.c
+++ b/src/st/st-widget.c
@@ -63,6 +63,7 @@ struct _StWidgetPrivate
   gboolean      has_tooltip : 1;
   gboolean      is_style_dirty : 1;
   gboolean      draw_bg_color : 1;
+  gboolean      draw_border_internal : 1;
 
   StTooltip    *tooltip;
 };
@@ -356,25 +357,25 @@ static void
 st_widget_real_draw_background (StWidget *self)
 {
   StWidgetPrivate *priv = self->priv;
+  ClutterActor *actor = CLUTTER_ACTOR (self);
+  ClutterActorBox allocation = { 0, };
+  gfloat w, h;
+  guint8 opacity;
+
+  clutter_actor_get_allocation_box (actor, &allocation);
+  w = allocation.x2 - allocation.x1;
+  h = allocation.y2 - allocation.y1;
+
+  opacity = clutter_actor_get_paint_opacity (actor);
 
   /* Default implementation just draws the background
    * colour and the image on top
    */
   if (priv->draw_bg_color)
     {
-      ClutterActor *actor = CLUTTER_ACTOR (self);
-      ClutterActorBox allocation = { 0, };
       ClutterColor bg_color = priv->bg_color;
-      gfloat w, h;
 
-      bg_color.alpha = clutter_actor_get_paint_opacity (actor)
-                       * bg_color.alpha
-                       / 255;
-
-      clutter_actor_get_allocation_box (actor, &allocation);
-
-      w = allocation.x2 - allocation.x1;
-      h = allocation.y2 - allocation.y1;
+      bg_color.alpha = opacity * bg_color.alpha / 255;
 
       cogl_set_source_color4ub (bg_color.red,
                                 bg_color.green,
@@ -383,6 +384,76 @@ st_widget_real_draw_background (StWidget *self)
       cogl_rectangle (0, 0, w, h);
     }
 
+  if (priv->draw_border_internal)
+    {
+      StThemeNode *node = st_widget_get_theme_node (self);
+      int side;
+      double border_top, border_right, border_bottom, border_left;
+
+      border_top = st_theme_node_get_border_width (node, ST_SIDE_TOP);
+      border_right = st_theme_node_get_border_width (node, ST_SIDE_RIGHT);
+      border_bottom = st_theme_node_get_border_width (node, ST_SIDE_BOTTOM);
+      border_left = st_theme_node_get_border_width (node, ST_SIDE_LEFT);
+
+      for (side = 0; side < 4; side++)
+        {
+          ClutterColor color;
+
+          switch (side)
+          {
+            case ST_SIDE_TOP:
+              if (border_top <= 0)
+                continue;
+              break;
+            case ST_SIDE_RIGHT:
+              if (border_right <= 0)
+                continue;
+              break;
+            case ST_SIDE_BOTTOM:
+              if (border_bottom <= 0)
+                continue;
+              break;
+            case ST_SIDE_LEFT:
+              if (border_left <= 0)
+                continue;
+              break;
+          }
+
+          st_theme_node_get_border_color (node, side, &color);
+
+          color.alpha = (color.alpha * opacity) / 0xff;
+
+          cogl_set_source_color4ub (color.red,
+                                    color.green,
+                                    color.blue,
+                                    color.alpha);
+
+          /* Note top and bottom extend to the ends, left/right
+           * are constrained by them.  See comment above about CSS
+           * conformance.
+           */
+          switch (side)
+          {
+            case ST_SIDE_TOP:
+              cogl_rectangle (0, 0,
+                              w, border_top);
+              break;
+            case ST_SIDE_RIGHT:
+              cogl_rectangle (w - border_right, border_top,
+                              w, h - border_bottom);
+              break;
+            case ST_SIDE_BOTTOM:
+              cogl_rectangle (0, h - border_bottom,
+                              w, h);
+              break;
+            case ST_SIDE_LEFT:
+              cogl_rectangle (0, border_top,
+                              border_left, h - border_bottom);
+              break;
+            }
+        }
+    }
+
   if (priv->border_image)
     clutter_actor_paint (priv->border_image);
 }
@@ -491,6 +562,7 @@ st_widget_real_style_changed (StWidget *self)
   ClutterColor border_color = { 0, };
   StSide side;
   StCorner corner;
+  gboolean uniform_border_width;
 
   /* application has request this widget is not stylable */
   if (!priv->is_stylable)
@@ -520,33 +592,6 @@ st_widget_real_style_changed (StWidget *self)
 
   texture_cache = st_texture_cache_get_default ();
 
-  /* StThemeNode supports different widths and colors for different sides
-   * of the border, and different radii for the different corners. We take
-   * the different border widths into account when positioning, but our current
-   * drawing code (using BigRectangle) can only handle a single width, color,
-   * and radius, so we arbitrarily pick the first non-zero width and radius,
-   * and use that.
-   */
-  for (side = ST_SIDE_TOP; side <= ST_SIDE_LEFT; side++)
-    {
-      double width = st_theme_node_get_border_width (theme_node, side);
-      if (width > 0.5)
-	{
-	  border_width = (int)(0.5 + width);
-	  st_theme_node_get_border_color (theme_node, side, &border_color);
-	  break;
-	}
-    }
-
-  for (corner = ST_CORNER_TOPLEFT; corner <= ST_CORNER_BOTTOMLEFT; corner++)
-    {
-      double radius = st_theme_node_get_border_radius (theme_node, corner);
-      if (radius > 0.5)
-	{
-	  border_radius = (int)(0.5 + radius);
-	  break;
-	}
-    }
 
   /* Rough notes about the relationship of borders and backgrounds in CSS3;
    * see http://www.w3.org/TR/css3-background/ for more accurate details.
@@ -565,6 +610,8 @@ st_widget_real_style_changed (StWidget *self)
    *   zero width or a border image is being used.
    *
    * Deviations from the above as implemented here:
+   *  - Nonuniform border widths combined with a non-zero border radius result
+   *    in the border radius being ignored
    *  - The combination of border image and a non-zero border radius is
    *    not supported; the background color will be drawn with square
    *    corners.
@@ -576,6 +623,44 @@ st_widget_real_style_changed (StWidget *self)
    * and a single background image above it.
    */
 
+  /* Check whether all border widths are the same.  Also, acquire the
+   * first nonzero border width as well as the border color.
+   */
+  uniform_border_width = TRUE;
+  border_width = st_theme_node_get_border_width (theme_node, ST_SIDE_TOP);
+  if (border_width > 0.5)
+    border_width = (int)(0.5 + border_width);
+  for (side = 0; side < 4; side++)
+    {
+      double width = st_theme_node_get_border_width (theme_node, side);
+      if (width > 0.5)
+        width = (int)(0.5 + width);
+      if (width > 0)
+        {
+          border_width = width;
+          st_theme_node_get_border_color (theme_node, side, &border_color);
+        }
+      if ((int)width != border_width)
+        {
+          uniform_border_width = FALSE;
+          break;
+        }
+    }
+
+  /* Pick the first nonzero border radius, but only if we have a uniform border. */
+  if (uniform_border_width)
+    {
+      for (corner = 0; corner < 4; corner++)
+        {
+          double radius = st_theme_node_get_border_radius (theme_node, corner);
+          if (radius > 0.5)
+            {
+              border_radius = (int)(0.5 + radius);
+              break;
+            }
+        }
+    }
+
   border_image = st_theme_node_get_border_image (theme_node);
   if (border_image)
     {
@@ -607,9 +692,9 @@ st_widget_real_style_changed (StWidget *self)
       has_changed = TRUE;
       relayout_needed = TRUE;
     }
-  else if ((border_width > 0 && border_color.alpha != 0) ||
-	   (border_radius > 0 && priv->bg_color.alpha != 0))
+  else if (border_radius > 0)
     {
+      priv->draw_border_internal = FALSE;
       priv->draw_bg_color = FALSE;
       priv->border_image = g_object_new (BIG_TYPE_RECTANGLE,
 					 "color", &priv->bg_color,
@@ -623,6 +708,19 @@ st_widget_real_style_changed (StWidget *self)
       has_changed = TRUE;
       relayout_needed = TRUE;
     }
+  else if (border_width > 0 && border_color.alpha != 0)
+    {
+      priv->draw_bg_color = TRUE;
+      priv->draw_border_internal = TRUE;
+      has_changed = TRUE;
+      relayout_needed = TRUE;
+    }
+  else if (priv->draw_border_internal)
+    {
+      priv->draw_border_internal = FALSE;
+      has_changed = TRUE;
+      relayout_needed = TRUE;
+    }
 
   bg_file = st_theme_node_get_background_image (theme_node);
   if (bg_file != NULL)



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