[gtk+] css: Add all border-radius properties



commit 90ff426396da18cbe376377c969466c09b11e136
Author: Benjamin Otte <otte redhat com>
Date:   Thu May 26 03:50:53 2011 +0200

    css: Add all border-radius properties
    
    Implement all border-radisu properties as specified by
    http://www.w3.org/TR/css3-background/#the-border-radius
    The end goal here is to get joined buttons to really look joined.

 gtk/Makefile.am          |    2 +
 gtk/gtkcsstypes.c        |   35 +++++
 gtk/gtkcsstypesprivate.h |   50 ++++++++
 gtk/gtkstyleproperties.c |    6 +
 gtk/gtkstyleproperty.c   |  313 +++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 403 insertions(+), 3 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index a9e623e..19b187a 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -389,6 +389,7 @@ gtk_private_h_sources =		\
 	gtkcssparserprivate.h	\
 	gtkcssproviderprivate.h	\
 	gtkcssselectorprivate.h	\
+	gtkcsstypesprivate.h	\
 	gtkcustompaperunixdialog.h \
 	gtkdndcursors.h		\
 	gtkentryprivate.h	\
@@ -518,6 +519,7 @@ gtk_base_c_sources = 		\
 	gtkcssparser.c		\
 	gtkcssprovider.c	\
 	gtkcssselector.c	\
+	gtkcsstypes.c		\
 	gtkdialog.c		\
 	gtkdrawingarea.c	\
 	gtkeditable.c		\
diff --git a/gtk/gtkcsstypes.c b/gtk/gtkcsstypes.c
new file mode 100644
index 0000000..44b0d28
--- /dev/null
+++ b/gtk/gtkcsstypes.c
@@ -0,0 +1,35 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2011 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gtkcsstypesprivate.h"
+
+#define DEFINE_BOXED_TYPE_WITH_COPY_FUNC(TypeName, type_name) \
+\
+static TypeName * \
+type_name ## _copy (const TypeName *foo) \
+{ \
+  return g_memdup (foo, sizeof (TypeName)); \
+} \
+\
+G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name ## _copy, g_free)
+
+DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderCornerRadius, _gtk_css_border_corner_radius)
+DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderRadius, _gtk_css_border_radius)
diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h
new file mode 100644
index 0000000..db3e274
--- /dev/null
+++ b/gtk/gtkcsstypesprivate.h
@@ -0,0 +1,50 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2011 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_CSS_TYPES_PRIVATE_H__
+#define __GTK_CSS_TYPES_PRIVATE_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GtkCssBorderCornerRadius GtkCssBorderCornerRadius;
+typedef struct _GtkCssBorderRadius GtkCssBorderRadius;
+
+struct _GtkCssBorderCornerRadius {
+  double horizontal;
+  double vertical;
+};
+
+struct _GtkCssBorderRadius {
+  GtkCssBorderCornerRadius top_left;
+  GtkCssBorderCornerRadius top_right;
+  GtkCssBorderCornerRadius bottom_right;
+  GtkCssBorderCornerRadius bottom_left;
+};
+
+#define GTK_TYPE_CSS_BORDER_CORNER_RADIUS _gtk_css_border_corner_radius_get_type ()
+#define GTK_TYPE_CSS_BORDER_RADIUS _gtk_css_border_radius_get_type ()
+
+GType           _gtk_css_border_corner_radius_get_type          (void);
+GType           _gtk_css_border_radius_get_type                 (void);
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_TYPES_PRIVATE_H__ */
diff --git a/gtk/gtkstyleproperties.c b/gtk/gtkstyleproperties.c
index ce7f805..7e1cb29 100644
--- a/gtk/gtkstyleproperties.c
+++ b/gtk/gtkstyleproperties.c
@@ -31,6 +31,7 @@
 #include "gtkanimationdescription.h"
 #include "gtkgradient.h"
 #include "gtkshadowprivate.h"
+#include "gtkcsstypesprivate.h"
 
 #include "gtkstylepropertyprivate.h"
 #include "gtkintl.h"
