[gtk+/gtk-style-context: 111/206] GtkCssProvider: Parse color mappings.



commit c172278cbed39fb18d53801c320d960dd71e5732
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Jun 25 20:27:15 2010 +0200

    GtkCssProvider: Parse color mappings.
    
    These are of the form:
    
    @color-a: #fff;
    @color-b: mix (@color-a, #000, 0.5)
    @color-c: shade (@color-b, 0.7)
    
    In the stylesheet, arbitrary nesting of these commands is handled.

 gtk/gtkcssprovider.c |  273 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 270 insertions(+), 3 deletions(-)
---
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index bd816df..5a8ba4e 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -86,6 +86,8 @@ struct GtkCssProviderPrivate
   GScanner *scanner;
   gchar *filename;
 
+  GHashTable *symbolic_colors;
+
   GPtrArray *selectors_info;
 
   /* Current parser state */
@@ -313,6 +315,10 @@ gtk_css_provider_init (GtkCssProvider *css_provider)
 
   priv->scanner = scanner;
   css_provider_apply_scope (css_provider, SCOPE_SELECTOR);
+
+  priv->symbolic_colors = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                 (GDestroyNotify) g_free,
+                                                 (GDestroyNotify) gtk_symbolic_color_unref);
 }
 
 typedef struct ComparePathData ComparePathData;
@@ -524,6 +530,29 @@ css_provider_get_selectors (GtkCssProvider *css_provider,
   return priority_info;
 }
 
+static void
+css_provider_dump_symbolic_colors (GtkCssProvider *css_provider,
+                                   GtkStyleSet    *set)
+{
+  GtkCssProviderPrivate *priv;
+  GHashTableIter iter;
+  gpointer key, value;
+
+  priv = GTK_CSS_PROVIDER_GET_PRIVATE (css_provider);
+  g_hash_table_iter_init (&iter, priv->symbolic_colors);
+
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      const gchar *name;
+      GtkSymbolicColor *color;
+
+      name = key;
+      color = value;
+
+      gtk_style_set_map_color (set, name, color);
+    }
+}
+
 static GtkStyleSet *
 gtk_css_provider_get_style (GtkStyleProvider *provider,
                             GtkWidgetPath    *path)
@@ -536,6 +565,7 @@ gtk_css_provider_get_style (GtkStyleProvider *provider,
   priv = GTK_CSS_PROVIDER_GET_PRIVATE (provider);
   set = gtk_style_set_new ();
 
+  css_provider_dump_symbolic_colors ((GtkCssProvider *) provider, set);
   priority_info = css_provider_get_selectors (GTK_CSS_PROVIDER (provider), path);
 
   for (i = 0; i < priority_info->len; i++)
@@ -635,6 +665,7 @@ gtk_css_provider_finalize (GObject *object)
   g_slist_free (priv->cur_selectors);
 
   g_hash_table_unref (priv->cur_properties);
+  g_hash_table_destroy (priv->symbolic_colors);
 
   G_OBJECT_CLASS (gtk_css_provider_parent_class)->finalize (object);
 }
