[gnome-shell/nbtk-introduction] Add support for inline styles



commit 0eca3efcb072ef2088453b575e6dd2dd000fb8ab
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Sat Sep 19 22:56:09 2009 -0400

    Add support for inline styles
    
    Add support for passing an inline-style string when creating a
    ShellThemeNode.
    
    Hook this up to a new 'style' property of NbtkWidget.
    
    Add a test case that demonstrates using this to update font sizes
    on the fly.

 src/nbtk/nbtk-widget.c            |   74 ++++++++++++++++++++++++++++++++++++-
 src/nbtk/nbtk-widget.h            |    3 +
 src/toolkit/shell-theme-context.c |    2 +-
 src/toolkit/shell-theme-node.c    |   39 ++++++++++++++++++-
 src/toolkit/shell-theme-node.h    |    3 +-
 src/toolkit/shell-theme-private.h |    6 +--
 src/toolkit/shell-theme.c         |   13 ++----
 src/toolkit/test-theme.c          |   28 ++++++++++----
 tests/interactive/inline-style.js |   47 +++++++++++++++++++++++
 9 files changed, 189 insertions(+), 26 deletions(-)
---
diff --git a/src/nbtk/nbtk-widget.c b/src/nbtk/nbtk-widget.c
index 4cc6c42..7295afe 100644
--- a/src/nbtk/nbtk-widget.c
+++ b/src/nbtk/nbtk-widget.c
@@ -54,6 +54,7 @@ struct _NbtkWidgetPrivate
   ShellThemeNode *theme_node;
   gchar *pseudo_class;
   gchar *style_class;
+  gchar *inline_style;
 
   ClutterActor *border_image;
   ClutterActor *background_image;
@@ -84,6 +85,7 @@ enum
   PROP_THEME,
   PROP_PSEUDO_CLASS,
   PROP_STYLE_CLASS,
+  PROP_STYLE,
 
   PROP_STYLABLE,
 
@@ -126,6 +128,10 @@ nbtk_widget_set_property (GObject      *gobject,
       nbtk_widget_set_style_class_name (actor, g_value_get_string (value));
       break;
 
+    case PROP_STYLE:
+      nbtk_widget_set_style (actor, g_value_get_string (value));
+      break;
+
     case PROP_STYLABLE:
       if (actor->priv->is_stylable != g_value_get_boolean (value))
         {
@@ -171,6 +177,10 @@ nbtk_widget_get_property (GObject    *gobject,
       g_value_set_string (value, priv->style_class);
       break;
 
+    case PROP_STYLE:
+      g_value_set_string (value, priv->inline_style);
+      break;
+
     case PROP_STYLABLE:
       g_value_set_boolean (value, priv->is_stylable);
       break;
@@ -662,7 +672,8 @@ nbtk_widget_get_theme_node (NbtkWidget *widget)
 					       G_OBJECT_TYPE (widget),
 					       clutter_actor_get_name (CLUTTER_ACTOR (widget)),
 					       priv->style_class,
-					       priv->pseudo_class);
+					       priv->pseudo_class,
+					       priv->inline_style);
     }
 
   return priv->theme_node;
