2007-10-09 Emmanuele Bassi <ebassi@openedhand.com>
authorEmmanuele Bassi <ebassi@openedhand.com>
Tue, 9 Oct 2007 13:29:03 +0000 (13:29 +0000)
committerEmmanuele Bassi <ebassi@openedhand.com>
Tue, 9 Oct 2007 13:29:03 +0000 (13:29 +0000)
* clutter/clutter-script-private.h:
* clutter/clutter-script.h:
* clutter/clutter-script.c: Add licensing information to
the newly added files.

* clutter/clutter-script.c: Support creating behaviours with
ClutterScript. ClutterAlpha objects are implicit, but
timelines can be both explicit objects using their id or
implicit objects. Make the property resolution and translation
more robust. Support the pixbuf property.

* tests/test-script.c: Test the newly added features.

* docs/reference/clutter-docs.sgml:
* docs/reference/clutter-sections.txt: Add ClutterScript.

ChangeLog
clutter/clutter-script-private.h
clutter/clutter-script.c
clutter/clutter-script.h
doc/reference/clutter-docs.sgml
doc/reference/clutter-sections.txt
tests/test-script.c

index 95b4cab..27ebedc 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
 2007-10-09  Emmanuele Bassi  <ebassi@openedhand.com>
 
+       * clutter/clutter-script-private.h:
+       * clutter/clutter-script.h:
+       * clutter/clutter-script.c: Add licensing information to
+       the newly added files.
+
+       * clutter/clutter-script.c: Support creating behaviours with
+       ClutterScript. ClutterAlpha objects are implicit, but
+       timelines can be both explicit objects using their id or
+       implicit objects. Make the property resolution and translation
+       more robust. Support the pixbuf property.
+
+       * tests/test-script.c: Test the newly added features.
+
+       * docs/reference/clutter-docs.sgml:
+       * docs/reference/clutter-sections.txt: Add ClutterScript.
+
+2007-10-09  Emmanuele Bassi  <ebassi@openedhand.com>
+
        * clutter/clutter-fixed.h: Add deprecation guards around
        CLUTTER_FIXED_INT().
 
index 7aee433..ae5a7c7 100644 (file)
@@ -1,3 +1,28 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * 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 __CLUTTER_SCRIPT_PRIVATE_H__
 #define __CLUTTER_SCRIPT_PRIVATE_H__
 