@@ -512,6 +513,11 @@ _gtk_style_properties_set_property_by_property (GtkStyleProperties     *props,
       g_return_if_fail (value_type == CAIRO_GOBJECT_TYPE_PATTERN ||
                         value_type == GTK_TYPE_GRADIENT);
     }
+  else if (style_prop->pspec->value_type == G_TYPE_INT)
+    {
+      g_return_if_fail (value_type == G_TYPE_INT ||
+                        value_type == GTK_TYPE_CSS_BORDER_RADIUS);
+    }
   else
     g_return_if_fail (style_prop->pspec->value_type == value_type);
 
diff --git a/gtk/gtkstyleproperty.c b/gtk/gtkstyleproperty.c
index 5fa9d77..ee5128f 100644
--- a/gtk/gtkstyleproperty.c
+++ b/gtk/gtkstyleproperty.c
@@ -30,6 +30,7 @@
 
 #include "gtkcssprovider.h"
 #include "gtkcssparserprivate.h"
+#include "gtkcsstypesprivate.h"
 
 /* the actual parsers we have */
 #include "gtkanimationdescription.h"
@@ -1184,6 +1185,216 @@ bindings_value_print (const GValue *value,
     }
 }
 
+static gboolean 
+border_corner_radius_value_parse (GtkCssParser *parser,
+                                  GFile        *base,
+                                  GValue       *value)
+{
+  GtkCssBorderCornerRadius corner;
+
+  if (!_gtk_css_parser_try_double (parser, &corner.horizontal))
+    {
+      _gtk_css_parser_error (parser, "Expected a number");
+      return FALSE;
+    }
+  else if (corner.horizontal < 0)
+    goto negative;
+
+  if (!_gtk_css_parser_try_double (parser, &corner.vertical))
+    corner.vertical = corner.horizontal;
+  else if (corner.vertical < 0)
+    goto negative;
+
+  g_value_set_boxed (value, &corner);
+  return TRUE;
+
+negative:
+  _gtk_css_parser_error (parser, "Border radius values cannot be negative");
+  return FALSE;
+}
+
+static void
+border_corner_radius_value_print (const GValue *value,
+                                  GString      *string)
+{
+  GtkCssBorderCornerRadius *corner;
+
+  corner = g_value_get_boxed (value);
+
+  if (corner == NULL)
+    {
+      g_string_append (string, "none");
+      return;
+    }
+
+  string_append_double (string, corner->horizontal);
+  if (corner->horizontal != corner->vertical)
+    {
+      g_string_append_c (string, ' ');
+      string_append_double (string, corner->vertical);
+    }
+}
+
+static gboolean 
+border_radius_value_parse (GtkCssParser *parser,
+                           GFile        *base,
+                           GValue       *value)
+{
+  GtkCssBorderRadius border;
+
+  if (!_gtk_css_parser_try_double (parser, &border.top_left.horizontal))
+    {
+      _gtk_css_parser_error (parser, "Expected a number");
+      return FALSE;
+    }
+  else if (border.top_left.horizontal < 0)
+    goto negative;
+
+  if (_gtk_css_parser_try_double (parser, &border.top_right.horizontal))
+    {
+      if (border.top_right.horizontal < 0)
+        goto negative;
+      if (_gtk_css_parser_try_double (parser, &border.bottom_right.horizontal))
+        {
+          if (border.bottom_right.horizontal < 0)
+            goto negative;
+          if (!_gtk_css_parser_try_double (parser, &border.bottom_left.horizontal))
+            border.bottom_left.horizontal = border.top_right.horizontal;
+          else if (border.bottom_left.horizontal < 0)
+            goto negative;
+        }
+      else
+        {
+          border.bottom_right.horizontal = border.top_left.horizontal;
+          border.bottom_left.horizontal = border.top_right.horizontal;
+        }
+    }
+  else
+    {
+      border.top_right.horizontal = border.top_left.horizontal;
+      border.bottom_right.horizontal = border.top_left.horizontal;
+      border.bottom_left.horizontal = border.top_left.horizontal;
+    }
+
+  if (_gtk_css_parser_try (parser, "/", TRUE))
+    {
+      if (!_gtk_css_parser_try_double (parser, &border.top_left.vertical))
+        {
+          _gtk_css_parser_error (parser, "Expected a number");
+          return FALSE;
+        }
+      else if (border.top_left.vertical < 0)
+        goto negative;
+
+      if (_gtk_css_parser_try_double (parser, &border.top_right.vertical))
+        {
+          if (border.top_right.vertical < 0)
+            goto negative;
+          if (_gtk_css_parser_try_double (parser, &border.bottom_right.vertical))
+            {
+              if (border.bottom_right.vertical < 0)
+                goto negative;
+              if (!_gtk_css_parser_try_double (parser, &border.bottom_left.vertical))
+                border.bottom_left.vertical = border.top_right.vertical;
+              else if (border.bottom_left.vertical < 0)
+                goto negative;
+            }
+          else
+            {
+              border.bottom_right.vertical = border.top_left.vertical;
+              border.bottom_left.vertical = border.top_right.vertical;
+            }
+        }
+      else
+        {
+          border.top_right.vertical = border.top_left.vertical;
+          border.bottom_right.vertical = border.top_left.vertical;
+          border.bottom_left.vertical = border.top_left.vertical;
+        }
+    }
+  else
+    {
+      border.top_left.vertical = border.top_left.horizontal;
+      border.top_right.vertical = border.top_right.horizontal;
+      border.bottom_right.vertical = border.bottom_right.horizontal;
+      border.bottom_left.vertical = border.bottom_left.horizontal;
+    }
+
+  /* border-radius is an int property for backwards-compat reasons */
+  g_value_unset (value);
+  g_value_init (value, GTK_TYPE_CSS_BORDER_RADIUS);
+  g_value_set_boxed (value, &border);
+
+  return TRUE;
+
+negative:
+  _gtk_css_parser_error (parser, "Border radius values cannot be negative");
+  return FALSE;
+}
+
+static void
+border_radius_value_print (const GValue *value,
+                           GString      *string)
+{
+  GtkCssBorderRadius *border;
+
+  border = g_value_get_boxed (value);
+
+  if (border == NULL)
+    {
+      g_string_append (string, "none");
+      return;
+    }
+
+  string_append_double (string, border->top_left.horizontal);
+  if (border->top_left.horizontal != border->top_right.horizontal ||
+      border->top_left.horizontal != border->bottom_right.horizontal ||
+      border->top_left.horizontal != border->bottom_left.horizontal)
+    {
+      g_string_append_c (string, ' ');
+      string_append_double (string, border->top_right.horizontal);
+      if (border->top_left.horizontal != border->bottom_right.horizontal ||
+          border->top_right.horizontal != border->bottom_left.horizontal)
+        {
+          g_string_append_c (string, ' ');
+          string_append_double (string, border->bottom_right.horizontal);
+          if (border->top_right.horizontal != border->bottom_left.horizontal)
+            {
+              g_string_append_c (string, ' ');
+              string_append_double (string, border->bottom_left.horizontal);
+            }
+        }
+    }
+
+  if (border->top_left.horizontal != border->top_left.vertical ||
+      border->top_right.horizontal != border->top_right.vertical ||
+      border->bottom_right.horizontal != border->bottom_right.vertical ||
+      border->bottom_left.horizontal != border->bottom_left.vertical)
+    {
+      g_string_append (string, " / ");
+      string_append_double (string, border->top_left.vertical);
+      if (border->top_left.vertical != border->top_right.vertical ||
+          border->top_left.vertical != border->bottom_right.vertical ||
+          border->top_left.vertical != border->bottom_left.vertical)
+        {
+          g_string_append_c (string, ' ');
+          string_append_double (string, border->top_right.vertical);
+          if (border->top_left.vertical != border->bottom_right.vertical ||
+              border->top_right.vertical != border->bottom_left.vertical)
+            {
+              g_string_append_c (string, ' ');
+              string_append_double (string, border->bottom_right.vertical);
+              if (border->top_right.vertical != border->bottom_left.vertical)
+                {
+                  g_string_append_c (string, ' ');
+                  string_append_double (string, border->bottom_left.vertical);
+                }
+            }
+        }
+
+    }
+}
+
 /*** PACKING ***/
 
 static GParameter *