@@ -767,6 +778,20 @@ nbtk_widget_class_init (NbtkWidgetClass *klass)
                                                         NBTK_PARAM_READWRITE));
 
   /**
+   * NbtkWidget:style:
+   *
+   * Inline style information for the actor as a ';'-separated list of
+   * CSS properties.
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_STYLE,
+                                   g_param_spec_string ("style",
+                                                        "Style",
+                                                        "Inline style string",
+                                                        "",
+                                                        NBTK_PARAM_READWRITE));
+
+  /**
    * NbtkWidget:theme
    *
    * A theme set on this actor overriding the global theming for this actor
@@ -975,6 +1000,53 @@ nbtk_widget_set_style_pseudo_class (NbtkWidget  *actor,
     }
 }
 
+/**
+ * nbtk_widget_set_style:
+ * @actor: a #NbtkWidget
+ * @style_class: (allow-none): a inline style string, or %NULL
+ *
+ * Set the inline style string for this widget. The inline style string is an
+ * optional ';'-separated list of CSS properties that override the style as
+ * determined from the stylesheets of the current theme.
+ */
+void
+nbtk_widget_set_style (NbtkWidget  *actor,
+		       const gchar *style)
+{
+  NbtkWidgetPrivate *priv = actor->priv;
+
+  g_return_if_fail (NBTK_IS_WIDGET (actor));
+
+  priv = actor->priv;
+
+  if (g_strcmp0 (style, priv->inline_style))
+    {
+      g_free (priv->inline_style);
+      priv->inline_style = g_strdup (style);
+
+      nbtk_widget_style_changed (actor);
+
+      g_object_notify (G_OBJECT (actor), "style");
+    }
+}
+
+/**
+ * nbtk_widget_get_style:
+ * @actor: a #NbtkWidget
+ *
+ * Get the current inline style string. See nbtk_widget_set_style().
+ *
+ * Returns: The inline style string, or %NULL. The string is owned by the
+ * #NbtkWidget and should not be modified or freed.
+ */
+const gchar*
+nbtk_widget_get_style (NbtkWidget *actor)
+{
+  g_return_val_if_fail (NBTK_IS_WIDGET (actor), NULL);
+
+  return actor->priv->inline_style;
+}
+
 static void
 nbtk_widget_name_notify (NbtkWidget *widget,
                          GParamSpec *pspec,
diff --git a/src/nbtk/nbtk-widget.h b/src/nbtk/nbtk-widget.h
index 8d367b0..cc303ad 100644
--- a/src/nbtk/nbtk-widget.h
+++ b/src/nbtk/nbtk-widget.h
@@ -85,6 +85,9 @@ G_CONST_RETURN gchar *nbtk_widget_get_style_pseudo_class (NbtkWidget   *actor);
 void                  nbtk_widget_set_style_class_name   (NbtkWidget   *actor,
                                                           const gchar  *style_class);
 G_CONST_RETURN gchar *nbtk_widget_get_style_class_name   (NbtkWidget   *actor);
+void                  nbtk_widget_set_style              (NbtkWidget   *actor,
+							  const gchar  *style);
+G_CONST_RETURN gchar *nbtk_widget_get_style              (NbtkWidget   *actor);
 
 void        nbtk_widget_set_theme (NbtkWidget *actor,
 				   ShellTheme *theme);
diff --git a/src/toolkit/shell-theme-context.c b/src/toolkit/shell-theme-context.c
index 62ad276..57b7e26 100644
--- a/src/toolkit/shell-theme-context.c
+++ b/src/toolkit/shell-theme-context.c
@@ -212,7 +212,7 @@ shell_theme_context_get_root_node (ShellThemeContext *context)
 {
   if (context->root_node == NULL)
     context->root_node = shell_theme_node_new (context, NULL, context->theme,
-                                               G_TYPE_NONE, NULL, NULL, NULL);
+                                               G_TYPE_NONE, NULL, NULL, NULL, NULL);
 
   return context->root_node;
 }