@@ -666,13 +697,13 @@ css_provider_apply_scope (GtkCssProvider *css_provider,
 
   if (scope == SCOPE_VALUE)
     {
-      priv->scanner->config->cset_identifier_first = G_CSET_a_2_z "#-_0123456789" G_CSET_A_2_Z;
-      priv->scanner->config->cset_identifier_nth = G_CSET_a_2_z "#-_ 0123456789" G_CSET_A_2_Z;
+      priv->scanner->config->cset_identifier_first = G_CSET_a_2_z "@#-_0123456789" G_CSET_A_2_Z;
+      priv->scanner->config->cset_identifier_nth = G_CSET_a_2_z "@#-_ 0123456789(),." G_CSET_A_2_Z;
       priv->scanner->config->scan_identifier_1char = TRUE;
     }
   else if (scope == SCOPE_SELECTOR)
     {
-      priv->scanner->config->cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "*";
+      priv->scanner->config->cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "*@";
       priv->scanner->config->cset_identifier_nth = G_CSET_a_2_z "-" G_CSET_A_2_Z;
       priv->scanner->config->scan_identifier_1char = TRUE;
     }
@@ -941,6 +972,206 @@ parse_selector (GtkCssProvider  *css_provider,
   return G_TOKEN_NONE;
 }
 
+#define SKIP_SPACES(s) while (s[0] == ' ') s++;
+
+static GtkSymbolicColor *
+symbolic_color_parse_str (const gchar  *string,
+			  gchar       **end_ptr)
+{
+  GtkSymbolicColor *symbolic_color = NULL;
+  gchar *str;
+
+  str = (gchar *) string;
+
+  if (str[0] == '#')
+    {
+      GdkColor color;
+      gchar *color_str;
+      const gchar *end;
+
+      end = str + 1;
+
+      while (g_ascii_isxdigit (*end))
+        end++;
+
+      color_str = g_strndup (str, end - str);
+      *end_ptr = (gchar *) end;
+
+      if (!gdk_color_parse (color_str, &color))
+        {
+          g_free (color_str);
+          return NULL;
+        }
+
+      symbolic_color = gtk_symbolic_color_new_literal (&color);
+      g_free (color_str);
+    }
+  else if (str[0] == '@')
+    {
+      const gchar *end;
+      gchar *name;
+
+      str++;
+      end = str;
+
+      while (*end == '-' || *end == '_' ||
+             g_ascii_isalpha (*end))
+        end++;
+
+      name = g_strndup (str, end - str);
+      symbolic_color = gtk_symbolic_color_new_name (name);
+      g_free (name);
+
+      *end_ptr = (gchar *) end;
+    }
+  else if (g_str_has_prefix (str, "shade"))
+    {
+      GtkSymbolicColor *param_color;
+      gdouble factor;
+
+      str += strlen ("shade");
+
+      SKIP_SPACES (str);
+
+      if (*str != '(')
+        {
+          *end_ptr = (gchar *) str;
+          return NULL;
+        }
+
+      str++;
+      SKIP_SPACES (str);
+      param_color = symbolic_color_parse_str (str, end_ptr);
+
+      if (!param_color)
+        return NULL;
+
+      str = *end_ptr;
+      SKIP_SPACES (str);
+
+      if (str[0] != ',')
+        {
+          gtk_symbolic_color_unref (param_color);
+          *end_ptr = (gchar *) str;
+          return NULL;
+        }
+
+      str++;
+      SKIP_SPACES (str);
+      factor = g_ascii_strtod (str, end_ptr);
+
+      str = *end_ptr;
+      SKIP_SPACES (str);
+      *end_ptr = (gchar *) str;
+
+      if (str[0] != ')')
+        {
+          gtk_symbolic_color_unref (param_color);
+          return NULL;
+        }
+
+      symbolic_color = gtk_symbolic_color_new_shade (param_color, factor);
+      (*end_ptr)++;
+    }
+  else if (g_str_has_prefix (str, "mix"))
+    {
+      GtkSymbolicColor *color1, *color2;
+      gdouble factor;
+
+      str += strlen ("mix");
+      SKIP_SPACES (str);
+
+      if (*str != '(')
+        {
+          *end_ptr = (gchar *) str;
+          return NULL;
+        }
+
+      str++;
+      SKIP_SPACES (str);
+      color1 = symbolic_color_parse_str (str, end_ptr);
+
+      if (!color1)
+        return NULL;
+
+      str = *end_ptr;
+      SKIP_SPACES (str);
+
+      if (str[0] != ',')
+        {
+          gtk_symbolic_color_unref (color1);
+          *end_ptr = (gchar *) str;
+          return NULL;
+        }
+
+      str++;
+      SKIP_SPACES (str);
+      color2 = symbolic_color_parse_str (str, end_ptr);
+
+      if (!color2 || *end_ptr[0] != ',')
+        {
+          gtk_symbolic_color_unref (color1);
+          return NULL;
+        }
+
+      str = *end_ptr;
+      SKIP_SPACES (str);
+
+      if (str[0] != ',')
+        {
+          gtk_symbolic_color_unref (color1);
+          gtk_symbolic_color_unref (color2);
+          *end_ptr = (gchar *) str;
+          return NULL;
+        }
+
+      str++;
+      SKIP_SPACES (str);
+      factor = g_ascii_strtod (str, end_ptr);
+
+      str = *end_ptr;
+      SKIP_SPACES (str);
+      *end_ptr = (gchar *) str;
+
+      if (str[0] != ')')
+	{
+          gtk_symbolic_color_unref (color1);
+          gtk_symbolic_color_unref (color2);
+          return NULL;
+        }
+
+      symbolic_color = gtk_symbolic_color_new_mix (color1, color2, factor);
+      (*end_ptr)++;
+    }
+
+  return symbolic_color;
+}
+
+#undef SKIP_SPACES
+
+static GtkSymbolicColor *
+symbolic_color_parse (const gchar *str)
+{
+  GtkSymbolicColor *color;
+  gchar *end;
+
+  color = symbolic_color_parse_str (str, &end);
+
+  if (*end != '\0')
+    {
+      g_warning ("Error parsing symbolic color \"%s\", stopped at char %ld : '%c'",
+                 str, end - str, *end);
+
+      if (color)
+        {
+          gtk_symbolic_color_unref (color);
+          color = NULL;
+        }
+    }
+
+  return color;
+}
+
 static gboolean
 css_provider_parse_value (const gchar *value_str,
                           GValue      *value)
@@ -1005,6 +1236,42 @@ parse_rule (GtkCssProvider *css_provider,
   priv = GTK_CSS_PROVIDER_GET_PRIVATE (css_provider);
 
   css_provider_push_scope (css_provider, SCOPE_SELECTOR);
+
+  if (scanner->token == G_TOKEN_IDENTIFIER &&
+      scanner->value.v_identifier[0] == '@')
+    {
+      GtkSymbolicColor *color;
+      gchar *color_name;
+
+      /* Rule is a color mapping */
+      color_name = g_strdup (&scanner->value.v_identifier[1]);
+      g_scanner_get_next_token (scanner);
+
+      if (scanner->token != ':')
+        return ':';
+
+      css_provider_push_scope (css_provider, SCOPE_VALUE);
+      g_scanner_get_next_token (scanner);
+
+      if (scanner->token != G_TOKEN_IDENTIFIER)
+        return G_TOKEN_IDENTIFIER;
+
+      color = symbolic_color_parse (scanner->value.v_identifier);
+
+      if (!color)
+        return G_TOKEN_IDENTIFIER;
+
+      g_hash_table_insert (priv->symbolic_colors, color_name, color);
+
+      css_provider_pop_scope (css_provider);
+      g_scanner_get_next_token (scanner);
+
+      if (scanner->token != ';')
+        return ';';
+
+      return G_TOKEN_NONE;
+    }
+
   expected_token = parse_selector (css_provider, scanner, &selector);
 
   if (expected_token != G_TOKEN_NONE)



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