@@ -27,6 +52,10 @@ typedef struct {
 GObject *clutter_script_construct_object (ClutterScript *script,
                                           ObjectInfo    *info);
 
+gboolean clutter_script_enum_from_string (GType          gtype,
+                                          const gchar   *string,
+                                          gint          *enum_value);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_SCRIPT_PRIVATE_H__ */
index 4fa30ec..817f33a 100644 (file)
@@ -1,3 +1,91 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:clutter-script
+ * @short_description: Loads a scene from UI definition data
+ *
+ * #ClutterScript is an object used for loading and building parts or a
+ * complete scenegraph from external definition data in forms of string
+ * buffers or files.
+ *
+ * The UI definition format is JSON, the JavaScript Object Notation as
+ * described by RFC 4627. #ClutterScript can load a JSON data stream,
+ * parse it and build all the objects defined into it. Each object must
+ * have an "id" and a "type" properties defining the name to be used
+ * to retrieve it from #ClutterScript with clutter_script_get_object(),
+ * and the class type to be instanciated. Every other attribute will
+ * be mapped to the class properties.
+ *
+ * A simple object might be defined as:
+ *
+ * <programlisting>
+ * {
+ *   "id"     : "red-button",
+ *   "type"   : "ClutterRectangle",
+ *   "width"  : 100,
+ *   "height" : 100,
+ *   "color"  : "0xff0000ff"
+ * }
+ * </programlisting>
+ *
+ * This will produce a red #ClutterRectangle, 100x100 pixels wide, and
+ * with a name of "red-button"; it can be retrieved by calling:
+ *
+ * <programlisting>
+ * ClutterActor *red_button;
+ *
+ * red_button = CLUTTER_ACTOR (clutter_script_get_object (script, "red-button"));
+ * </programlisting>
+ *
+ * and then manipulated with the Clutter API.
+ *
+ * Packing can be represented using the "children" member, and passing an
+ * array of objects or ids of objects already defined (but not packed: the
+ * packing rules of Clutter still apply).
+ *
+ * Behaviours and timelines can also be defined inside a UI definition
+ * buffer:
+ *
+ * <programlisting>
+ * {
+ *   "id"          : "rotate-behaviour",
+ *   "type"        : "ClutterBehaviourRotate",
+ *   "angle-begin" : 0.0,
+ *   "angle-end"   : 360.0,
+ *   "axis"        : "z-axis",
+ *   "alpha"       : {
+ *     "timeline" : { "num-frames" : 240, "fps" : 60, "loop" : true },
+ *     "function" : "sine"
+ *   }
+ * }
+ * </programlisting>
+ *
+ * #ClutterScript is available since Clutter 0.6
+ */
+
 #include "config.h"
 
 #include <stdlib.h>
@@ -9,8 +97,10 @@
 #include <glib-object.h>
 
 #include "clutter-actor.h"
-#include "clutter-stage.h"
+#include "clutter-alpha.h"
+#include "clutter-behaviour.h"
 #include "clutter-container.h"
+#include "clutter-stage.h"
 
 #include "clutter-script.h"
 #include "clutter-script-private.h"
@@ -38,6 +128,8 @@ struct _ClutterScriptPrivate
 
 G_DEFINE_TYPE (ClutterScript, clutter_script, G_TYPE_OBJECT);
 
+static void object_info_free (gpointer data);
+
 /* tries to map a name in camel case into the corresponding get_type()
  * function, e.g.:
  *
@@ -83,6 +175,47 @@ resolve_type_lazily (const gchar *name)
   return gtype;
 }
 
+static ClutterAlphaFunc
+resolve_alpha_func (const gchar *name)
+{
+  static GModule *module = NULL;
+  ClutterAlphaFunc func;
+  GString *symbol_name = g_string_new ("");
+  char c, *symbol;
+  int i;
+
+  if (!module)
+    module = g_module_open (NULL, 0);
+  
+  if (g_module_symbol (module, name, (gpointer) &func))
+    return func;
+
+  g_string_append (symbol_name, "clutter_");
+
+  for (i = 0; name[i] != '\0'; i++)
+    {
+      c = name[i];
+      /* skip if uppercase, first or previous is uppercase */
+      if ((c == g_ascii_toupper (c) &&
+           i > 0 && name[i-1] != g_ascii_toupper (name[i-1])) ||
+          (i > 2 && name[i]   == g_ascii_toupper (name[i]) &&
+           name[i-1] == g_ascii_toupper (name[i-1]) &&
+           name[i-2] == g_ascii_toupper (name[i-2])))
+        g_string_append_c (symbol_name, '_');
+      g_string_append_c (symbol_name, g_ascii_tolower (c));
+    }
+  g_string_append (symbol_name, "_func");
+  
+  symbol = g_string_free (symbol_name, FALSE);
+
+  if (!g_module_symbol (module, symbol, (gpointer)&func))
+    func = NULL;
+  
+  g_free (symbol);
+
+  return func;
+}
+
 static void
 warn_missing_attribute (ClutterScript *script,
                         const gchar   *id,
@@ -131,6 +264,53 @@ warn_invalid_value (ClutterScript *script,
     }
 }
 