diff --git a/src/toolkit/shell-theme-node.c b/src/toolkit/shell-theme-node.c
index 474e351..fcf2dcc 100644
--- a/src/toolkit/shell-theme-node.c
+++ b/src/toolkit/shell-theme-node.c
@@ -43,10 +43,15 @@ struct _ShellThemeNode {
   char *element_id;
   char *element_class;
   char *pseudo_class;
+  char *inline_style;
 
   CRDeclaration **properties;
   int n_properties;
 
+  /* We hold onto these separately so we can unref them; the alternative
+   * would be to ref everything in ->properties */
+  CRDeclaration *inline_properties;
+
   guint properties_computed : 1;
   guint borders_computed : 1;
   guint background_computed : 1;
@@ -91,10 +96,12 @@ static void
 shell_theme_node_finalize (GObject *object)
 {
   ShellThemeNode *node = SHELL_THEME_NODE (object);
+  CRDeclaration *cur_decl;
 
   g_free (node->element_id);
   g_free (node->element_class);
   g_free (node->pseudo_class);
+  g_free (node->inline_style);
 
   if (node->properties)
     {
@@ -103,6 +110,9 @@ shell_theme_node_finalize (GObject *object)
       node->n_properties = 0;
     }
 
+  for (cur_decl = node->inline_properties; cur_decl; cur_decl = cur_decl->next)
+    cr_declaration_unref (cur_decl);
+
   if (node->font_desc)
     {
       pango_font_description_free (node->font_desc);
@@ -128,7 +138,8 @@ shell_theme_node_new (ShellThemeContext    *context,
                       GType                 element_type,
                       const char           *element_id,
                       const char           *element_class,
-                      const char           *pseudo_class)
+                      const char           *pseudo_class,
+                      const char           *inline_style)
 {
   ShellThemeNode *node;
 
@@ -153,6 +164,7 @@ shell_theme_node_new (ShellThemeContext    *context,
   node->element_id = g_strdup (element_id);
   node->element_class = g_strdup (element_class);
   node->pseudo_class = g_strdup (pseudo_class);
+  node->inline_style = g_strdup (inline_style);
 
   return node;
 }
@@ -227,11 +239,32 @@ ensure_properties (ShellThemeNode *node)
 {
   if (!node->properties_computed)
     {
+      GPtrArray *properties = NULL;
+
       node->properties_computed = TRUE;
 
       if (node->theme)
-        _shell_theme_get_matched_properties (node->theme, node,
-                                             &node->properties, &node->n_properties);
+        properties = _shell_theme_get_matched_properties (node->theme, node);
+
+      if (node->inline_style)
+        {
+          CRDeclaration *cur_decl;
+
+          if (!properties)
+            properties = g_ptr_array_new ();
+
+          node->inline_properties = cr_declaration_parse_list_from_buf ((const guchar *)node->inline_style,
+                                                                        CR_UTF_8);
+
+          for (cur_decl = node->inline_properties; cur_decl; cur_decl = cur_decl->next)
+            g_ptr_array_add (properties, cur_decl);
+        }
+
+      if (properties)
+        {
+          node->n_properties = properties->len;
+          node->properties = (CRDeclaration **)g_ptr_array_free (properties, FALSE);
+        }
     }
 }
 
diff --git a/src/toolkit/shell-theme-node.h b/src/toolkit/shell-theme-node.h
index b98b037..489295e 100644
--- a/src/toolkit/shell-theme-node.h
+++ b/src/toolkit/shell-theme-node.h
@@ -46,7 +46,8 @@ ShellThemeNode *shell_theme_node_new (ShellThemeContext *context,
                                       GType              element_type,
                                       const char        *element_id,
                                       const char        *element_class,
-                                      const char        *pseudo_class);
+                                      const char        *pseudo_class,
+                                      const char        *inline_style);
 
 ShellThemeNode *shell_theme_node_get_parent (ShellThemeNode *node);
 
diff --git a/src/toolkit/shell-theme-private.h b/src/toolkit/shell-theme-private.h
index 214e94d..18c9757 100644
--- a/src/toolkit/shell-theme-private.h
+++ b/src/toolkit/shell-theme-private.h
@@ -7,10 +7,8 @@
 
 G_BEGIN_DECLS
 
-void _shell_theme_get_matched_properties (ShellTheme       *theme,
-                                          ShellThemeNode   *node,
-                                          CRDeclaration  ***properties,
-                                          int              *n_properties);
+GPtrArray *_shell_theme_get_matched_properties (ShellTheme       *theme,
+                                                ShellThemeNode   *node);
 
 /* Resolve an URL from the stylesheet to a filename */
 char *_shell_theme_resolve_url (ShellTheme   *theme,
diff --git a/src/toolkit/shell-theme.c b/src/toolkit/shell-theme.c
index b64e15d..e1ab3f7 100644
--- a/src/toolkit/shell-theme.c
+++ b/src/toolkit/shell-theme.c
@@ -940,18 +940,16 @@ compare_declarations (gconstpointer a,
   return 0;
 }
 
-void
+GPtrArray *
 _shell_theme_get_matched_properties (ShellTheme      *theme,
-				     ShellThemeNode  *node,
-				     CRDeclaration ***properties,
-				     int             *n_properties)
+				     ShellThemeNode  *node)
 {
   enum CRStyleOrigin origin = 0;
   CRStyleSheet *sheet = NULL;
   GPtrArray *props = g_ptr_array_new ();
 
-  g_return_if_fail (SHELL_IS_THEME (theme));
-  g_return_if_fail (SHELL_IS_THEME_NODE (node));
+  g_return_val_if_fail (SHELL_IS_THEME (theme), NULL);
+  g_return_val_if_fail (SHELL_IS_THEME_NODE (node), NULL);
 
   for (origin = ORIGIN_UA; origin < NB_ORIGINS; origin++)
     {
@@ -966,8 +964,7 @@ _shell_theme_get_matched_properties (ShellTheme      *theme,
    * after earlier declarations */
   g_ptr_array_sort (props, compare_declarations);
 
-  *n_properties = props->len;
-  *properties = (CRDeclaration **) g_ptr_array_free (props, FALSE);
+  return props;
 }
 
 /* Resolve an url from an url() reference in a stylesheet into an absolute
diff --git a/src/toolkit/test-theme.c b/src/toolkit/test-theme.c
index f2bf3fc..d163344 100644
--- a/src/toolkit/test-theme.c
+++ b/src/toolkit/test-theme.c
@@ -244,6 +244,16 @@ test_pseudo_class (void)
   assert_text_decoration  (group3,  "group3", 0);
 }
 
+static void
+test_inline_style (void)
+{
+  test = "inline_style";
+  /* These properties come from the inline-style specified when creating the node */
+  assert_foreground_color (text3,   "text3",  0x00000ffff);
+  assert_length ("text3", "padding-bottom", 12.,
+		 shell_theme_node_get_padding (text3, SHELL_SIDE_BOTTOM));
+}
+
 int
 main (int argc, char **argv)
 {
@@ -263,21 +273,22 @@ main (int argc, char **argv)
 
   root = shell_theme_context_get_root_node (context);
   group1 = shell_theme_node_new (context, root, NULL,
-				 CLUTTER_TYPE_GROUP, "group1", NULL, NULL);
+				 CLUTTER_TYPE_GROUP, "group1", NULL, NULL, NULL);
   text1 = shell_theme_node_new  (context, group1, NULL,
-				 CLUTTER_TYPE_TEXT, "text1", "special-text", NULL);
+				 CLUTTER_TYPE_TEXT, "text1", "special-text", NULL, NULL);
   text2 = shell_theme_node_new  (context, group1, NULL,
-				 CLUTTER_TYPE_TEXT, "text2", NULL, NULL);
+				 CLUTTER_TYPE_TEXT, "text2", NULL, NULL, NULL);
   group2 = shell_theme_node_new (context, root, NULL,
-				 CLUTTER_TYPE_GROUP, "group2", NULL, NULL);
+				 CLUTTER_TYPE_GROUP, "group2", NULL, NULL, NULL);
   text3 = shell_theme_node_new  (context, group2, NULL,
-				 CLUTTER_TYPE_TEXT, "text3", NULL, NULL);
+				 CLUTTER_TYPE_TEXT, "text3", NULL, NULL,
+                                 "color: #0000ff; padding-bottom: 12px;");
   text4 = shell_theme_node_new  (context, group2, NULL,
-				 CLUTTER_TYPE_TEXT, "text4", NULL, "visited hover");
+				 CLUTTER_TYPE_TEXT, "text4", NULL, "visited hover", NULL);
   group3 = shell_theme_node_new (context, group2, NULL,
-				 CLUTTER_TYPE_GROUP, "group3", NULL, "hover");
+				 CLUTTER_TYPE_GROUP, "group3", NULL, "hover", NULL);
   cairo_texture = shell_theme_node_new (context, root, NULL,
-					CLUTTER_TYPE_CAIRO_TEXTURE, "cairoTexture", NULL, NULL);
+					CLUTTER_TYPE_CAIRO_TEXTURE, "cairoTexture", NULL, NULL, NULL);
 
   test_defaults ();
   test_lengths ();