@@ -1299,6 +1510,60 @@ pack_margin (GValue             *value,
                "margin-bottom", "margin-right");
 }
 
+static GParameter *
+unpack_border_radius (const GValue *value,
+                      guint        *n_params)
+{
+  GParameter *parameter = g_new0 (GParameter, 4);
+  GtkCssBorderRadius *border;
+  
+  if (G_VALUE_HOLDS_BOXED (value))
+    border = g_value_get_boxed (value);
+  else
+    border = NULL;
+
+  parameter[0].name = "border-top-left-radius";
+  g_value_init (&parameter[0].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
+  parameter[1].name = "border-top-right-radius";
+  g_value_init (&parameter[1].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
+  parameter[2].name = "border-bottom-right-radius";
+  g_value_init (&parameter[2].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
+  parameter[3].name = "border-bottom-left-radius";
+  g_value_init (&parameter[3].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
+  if (border)
+    {
+      g_value_set_boxed (&parameter[0].value, &border->top_left);
+      g_value_set_boxed (&parameter[1].value, &border->top_right);
+      g_value_set_boxed (&parameter[2].value, &border->bottom_right);
+      g_value_set_boxed (&parameter[3].value, &border->bottom_left);
+    }
+
+  *n_params = 4;
+  return parameter;
+}
+
+static void
+pack_border_radius (GValue             *value,
+                    GtkStyleProperties *props,
+                    GtkStateFlags       state)
+{
+  GtkCssBorderCornerRadius *top_left;
+
+  /* NB: We are an int property, so we have to resolve to an int here.
+   * So we just resolve to an int. We pick one and stick to it.
+   * Lesson learned: Don't query border-radius shorthand, query the 
+   * real properties instead. */
+  gtk_style_properties_get (props,
+                            state,
+                            "border-top-left-radius", &top_left,
+                            NULL);
+
+  if (top_left)
+    g_value_set_int (value, top_left->horizontal);
+
+  g_free (top_left);
+}
+
 /*** API ***/
 
 static void
@@ -1627,11 +1892,53 @@ gtk_style_property_init (void)
                                           pack_border_width,
                                           NULL,
                                           NULL);
-  gtk_style_properties_register_property (NULL,
-                                          g_param_spec_int ("border-radius",
+
+  _gtk_style_property_register           (g_param_spec_boxed ("border-top-left-radius",
+                                                              "Border top left radius",
+                                                              "Border radius of top left corner, in pixels",
+                                                              GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0),
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          border_corner_radius_value_parse,
+                                          border_corner_radius_value_print);
+  _gtk_style_property_register           (g_param_spec_boxed ("border-top-right-radius",
+                                                              "Border top right radius",
+                                                              "Border radius of top right corner, in pixels",
+                                                              GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0),
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          border_corner_radius_value_parse,
+                                          border_corner_radius_value_print);
+  _gtk_style_property_register           (g_param_spec_boxed ("border-bottom-right-radius",
+                                                              "Border bottom right radius",
+                                                              "Border radius of bottom right corner, in pixels",
+                                                              GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0),
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          border_corner_radius_value_parse,
+                                          border_corner_radius_value_print);
+  _gtk_style_property_register           (g_param_spec_boxed ("border-bottom-left-radius",
+                                                              "Border bottom left radius",
+                                                              "Border radius of bottom left corner, in pixels",
+                                                              GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0),
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          border_corner_radius_value_parse,
+                                          border_corner_radius_value_print);
+  _gtk_style_property_register           (g_param_spec_int ("border-radius",
                                                             "Border radius",
                                                             "Border radius, in pixels",
-                                                            0, G_MAXINT, 0, 0));
+                                                            0, G_MAXINT, 0, 0),
+                                          NULL,
+                                          unpack_border_radius,
+                                          pack_border_radius,
+                                          border_radius_value_parse,
+                                          border_radius_value_print);
+
   gtk_style_properties_register_property (NULL,
                                           g_param_spec_enum ("border-style",
                                                              "Border style",



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