+static ClutterTimeline *
+construct_timeline (ClutterScript *script,
+                    JsonObject    *object)
+{
+  ClutterTimeline *retval = NULL;
+  ObjectInfo *oinfo;
+  GList *members, *l;
+  
+  /* we fake an ObjectInfo so we can reuse clutter_script_construct_object()
+   * here; we do not save it inside the hash table, because if this had
+   * been a named object then we wouldn't have ended up here in the first
+   * place
+   */
+  oinfo = g_slice_new0 (ObjectInfo);
+  oinfo->gtype = CLUTTER_TYPE_TIMELINE;
+
+  members = json_object_get_members (object);
+  for (l = members; l != NULL; l = l->next)
+    {
+      const gchar *name = l->data;
+      JsonNode *node = json_object_get_member (object, name);
+
+      if (JSON_NODE_TYPE (node) == JSON_NODE_VALUE)
+        {
+          PropertyInfo *pinfo = g_slice_new (PropertyInfo);
+          GValue value = { 0, };
+
+          pinfo->property_name = g_strdup (name);
+
+          json_node_get_value (node, &value);
+          g_value_init (&pinfo->value, G_VALUE_TYPE (&value));
+          g_value_transform (&value, &pinfo->value);
+          g_value_unset (&value);
+
+          oinfo->properties = g_list_prepend (oinfo->properties, pinfo);
+        }
+    }
+  g_list_free (members);
+  
+  retval = CLUTTER_TIMELINE (clutter_script_construct_object (script, oinfo));
+
+  g_object_ref (retval);
+  object_info_free (oinfo);
+
+  return retval;
+}
+
 static PropertyInfo *
 parse_member_to_property (ClutterScript *script,
                           ObjectInfo    *info,
@@ -148,11 +328,51 @@ parse_member_to_property (ClutterScript *script,
 
       json_node_get_value (node, &value);
       g_value_init (&retval->value, G_VALUE_TYPE (&value));
-      g_value_copy (&value, &retval->value);
+      g_value_transform (&value, &retval->value);
       g_value_unset (&value);
       break;
 
     case JSON_NODE_OBJECT:
+      if (strcmp (name, "alpha") == 0)
+        {
+          JsonObject *object = json_node_get_object (node);
+          ClutterAlpha *alpha = NULL;
+          ClutterTimeline *timeline = NULL;
+          ClutterAlphaFunc func = NULL;
+          JsonNode *val;
+
+          retval = g_slice_new (PropertyInfo);
+          retval->property_name = g_strdup (name);
+
+          alpha = clutter_alpha_new ();
+          
+          val = json_object_get_member (object, "timeline");
+          if (val)
+            {
+              if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE &&
+                  json_node_get_string (val) != NULL)
+                {
+                  const gchar *id = json_node_get_string (val);
+
+                  timeline = 
+                    CLUTTER_TIMELINE (clutter_script_get_object (script, id));
+                }
+              else if (JSON_NODE_TYPE (val) == JSON_NODE_OBJECT)
+                timeline = construct_timeline (script, json_node_get_object (val));
+            }
+
+          val = json_object_get_member (object, "function");
+          if (val && json_node_get_string (val) != NULL)
+            func = resolve_alpha_func (json_node_get_string (val));
+
+          alpha = g_object_new (CLUTTER_TYPE_ALPHA,
+                                "timeline", timeline,
+                                NULL);
+          clutter_alpha_set_func (alpha, func, NULL, NULL);
+
+          g_value_init (&retval->value, CLUTTER_TYPE_ALPHA);
+          g_value_set_object (&retval->value, G_OBJECT (alpha));
+        }
       break;
 
     case JSON_NODE_ARRAY:
@@ -365,59 +585,150 @@ json_object_end (JsonParser *parser,
   g_hash_table_replace (priv->objects, g_strdup (oinfo->id), oinfo);
 }
 
+/* the property translation sequence is split in two: the first
+ * half is done in parse_member_to_property(), which translates
+ * from JSON data types into valid property types. the second
+ * half is done here, where property types are translated into
+ * the correct type for the given property GType
+ */
 static gboolean
-translate_property (const gchar  *name,
-                    const GValue *src,
-                    GValue       *dest)
+translate_property (ClutterScript *script,
+                    GType          gtype,
+                    const gchar   *name,
+                    const GValue  *src,
+                    GValue        *dest)
 {
+  gboolean retval = FALSE;
+
+  /* colors have a parse function, so we can pass it the
+   * string we get from the parser
+   */
   if (strcmp (name, "color") == 0)
     {
       ClutterColor color = { 0, };
       const gchar *color_str;
 
       if (G_VALUE_HOLDS (src, G_TYPE_STRING))
-        color_str = g_value_get_string (src);
-      else
-        color_str = NULL;
-
-      clutter_color_parse (color_str, &color);
+        {
+          color_str = g_value_get_string (src);
+          clutter_color_parse (color_str, &color);
+        }
 
       g_value_init (dest, CLUTTER_TYPE_COLOR);
       g_value_set_boxed (dest, &color);
 
       return TRUE;
     }
-  else if (strcmp (name, "pixbuf") == 0)
+
+  /* pixbufs are specified using the path to the file name; the
+   * path can be absolute or relative to the current directory.
+   * we need to load the pixbuf from the file and print a
+   * warning here in case it didn't work.
+   */
+  if (strcmp (name, "pixbuf") == 0)
     {
       GdkPixbuf *pixbuf = NULL;
-      const gchar *path;
+      const gchar *string;
+      gchar *path;
+      GError *error;
 
       if (G_VALUE_HOLDS (src, G_TYPE_STRING))
-        path = g_value_get_string (src);
+        string = g_value_get_string (src);
       else
-        path = NULL;
+        return FALSE;
 
-      if (path && g_path_is_absolute (path))
+      if (g_path_is_absolute (string))
+        path = g_strdup (string);
+      else
         {
-          GError *error = NULL;
+          if (script->priv->is_filename)
+            {
+              gchar *dirname;
 
-          pixbuf = gdk_pixbuf_new_from_file (path, &error);
-          if (error)
+              dirname = g_path_get_dirname (script->priv->filename);
+              path = g_build_filename (dirname, string, NULL);
+              
+              g_free (dirname);
+            }
+          else
             {
-              g_warning ("Unable to open pixbuf at path `%s': %s",
-                         path,
-                         error->message);
-              g_error_free (error);
+              gchar *dirname;
+              
+              dirname = g_get_current_dir ();
+              path = g_build_filename (dirname, string, NULL);
+
+              g_free (dirname);
             }
         }
 
+      error = NULL;
+      pixbuf = gdk_pixbuf_new_from_file (path, &error);
+      if (error)
+        {
+          g_warning ("Unable to open pixbuf at path `%s': %s",
+                     path,
+                     error->message);
+          g_error_free (error);
+          g_free (path);
+          return FALSE;
+        }
+
+      CLUTTER_NOTE (SCRIPT, "Setting pixbuf [%p] from file `%s'",
+                    pixbuf,
+                    path);
+      
+      g_free (path);
+      
       g_value_init (dest, GDK_TYPE_PIXBUF);
       g_value_set_object (dest, pixbuf);
 
       return TRUE;
     }
 
-  return FALSE;
+  CLUTTER_NOTE (SCRIPT, "Copying property `%s' to type `%s'",
+                name,
+                g_type_name (gtype));
+
+  /* fall back scenario */
+  g_value_init (dest, gtype);
+
+  switch (G_TYPE_FUNDAMENTAL (gtype))
+    {
+    case G_TYPE_UINT:
+      g_value_set_uint (dest, (guint) g_value_get_int (src));
+      retval = TRUE;
+      break;
+    case G_TYPE_UCHAR:
+      g_value_set_uchar (dest, (guchar) g_value_get_int (src));
+      retval = TRUE;
+      break;
+    case G_TYPE_ENUM:
+      if (G_VALUE_HOLDS (src, G_TYPE_STRING))
+        {
+          const gchar *string = g_value_get_string (src);
+          gint enum_value;
+
+          if (clutter_script_enum_from_string (gtype, string, &enum_value))
+            {
+              g_value_set_enum (dest, enum_value);
+              retval = TRUE;
+            }
+        }
+      else if (G_VALUE_HOLDS (src, G_TYPE_INT))
+        {
+          g_value_set_enum (dest, g_value_get_int (src));
+          retval = TRUE;
+        }
+      break;
+    case G_TYPE_FLAGS:
+      break;
+    default:
+      g_value_copy (src, dest);
+      retval = TRUE;
+      break;
+    }
+
+  return retval;
 }
 
 static void
@@ -451,10 +762,15 @@ translate_properties (ClutterScript  *script,
         }
 
       param.name = pinfo->property_name;
-      if (!translate_property (param.name, &pinfo->value, &param.value))
+      if (!translate_property (script, G_PARAM_SPEC_VALUE_TYPE (pspec),
+                               param.name,
+                               &pinfo->value,
+                               &param.value))
         {
-          g_value_init (&param.value, G_PARAM_SPEC_VALUE_TYPE (pspec));
-          g_value_copy (&pinfo->value, &param.value);
+          g_warning ("Unable to set property `%s' for class `%s'",
+                     pinfo->property_name,
+                     g_type_name (oinfo->gtype));
+          continue;
         }
 
       g_array_append_val (parameters, param);
@@ -525,10 +841,15 @@ construct_stage (ClutterScript *script,
           continue;
         }
 
-      if (!translate_property (name, &pinfo->value, &value))
+      if (!translate_property (script, G_PARAM_SPEC_VALUE_TYPE (pspec),
+                               name,
+                               &pinfo->value,
+                               &value))
         {
-          g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
-          g_value_copy (&pinfo->value, &value);
+          g_warning ("Unable to set property `%s' for class `%s'",
+                     pinfo->property_name,
+                     g_type_name (oinfo->gtype));
+          continue;
         }
 
       g_object_set_property (oinfo->object, name, &value);
@@ -557,33 +878,34 @@ GObject *
 clutter_script_construct_object (ClutterScript *script,
                                  ObjectInfo    *oinfo)
 {
-  GType gtype;
   guint n_params, i;
   GParameter *params;
 
   if (oinfo->object)
     return oinfo->object;
 
-  gtype = resolve_type_lazily (oinfo->class_name);
-  if (gtype == G_TYPE_INVALID)
-    return NULL;
+  if (oinfo->gtype == G_TYPE_INVALID)
+    {
+      oinfo->gtype = resolve_type_lazily (oinfo->class_name);
+      if (oinfo->gtype == G_TYPE_INVALID)
+        return NULL;
+    }
 
   /* the stage is a special case: it's a singleton, it cannot
    * be created by the user and it's owned by the backend. hence,
    * we cannot follow the usual pattern here
    */
-  if (g_type_is_a (gtype, CLUTTER_TYPE_STAGE))
+  if (g_type_is_a (oinfo->gtype, CLUTTER_TYPE_STAGE))
     return construct_stage (script, oinfo);
 
-  oinfo->gtype = gtype;
   params = NULL;
   translate_properties (script, oinfo, &n_params, &params);
 
   CLUTTER_NOTE (SCRIPT, "Creating instance for type `%s' (params:%d)",
-                g_type_name (gtype),
+                g_type_name (oinfo->gtype),
                 n_params);
 
-  oinfo->object = g_object_newv (gtype, n_params, params);
+  oinfo->object = g_object_newv (oinfo->gtype, n_params, params);
 
   for (i = 0; i < n_params; i++)
     {
@@ -593,15 +915,13 @@ clutter_script_construct_object (ClutterScript *script,
 
   g_free (params);
 
-  if (oinfo->children)
-    {
-      if (CLUTTER_IS_CONTAINER (oinfo->object))
-        add_children (script, CLUTTER_CONTAINER (oinfo->object), oinfo->children); 
-    }
+  if (oinfo->children && CLUTTER_IS_CONTAINER (oinfo->object))
+    add_children (script, CLUTTER_CONTAINER (oinfo->object), oinfo->children); 
 
-  g_object_set_data_full (oinfo->object, "clutter-script-name",
-                          g_strdup (oinfo->id),
-                          g_free);
+  if (oinfo->id)
+    g_object_set_data_full (oinfo->object, "clutter-script-name",
+                            g_strdup (oinfo->id),
+                            g_free);
 
   return oinfo->object;
 }
@@ -647,6 +967,7 @@ object_info_free (gpointer data)
         }
       g_list_free (oinfo->properties);
 
+      /* these are ids */
       g_list_foreach (oinfo->children, (GFunc) g_free, NULL);
       g_list_free (oinfo->children);
 
@@ -824,6 +1145,41 @@ clutter_script_get_objects (ClutterScript *script,
 }
 
 gboolean
+clutter_script_enum_from_string (GType        type, 
+                                 const gchar *string,
+                                 gint        *enum_value)
+{
+  GEnumClass *eclass;
+  GEnumValue *ev;
+  gchar *endptr;
+  gint value;
+  gboolean retval = TRUE;
+  
+  g_return_val_if_fail (G_TYPE_IS_ENUM (type), 0);
+  g_return_val_if_fail (string != NULL, 0);
+  
+  value = strtoul (string, &endptr, 0);
+  if (endptr != string) /* parsed a number */
+    *enum_value = value;
+  else
+    {
+      eclass = g_type_class_ref (type);
+      ev = g_enum_get_value_by_name (eclass, string);
+      if (!ev)
+       ev = g_enum_get_value_by_nick (eclass, string);
+
+      if (ev)
+       *enum_value = ev->value;
+      else
+        retval = FALSE;
+      
+      g_type_class_unref (eclass);
+    }
+  
+  return retval;
+}
+
+gboolean
 clutter_script_value_from_data (ClutterScript  *script,
                                 GType           gtype,
                                 const gchar    *data,
@@ -832,3 +1188,9 @@ clutter_script_value_from_data (ClutterScript  *script,
 {
   return FALSE;
 }
+
+GQuark
+clutter_script_error_quark (void)
+{
+  return g_quark_from_static_string ("clutter-script-error");
+}
index f782b09..c1ac9f1 100644 (file)
@@ -1,3 +1,28 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * 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 __CLUTTER_SCRIPT_H__
 #define __CLUTTER_SCRIPT_H__
 
index 62fea69..81e419e 100644 (file)
     <xi:include href="xml/clutter-fixed.xml"/>
     <xi:include href="xml/clutter-version.xml"/>
     <xi:include href="xml/clutter-units.xml"/>
+    <xi:include href="xml/clutter-script.xml"/>
   </part>
 
   <part>
index 97c666e..245cd25 100644 (file)
@@ -1046,3 +1046,28 @@ CLUTTER_BEHAVIOUR_DEPTH_GET_CLASS
 ClutterBehaviourDepthPrivate
 clutter_behaviour_depth_get_type
 </SECTION>
+
+<SECTION>
+<FILE>clutter-script</FILE>
+<TITLE>ClutterScript</TITLE>
+ClutterScript
+ClutterScriptClass
+clutter_script_new
+ClutterScriptError
+clutter_script_load_from_data
+clutter_script_load_from_file
+clutter_script_get_object
+clutter_script_get_objects
+<SUBSECTION Standard>
+CLUTTER_TYPE_SCRIPT
+CLUTTER_SCRIPT
+CLUTTER_IS_SCRIPT
+CLUTTER_SCRIPT_CLASS
+CLUTTER_IS_SCRIPT_CLASS
+CLUTTER_SCRIPT_GET_CLASS
+CLUTTER_SCRIPT_ERROR
+<SUBSECTION Private>
+ClutterScriptPrivate
+clutter_script_get_type
+clutter_script_error_quark
+</SECTION>
index 2cc45d9..c265111 100644 (file)
@@ -5,6 +5,19 @@
 
 #include <clutter/clutter.h>
 
+static const gchar *test_behaviour =
+"{"
+"  \"id\"          : \"rotate-behaviour\","
+"  \"type\"        : \"ClutterBehaviourRotate\","
+"  \"angle-begin\" : 0.0,"
+"  \"angle-end\"   : 360.0,"
+"  \"axis\"        : \"z-axis\","
+"  \"alpha\"       : {"
+"    \"timeline\" : { \"num-frames\" : 300, \"fps\" : 60, \"loop\" : true },"
+"    \"function\" : \"sine\""
+"  }"
+"}";
+
 static const gchar *test_ui =
 "{"
 "  \"Scene\" : {"
@@ -43,6 +56,15 @@ static const gchar *test_ui =
 "        \"width\"    : 100,"
 "        \"height\"   : 100,"
 "        \"visible\"  : true,"
+"      },"
+"      {"
+"        \"id\"       : \"red-hand\","
+"        \"type\"     : \"ClutterTexture\","
+"        \"pixbuf\"   : \"redhand.png\","
+"        \"x\"        : 50,"
+"        \"y\"        : 50,"
+"        \"opacity\"  : 25,"
+"        \"visible\"  : true,"
 "      }"
 "    ]"
 "  }"
@@ -52,14 +74,26 @@ int
 main (int argc, char *argv[])
 {
   ClutterActor *stage;
-  ClutterActor *rect;
+  ClutterActor *texture;
+  ClutterBehaviour *rotate;
   ClutterScript *script;
-  GError *error;
+  GError *error = NULL;
 
   clutter_init (&argc, &argv);
 
   script = clutter_script_new ();
-  error = NULL;
+  g_assert (CLUTTER_IS_SCRIPT (script));
+
+  clutter_script_load_from_data (script, test_behaviour, -1, &error);
+  if (error)
+    {
+      g_print ("*** Error:\n"
+               "***   %s\n", error->message);
+      g_error_free (error);
+      g_object_unref (script);
+      return EXIT_FAILURE;
+    }
+  
   clutter_script_load_from_data (script, test_ui, -1, &error);
   if (error)
     {
@@ -73,6 +107,12 @@ main (int argc, char *argv[])
   stage = CLUTTER_ACTOR (clutter_script_get_object (script, "main-stage"));
   clutter_actor_show (stage);
 
+  texture = CLUTTER_ACTOR (clutter_script_get_object (script, "red-hand"));
+
+  rotate = CLUTTER_BEHAVIOUR (clutter_script_get_object (script, "rotate-behaviour"));
+  clutter_behaviour_apply (rotate, texture);
+  clutter_timeline_start (clutter_alpha_get_timeline (clutter_behaviour_get_alpha (rotate)));
+
   clutter_main ();
 
   g_object_unref (script);