@@ -287,6 +298,7 @@ main (int argc, char **argv)
   test_background ();
   test_font ();
   test_pseudo_class ();
+  test_inline_style ();
 
   return fail ? 1 : 0;
 }
diff --git a/tests/interactive/inline-style.js b/tests/interactive/inline-style.js
new file mode 100644
index 0000000..366db2b
--- /dev/null
+++ b/tests/interactive/inline-style.js
@@ -0,0 +1,47 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const Clutter = imports.gi.Clutter;
+const Nbtk = imports.gi.Nbtk;
+
+const UI = imports.testcommon.ui;
+
+UI.init();
+let stage = Clutter.Stage.get_default();
+
+let vbox = new Nbtk.BoxLayout({ vertical: true,
+  			        width: stage.width,
+			        height: stage.height });
+stage.add_actor(vbox);
+
+let hbox = new Nbtk.BoxLayout({ spacing: 12 });
+vbox.add(hbox);
+
+let text = new Nbtk.Label({ text: "Styled Text" });
+vbox.add (text);
+
+let size = 24;
+function update_size() {
+    text.style = 'font-size: ' + size + 'pt';
+}
+update_size();
+
+let button = new Nbtk.Button ({ label: 'Smaller',
+                                style: 'padding: 4px; background: #eeddcc' });
+hbox.add (button);
+button.connect('clicked', function() {
+                   size /= 1.2;
+                   update_size ();
+               });
+
+let button = new Nbtk.Button ({ label: 'Bigger',
+                                style: 'padding: 4px; background: #eeddcc' });
+hbox.add (button);
+button.connect('clicked', function() {
+                   size *= 1.2;
+                   update_size ();
+               });
+
+stage.show();
+Clutter.main();
+stage.destroy();
+



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