mirror of
https://github.com/brl/mutter.git
synced 2024-12-25 04:22:05 +00:00
Merge branch 'animator-parser'
* animator-parser: docs: Describe the Animation definition syntax animator: Provide a ClutterScript parser animator: Allow retrieving type property type from a key script: Use a node when resolving an animation mode
This commit is contained in:
commit
069ba6daf9
2
.gitignore
vendored
2
.gitignore
vendored
@ -245,6 +245,8 @@ TAGS
|
|||||||
/tests/conform/test-behaviours
|
/tests/conform/test-behaviours
|
||||||
/tests/conform/test-cogl-sub-texture
|
/tests/conform/test-cogl-sub-texture
|
||||||
/tests/conform/test-cogl-multitexture
|
/tests/conform/test-cogl-multitexture
|
||||||
|
/tests/conform/test-animator-base
|
||||||
|
/tests/conform/test-animator-properties
|
||||||
/tests/micro-bench/test-text-perf
|
/tests/micro-bench/test-text-perf
|
||||||
/tests/micro-bench/test-text
|
/tests/micro-bench/test-text
|
||||||
/tests/micro-bench/test-picking
|
/tests/micro-bench/test-picking
|
||||||
|
@ -302,25 +302,14 @@ clutter_alpha_parse_custom_node (ClutterScriptable *scriptable,
|
|||||||
*/
|
*/
|
||||||
if (strncmp (name, "mode", 4) == 0)
|
if (strncmp (name, "mode", 4) == 0)
|
||||||
{
|
{
|
||||||
if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
|
gulong mode;
|
||||||
return FALSE;
|
|
||||||
|
mode = clutter_script_resolve_animation_mode (node);
|
||||||
|
|
||||||
g_value_init (value, G_TYPE_ULONG);
|
g_value_init (value, G_TYPE_ULONG);
|
||||||
|
g_value_set_ulong (value, mode);
|
||||||
|
|
||||||
if (json_node_get_value_type (node) == G_TYPE_INT64)
|
return TRUE;
|
||||||
{
|
|
||||||
g_value_set_ulong (value, json_node_get_int (node));
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else if (json_node_get_value_type (node) == G_TYPE_STRING)
|
|
||||||
{
|
|
||||||
const gchar *str = json_node_get_string (node);
|
|
||||||
gulong mode;
|
|
||||||
|
|
||||||
mode = clutter_script_resolve_animation_mode (str);
|
|
||||||
g_value_set_ulong (value, mode);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -403,29 +403,14 @@ clutter_animation_parse_custom_node (ClutterScriptable *scriptable,
|
|||||||
{
|
{
|
||||||
if (strncmp (name, "mode", 4) == 0)
|
if (strncmp (name, "mode", 4) == 0)
|
||||||
{
|
{
|
||||||
if (json_node_get_node_type (node) != JSON_NODE_VALUE)
|
gulong mode;
|
||||||
return FALSE;
|
|
||||||
|
mode = clutter_script_resolve_animation_mode (node);
|
||||||
|
|
||||||
g_value_init (value, G_TYPE_ULONG);
|
g_value_init (value, G_TYPE_ULONG);
|
||||||
|
g_value_set_ulong (value, mode);
|
||||||
|
|
||||||
if (json_node_get_value_type (node) == G_TYPE_INT64)
|
return TRUE;
|
||||||
{
|
|
||||||
g_value_set_ulong (value, json_node_get_int (node));
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else if (json_node_get_value_type (node) == G_TYPE_STRING)
|
|
||||||
{
|
|
||||||
const gchar *str = json_node_get_string (node);
|
|
||||||
gulong mode = CLUTTER_LINEAR;
|
|
||||||
|
|
||||||
mode = clutter_script_resolve_animation_mode (str);
|
|
||||||
g_value_set_ulong (value, mode);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
g_warning ("Expected an integer id or a string id for "
|
|
||||||
"the ClutterAnimation mode property");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -37,6 +37,65 @@
|
|||||||
* through the #ClutterScript definition format, but it comes with a
|
* through the #ClutterScript definition format, but it comes with a
|
||||||
* convenience C API.
|
* convenience C API.
|
||||||
*
|
*
|
||||||
|
* <refsect2 id="ClutterAnimator-script">
|
||||||
|
* <title>ClutterAnimator description for #ClutterScript</title>
|
||||||
|
* <para>#ClutterAnimator defines a custom "properties" property
|
||||||
|
* which allows describing the key frames for objects.</para>
|
||||||
|
* <para>The "properties" property has the following syntax:</para>
|
||||||
|
* <informalexample>
|
||||||
|
* <programlisting>
|
||||||
|
* {
|
||||||
|
* "properties" : [
|
||||||
|
* {
|
||||||
|
* "object" : <id of an object>,
|
||||||
|
* "name" : <name of the property>,
|
||||||
|
* "ease-in" : <boolean>,
|
||||||
|
* "interpolation" : <#ClutterInterpolation value>,
|
||||||
|
* "keys" : [
|
||||||
|
* [ <progress>, <easing mode>, <final value> ]
|
||||||
|
* ]
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
* </programlisting>
|
||||||
|
* </informalexample>
|
||||||
|
* <example id="ClutterAnimator-script-example">
|
||||||
|
* <title>ClutterAnimator definition<title>
|
||||||
|
* <para>The following JSON fragment defines a #ClutterAnimator
|
||||||
|
* with the duration of 1 second and operating on the x and y
|
||||||
|
* properties of a #ClutterActor named "rect-01", with two frames
|
||||||
|
* for each property. The first frame will linearly move the actor
|
||||||
|
* from its current position to the 100, 100 position in 20 percent
|
||||||
|
* of the duration of the animation; the second will using a cubic
|
||||||
|
* easing to move the actor to the 200, 200 coordinates.</para>
|
||||||
|
* <programlisting>
|
||||||
|
* {
|
||||||
|
* "type" : "ClutterAnimator",
|
||||||
|
* "duration" : 1000,
|
||||||
|
* "properties" : [
|
||||||
|
* {
|
||||||
|
* "object" : "rect-01",
|
||||||
|
* "name" : "x",
|
||||||
|
* "ease-in" : true,
|
||||||
|
* "keys" : [
|
||||||
|
* [ 0.2, "linear", 100.0 ],
|
||||||
|
* [ 1.0, "easeOutCubic", 200.0 ]
|
||||||
|
* ]
|
||||||
|
* },
|
||||||
|
* {
|
||||||
|
* "object" : "rect-01",
|
||||||
|
* "name" : "y",
|
||||||
|
* "ease-in" : true,
|
||||||
|
* "keys" : [
|
||||||
|
* [ 0.2, "linear", 100.0 ],
|
||||||
|
* [ 1.0, "easeOutCubic", 200.0 ]
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
* </programlisting>
|
||||||
|
* </example>
|
||||||
|
* </refsect2>
|
||||||
|
*
|
||||||
* #ClutterAnimator is available since Clutter 1.2
|
* #ClutterAnimator is available since Clutter 1.2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -54,8 +113,8 @@
|
|||||||
#include "clutter-enum-types.h"
|
#include "clutter-enum-types.h"
|
||||||
#include "clutter-interval.h"
|
#include "clutter-interval.h"
|
||||||
#include "clutter-private.h"
|
#include "clutter-private.h"
|
||||||
|
#include "clutter-script-private.h"
|
||||||
G_DEFINE_TYPE (ClutterAnimator, clutter_animator, G_TYPE_OBJECT);
|
#include "clutter-scriptable.h"
|
||||||
|
|
||||||
#define CLUTTER_ANIMATOR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ANIMATOR, ClutterAnimatorPrivate))
|
#define CLUTTER_ANIMATOR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ANIMATOR, ClutterAnimatorPrivate))
|
||||||
|
|
||||||
@ -104,6 +163,13 @@ enum
|
|||||||
PROP_DURATION
|
PROP_DURATION
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void clutter_scriptable_init (ClutterScriptableIface *iface);
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_CODE (ClutterAnimator,
|
||||||
|
clutter_animator,
|
||||||
|
G_TYPE_OBJECT,
|
||||||
|
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
|
||||||
|
clutter_scriptable_init));
|
||||||
/**
|
/**
|
||||||
* clutter_animator_new:
|
* clutter_animator_new:
|
||||||
*
|
*
|
||||||
@ -270,10 +336,10 @@ object_disappeared (gpointer data,
|
|||||||
|
|
||||||
static ClutterAnimatorKey *
|
static ClutterAnimatorKey *
|
||||||
clutter_animator_key_new (ClutterAnimator *animator,
|
clutter_animator_key_new (ClutterAnimator *animator,
|
||||||
gdouble progress,
|
|
||||||
GObject *object,
|
GObject *object,
|
||||||
guint mode,
|
const gchar *property_name,
|
||||||
const gchar *property_name)
|
gdouble progress,
|
||||||
|
guint mode)
|
||||||
{
|
{
|
||||||
ClutterAnimatorKey *animator_key;
|
ClutterAnimatorKey *animator_key;
|
||||||
|
|
||||||
@ -771,10 +837,16 @@ clutter_animator_get_timeline (ClutterAnimator *animator)
|
|||||||
ClutterTimeline *
|
ClutterTimeline *
|
||||||
clutter_animator_run (ClutterAnimator *animator)
|
clutter_animator_run (ClutterAnimator *animator)
|
||||||
{
|
{
|
||||||
|
ClutterAnimatorPrivate *priv;
|
||||||
|
|
||||||
g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), NULL);
|
g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), NULL);
|
||||||
clutter_timeline_rewind (animator->priv->timeline);
|
|
||||||
clutter_timeline_start (animator->priv->timeline);
|
priv = animator->priv;
|
||||||
return animator->priv->timeline;
|
|
||||||
|
clutter_timeline_rewind (priv->timeline);
|
||||||
|
clutter_timeline_start (priv->timeline);
|
||||||
|
|
||||||
|
return priv->timeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -915,18 +987,47 @@ clutter_animator_set (ClutterAnimator *animator,
|
|||||||
va_end (args);
|
va_end (args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
clutter_animator_set_key_internal (ClutterAnimator *animator,
|
||||||
|
ClutterAnimatorKey *key)
|
||||||
|
{
|
||||||
|
ClutterAnimatorPrivate *priv = animator->priv;
|
||||||
|
GList *old_item;
|
||||||
|
|
||||||
|
old_item = g_list_find_custom (priv->score, key,
|
||||||
|
sort_actor_prop_progress_func);
|
||||||
|
|
||||||
|
/* replace the key if we already have a similar one */
|
||||||
|
if (old_item != NULL)
|
||||||
|
{
|
||||||
|
ClutterAnimatorKey *old_key = old_item->data;
|
||||||
|
|
||||||
|
clutter_animator_key_free (old_key);
|
||||||
|
|
||||||
|
priv->score = g_list_remove (priv->score, old_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->score = g_list_insert_sorted (priv->score, key,
|
||||||
|
sort_actor_prop_progress_func);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_animator_set_key:
|
* clutter_animator_set_key:
|
||||||
* @animator: a #ClutterAnimator
|
* @animator: a #ClutterAnimator
|
||||||
* @object: a #GObject
|
* @object: a #GObject
|
||||||
* @property_name: the property to specify a key for
|
* @property_name: the property to specify a key for
|
||||||
* @mode: the id of the alpha function to use
|
* @mode: the id of the alpha function to use
|
||||||
* @progress: at which stage of the animation this value applies (range 0.0-1.0)
|
* @progress: the normalized range at which stage of the animation this
|
||||||
|
* value applies
|
||||||
* @value: the value property_name should have at progress.
|
* @value: the value property_name should have at progress.
|
||||||
*
|
*
|
||||||
* As clutter_animator_set but only for a single key.
|
* Sets a single key in the #ClutterAnimator for the @property_name of
|
||||||
|
* @object at @progress.
|
||||||
|
*
|
||||||
|
* See also: clutter_animator_set()
|
||||||
|
*
|
||||||
|
* Return value: (transfer none): The animator instance
|
||||||
*
|
*
|
||||||
* Return value: (transfer none): The animator itself.
|
|
||||||
* Since: 1.2
|
* Since: 1.2
|
||||||
*/
|
*/
|
||||||
ClutterAnimator *
|
ClutterAnimator *
|
||||||
@ -939,7 +1040,6 @@ clutter_animator_set_key (ClutterAnimator *animator,
|
|||||||
{
|
{
|
||||||
ClutterAnimatorPrivate *priv;
|
ClutterAnimatorPrivate *priv;
|
||||||
ClutterAnimatorKey *animator_key;
|
ClutterAnimatorKey *animator_key;
|
||||||
GList *old_item;
|
|
||||||
|
|
||||||
g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), NULL);
|
g_return_val_if_fail (CLUTTER_IS_ANIMATOR (animator), NULL);
|
||||||
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
|
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
|
||||||
@ -949,22 +1049,16 @@ clutter_animator_set_key (ClutterAnimator *animator,
|
|||||||
priv = animator->priv;
|
priv = animator->priv;
|
||||||
property_name = g_intern_string (property_name);
|
property_name = g_intern_string (property_name);
|
||||||
|
|
||||||
animator_key = clutter_animator_key_new (animator, progress, object, mode,
|
animator_key = clutter_animator_key_new (animator,
|
||||||
property_name);
|
object, property_name,
|
||||||
|
progress,
|
||||||
|
mode);
|
||||||
|
|
||||||
g_value_init (&animator_key->value, G_VALUE_TYPE (value));
|
g_value_init (&animator_key->value, G_VALUE_TYPE (value));
|
||||||
g_value_copy (value, &animator_key->value);
|
g_value_copy (value, &animator_key->value);
|
||||||
|
|
||||||
if ((old_item = g_list_find_custom (priv->score, animator_key,
|
clutter_animator_set_key_internal (animator, animator_key);
|
||||||
sort_actor_prop_progress_func)))
|
|
||||||
{
|
|
||||||
ClutterAnimatorKey *old_key = old_item->data;
|
|
||||||
clutter_animator_key_free (old_key);
|
|
||||||
animator->priv->score = g_list_remove (animator->priv->score, old_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->score = g_list_insert_sorted (priv->score, animator_key,
|
|
||||||
sort_actor_prop_progress_func);
|
|
||||||
return animator;
|
return animator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1077,6 +1171,228 @@ again:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct _ParseClosure {
|
||||||
|
ClutterAnimator *animator;
|
||||||
|
ClutterScript *script;
|
||||||
|
|
||||||
|
GValue *value;
|
||||||
|
|
||||||
|
gboolean result;
|
||||||
|
} ParseClosure;
|
||||||
|
|
||||||
|
static ClutterInterpolation
|
||||||
|
resolve_interpolation (JsonNode *node)
|
||||||
|
{
|
||||||
|
if ((JSON_NODE_TYPE (node) != JSON_NODE_VALUE))
|
||||||
|
return CLUTTER_INTERPOLATION_LINEAR;
|
||||||
|
|
||||||
|
if (json_node_get_value_type (node) == G_TYPE_INT64)
|
||||||
|
{
|
||||||
|
return json_node_get_int (node);
|
||||||
|
}
|
||||||
|
else if (json_node_get_value_type (node) == G_TYPE_STRING)
|
||||||
|
{
|
||||||
|
const gchar *str = json_node_get_string (node);
|
||||||
|
gboolean res;
|
||||||
|
gint enum_value;
|
||||||
|
|
||||||
|
res = clutter_script_enum_from_string (CLUTTER_TYPE_INTERPOLATION,
|
||||||
|
str,
|
||||||
|
&enum_value);
|
||||||
|
if (res)
|
||||||
|
return enum_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLUTTER_INTERPOLATION_LINEAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_animator_property (JsonArray *array,
|
||||||
|
guint index_,
|
||||||
|
JsonNode *element,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
ParseClosure *clos = data;
|
||||||
|
JsonObject *object;
|
||||||
|
JsonArray *keys;
|
||||||
|
GObject *gobject;
|
||||||
|
const gchar *id, *pname;
|
||||||
|
GObjectClass *klass;
|
||||||
|
GParamSpec *pspec;
|
||||||
|
GSList *valid_keys = NULL;
|
||||||
|
GList *k;
|
||||||
|
ClutterInterpolation interpolation = CLUTTER_INTERPOLATION_LINEAR;
|
||||||
|
gboolean ease_in = FALSE;
|
||||||
|
|
||||||
|
if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
|
||||||
|
{
|
||||||
|
g_warning ("The 'properties' member of a ClutterAnimator description "
|
||||||
|
"should be an array of objects, but the element %d of the "
|
||||||
|
"array is of type '%s'. The element will be ignored.",
|
||||||
|
index_,
|
||||||
|
json_node_type_name (element));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
object = json_node_get_object (element);
|
||||||
|
|
||||||
|
if (!json_object_has_member (object, "object") ||
|
||||||
|
!json_object_has_member (object, "name") ||
|
||||||
|
!json_object_has_member (object, "keys"))
|
||||||
|
{
|
||||||
|
g_warning ("The property description at index %d is missing one of "
|
||||||
|
"the mandatory fields: object, name and keys",
|
||||||
|
index_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = json_object_get_string_member (object, "object");
|
||||||
|
gobject = clutter_script_get_object (clos->script, id);
|
||||||
|
if (gobject == NULL)
|
||||||
|
{
|
||||||
|
g_warning ("No object with id '%s' has been defined.", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pname = json_object_get_string_member (object, "name");
|
||||||
|
klass = G_OBJECT_GET_CLASS (gobject);
|
||||||
|
pspec = g_object_class_find_property (klass, pname);
|
||||||
|
if (pspec == NULL)
|
||||||
|
{
|
||||||
|
g_warning ("The object of type '%s' and name '%s' has no "
|
||||||
|
"property named '%s'",
|
||||||
|
G_OBJECT_TYPE_NAME (gobject),
|
||||||
|
id,
|
||||||
|
pname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_object_has_member (object, "ease-in"))
|
||||||
|
ease_in = json_object_get_boolean_member (object, "ease-in");
|
||||||
|
|
||||||
|
if (json_object_has_member (object, "interpolation"))
|
||||||
|
{
|
||||||
|
JsonNode *node = json_object_get_member (object, "interpolation");
|
||||||
|
|
||||||
|
interpolation = resolve_interpolation (node);
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = json_object_get_array_member (object, "keys");
|
||||||
|
if (keys == NULL)
|
||||||
|
{
|
||||||
|
g_warning ("The property description at index %d has an invalid "
|
||||||
|
"key field of type '%s' when an array was expected.",
|
||||||
|
index_,
|
||||||
|
json_node_type_name (json_object_get_member (object, "keys")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
valid_keys = NULL;
|
||||||
|
for (k = json_array_get_elements (keys);
|
||||||
|
k != NULL;
|
||||||
|
k = k->next)
|
||||||
|
{
|
||||||
|
JsonNode *node = k->data;
|
||||||
|
JsonArray *key = json_node_get_array (node);
|
||||||
|
ClutterAnimatorKey *animator_key;
|
||||||
|
gdouble progress;
|
||||||
|
gulong mode;
|
||||||
|
GValue *value;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
|
progress = json_array_get_double_element (key, 0);
|
||||||
|
mode = clutter_script_resolve_animation_mode (json_array_get_element (key, 1));
|
||||||
|
|
||||||
|
animator_key = clutter_animator_key_new (clos->animator,
|
||||||
|
gobject,
|
||||||
|
pname,
|
||||||
|
progress,
|
||||||
|
mode);
|
||||||
|
value = &animator_key->value;
|
||||||
|
res = clutter_script_parse_node (clos->script,
|
||||||
|
value,
|
||||||
|
pname,
|
||||||
|
json_array_get_element (key, 2),
|
||||||
|
pspec);
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
g_warning ("Unable to parse the key value for the "
|
||||||
|
"property '%s' (progress: %.2f) at index %d",
|
||||||
|
pname,
|
||||||
|
progress,
|
||||||
|
index_);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
animator_key->ease_in = ease_in;
|
||||||
|
animator_key->interpolation = interpolation;
|
||||||
|
|
||||||
|
valid_keys = g_slist_prepend (valid_keys, animator_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_value_init (clos->value, G_TYPE_POINTER);
|
||||||
|
g_value_set_pointer (clos->value, g_slist_reverse (valid_keys));
|
||||||
|
|
||||||
|
clos->result = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
clutter_animator_parse_custom_node (ClutterScriptable *scriptable,
|
||||||
|
ClutterScript *script,
|
||||||
|
GValue *value,
|
||||||
|
const gchar *name,
|
||||||
|
JsonNode *node)
|
||||||
|
{
|
||||||
|
ParseClosure parse_closure;
|
||||||
|
|
||||||
|
if (strcmp (name, "properties") != 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
parse_closure.animator = CLUTTER_ANIMATOR (scriptable);
|
||||||
|
parse_closure.script = script;
|
||||||
|
parse_closure.value = value;
|
||||||
|
parse_closure.result = FALSE;
|
||||||
|
|
||||||
|
json_array_foreach_element (json_node_get_array (node),
|
||||||
|
parse_animator_property,
|
||||||
|
&parse_closure);
|
||||||
|
|
||||||
|
/* we return TRUE if we had at least one key parsed */
|
||||||
|
|
||||||
|
return parse_closure.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clutter_animator_set_custom_property (ClutterScriptable *scriptable,
|
||||||
|
ClutterScript *script,
|
||||||
|
const gchar *name,
|
||||||
|
const GValue *value)
|
||||||
|
{
|
||||||
|
if (strcmp (name, "properties") == 0)
|
||||||
|
{
|
||||||
|
ClutterAnimator *animator = CLUTTER_ANIMATOR (scriptable);
|
||||||
|
GSList *keys = g_value_get_pointer (value);
|
||||||
|
GSList *k;
|
||||||
|
|
||||||
|
for (k = keys; k != NULL; k = k->next)
|
||||||
|
clutter_animator_set_key_internal (animator, k->data);
|
||||||
|
|
||||||
|
g_slist_free (keys);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
g_object_set_property (G_OBJECT (scriptable), name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clutter_scriptable_init (ClutterScriptableIface *iface)
|
||||||
|
{
|
||||||
|
iface->parse_custom_node = clutter_animator_parse_custom_node;
|
||||||
|
iface->set_custom_property = clutter_animator_set_custom_property;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_animator_set_property (GObject *gobject,
|
clutter_animator_set_property (GObject *gobject,
|
||||||
guint prop_id,
|
guint prop_id,
|
||||||
@ -1340,24 +1656,25 @@ clutter_animator_key_get_type (void)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_animator_key_get_object:
|
* clutter_animator_key_get_object:
|
||||||
* @animator_key: a #ClutterAnimatorKey
|
* @key: a #ClutterAnimatorKey
|
||||||
*
|
*
|
||||||
* Retrieves the object a key applies to.
|
* Retrieves the object a key applies to.
|
||||||
*
|
*
|
||||||
* Return value: the object an animator_key exist for.
|
* Return value: (transfer none): the object an animator_key exist for.
|
||||||
*
|
*
|
||||||
* Since: 1.2
|
* Since: 1.2
|
||||||
*/
|
*/
|
||||||
GObject *
|
GObject *
|
||||||
clutter_animator_key_get_object (ClutterAnimatorKey *animator_key)
|
clutter_animator_key_get_object (const ClutterAnimatorKey *key)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (animator_key, NULL);
|
g_return_val_if_fail (key != NULL, NULL);
|
||||||
return animator_key->object;
|
|
||||||
|
return key->object;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_animator_key_get_property_name:
|
* clutter_animator_key_get_property_name:
|
||||||
* @animator_key: a #ClutterAnimatorKey
|
* @key: a #ClutterAnimatorKey
|
||||||
*
|
*
|
||||||
* Retrieves the name of the property a key applies to.
|
* Retrieves the name of the property a key applies to.
|
||||||
*
|
*
|
||||||
@ -1366,16 +1683,37 @@ clutter_animator_key_get_object (ClutterAnimatorKey *animator_key)
|
|||||||
* Since: 1.2
|
* Since: 1.2
|
||||||
*/
|
*/
|
||||||
G_CONST_RETURN gchar *
|
G_CONST_RETURN gchar *
|
||||||
clutter_animator_key_get_property_name (ClutterAnimatorKey *animator_key)
|
clutter_animator_key_get_property_name (const ClutterAnimatorKey *key)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (animator_key != NULL, NULL);
|
g_return_val_if_fail (key != NULL, NULL);
|
||||||
|
|
||||||
return animator_key->property_name;
|
return key->property_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_animator_key_get_property_type:
|
||||||
|
* @key: a #ClutterAnimatorKey
|
||||||
|
*
|
||||||
|
* Retrieves the #GType of the property a key applies to
|
||||||
|
*
|
||||||
|
* You can use this type to initialize the #GValue to pass to
|
||||||
|
* clutter_animator_key_get_value()
|
||||||
|
*
|
||||||
|
* Return value: the #GType of the property
|
||||||
|
*
|
||||||
|
* Since: 1.2
|
||||||
|
*/
|
||||||
|
GType
|
||||||
|
clutter_animator_key_get_property_type (const ClutterAnimatorKey *key)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (key != NULL, G_TYPE_INVALID);
|
||||||
|
|
||||||
|
return G_VALUE_TYPE (&key->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_animator_key_get_mode:
|
* clutter_animator_key_get_mode:
|
||||||
* @animator_key: a #ClutterAnimatorKey
|
* @key: a #ClutterAnimatorKey
|
||||||
*
|
*
|
||||||
* Retrieves the mode of a #ClutterAnimator key, for the first key of a
|
* Retrieves the mode of a #ClutterAnimator key, for the first key of a
|
||||||
* property for an object this represents the whether the animation is
|
* property for an object this represents the whether the animation is
|
||||||
@ -1387,16 +1725,16 @@ clutter_animator_key_get_property_name (ClutterAnimatorKey *animator_key)
|
|||||||
* Since: 1.2
|
* Since: 1.2
|
||||||
*/
|
*/
|
||||||
gulong
|
gulong
|
||||||
clutter_animator_key_get_mode (ClutterAnimatorKey *animator_key)
|
clutter_animator_key_get_mode (const ClutterAnimatorKey *key)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (animator_key != NULL, 0);
|
g_return_val_if_fail (key != NULL, 0);
|
||||||
|
|
||||||
return animator_key->mode;
|
return key->mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_animator_key_get_progress:
|
* clutter_animator_key_get_progress:
|
||||||
* @animator_key: a #ClutterAnimatorKey
|
* @key: a #ClutterAnimatorKey
|
||||||
*
|
*
|
||||||
* Retrieves the progress of an clutter_animator_key
|
* Retrieves the progress of an clutter_animator_key
|
||||||
*
|
*
|
||||||
@ -1405,31 +1743,52 @@ clutter_animator_key_get_mode (ClutterAnimatorKey *animator_key)
|
|||||||
* Since: 1.2
|
* Since: 1.2
|
||||||
*/
|
*/
|
||||||
gdouble
|
gdouble
|
||||||
clutter_animator_key_get_progress (ClutterAnimatorKey *animator_key)
|
clutter_animator_key_get_progress (const ClutterAnimatorKey *key)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (animator_key != NULL, 0.0);
|
g_return_val_if_fail (key != NULL, 0.0);
|
||||||
|
|
||||||
return animator_key->progress;
|
return key->progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_animator_key_get_value:
|
* clutter_animator_key_get_value:
|
||||||
* @animator_key: a #ClutterAnimatorKey
|
* @key: a #ClutterAnimatorKey
|
||||||
* @value: a #GValue initialized with the correct type for the animator key
|
* @value: a #GValue initialized with the correct type for the animator key
|
||||||
*
|
*
|
||||||
* Retrieves a copy of the value for a #ClutterAnimatorKey.
|
* Retrieves a copy of the value for a #ClutterAnimatorKey.
|
||||||
*
|
*
|
||||||
* The passed in GValue needs to be already initialized for the value type.
|
* The passed in #GValue needs to be already initialized for the value
|
||||||
|
* type of the key or to a type that allow transformation from the value
|
||||||
|
* type of the key.
|
||||||
*
|
*
|
||||||
* Use g_value_unset() when done
|
* Use g_value_unset() when done.
|
||||||
|
*
|
||||||
|
* Return value: %TRUE if the passed #GValue was successfully set, and
|
||||||
|
* %FALSE otherwise
|
||||||
*
|
*
|
||||||
* Since: 1.2
|
* Since: 1.2
|
||||||
*/
|
*/
|
||||||
void
|
gboolean
|
||||||
clutter_animator_key_get_value (ClutterAnimatorKey *animator_key,
|
clutter_animator_key_get_value (const ClutterAnimatorKey *key,
|
||||||
GValue *value)
|
GValue *value)
|
||||||
{
|
{
|
||||||
g_return_if_fail (animator_key != NULL);
|
GType gtype;
|
||||||
|
|
||||||
g_value_copy (&animator_key->value, value);
|
g_return_val_if_fail (key != NULL, FALSE);
|
||||||
|
|
||||||
|
gtype = G_VALUE_TYPE (&key->value);
|
||||||
|
|
||||||
|
if (g_value_type_compatible (gtype, G_VALUE_TYPE (value)))
|
||||||
|
{
|
||||||
|
g_value_copy (&key->value, value);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_value_type_transformable (gtype, G_VALUE_TYPE (value)))
|
||||||
|
{
|
||||||
|
if (g_value_transform (&key->value, value))
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -154,12 +154,13 @@ void clutter_animator_property_set_interpolation (ClutterAnimato
|
|||||||
ClutterInterpolation interpolation);
|
ClutterInterpolation interpolation);
|
||||||
|
|
||||||
GType clutter_animator_key_get_type (void) G_GNUC_CONST;
|
GType clutter_animator_key_get_type (void) G_GNUC_CONST;
|
||||||
GObject * clutter_animator_key_get_object (ClutterAnimatorKey *animator_key);
|
GObject * clutter_animator_key_get_object (const ClutterAnimatorKey *animator_key);
|
||||||
G_CONST_RETURN gchar *clutter_animator_key_get_property_name (ClutterAnimatorKey *animator_key);
|
G_CONST_RETURN gchar *clutter_animator_key_get_property_name (const ClutterAnimatorKey *animator_key);
|
||||||
gulong clutter_animator_key_get_mode (ClutterAnimatorKey *animator_key);
|
GType clutter_animator_key_get_property_type (const ClutterAnimatorKey *animator_key);
|
||||||
gdouble clutter_animator_key_get_progress (ClutterAnimatorKey *animator_key);
|
gulong clutter_animator_key_get_mode (const ClutterAnimatorKey *animator_key);
|
||||||
void clutter_animator_key_get_value (ClutterAnimatorKey *animator_key,
|
gdouble clutter_animator_key_get_progress (const ClutterAnimatorKey *animator_key);
|
||||||
GValue *value);
|
gboolean clutter_animator_key_get_value (const ClutterAnimatorKey *animator_key,
|
||||||
|
GValue *value);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
@ -769,27 +769,40 @@ static const struct
|
|||||||
static const gint n_animation_modes = G_N_ELEMENTS (animation_modes);
|
static const gint n_animation_modes = G_N_ELEMENTS (animation_modes);
|
||||||
|
|
||||||
gulong
|
gulong
|
||||||
clutter_script_resolve_animation_mode (const gchar *name)
|
clutter_script_resolve_animation_mode (JsonNode *node)
|
||||||
{
|
{
|
||||||
gint i, res = 0;
|
gint i, res = CLUTTER_CUSTOM_MODE;
|
||||||
|
|
||||||
/* XXX - we might be able to optimize by changing the ordering
|
if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
|
||||||
* of the animation_modes array, e.g.
|
return CLUTTER_CUSTOM_MODE;
|
||||||
* - special casing linear
|
|
||||||
* - tokenizing ('ease', 'In', 'Sine') and matching on token
|
if (json_node_get_value_type (node) == G_TYPE_INT64)
|
||||||
* - binary searching?
|
return json_node_get_int (node);
|
||||||
*/
|
|
||||||
for (i = 0; i < n_animation_modes; i++)
|
if (json_node_get_value_type (node) == G_TYPE_STRING)
|
||||||
{
|
{
|
||||||
if (strcmp (animation_modes[i].name, name) == 0)
|
const gchar *name = json_node_get_string (node);
|
||||||
return animation_modes[i].mode;
|
|
||||||
|
/* XXX - we might be able to optimize by changing the ordering
|
||||||
|
* of the animation_modes array, e.g.
|
||||||
|
* - special casing linear
|
||||||
|
* - tokenizing ('ease', 'In', 'Sine') and matching on token
|
||||||
|
* - binary searching?
|
||||||
|
*/
|
||||||
|
for (i = 0; i < n_animation_modes; i++)
|
||||||
|
{
|
||||||
|
if (strcmp (animation_modes[i].name, name) == 0)
|
||||||
|
return animation_modes[i].mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clutter_script_enum_from_string (CLUTTER_TYPE_ANIMATION_MODE,
|
||||||
|
name,
|
||||||
|
&res))
|
||||||
|
return res;
|
||||||
|
|
||||||
|
g_warning ("Unable to find the animation mode '%s'", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clutter_script_enum_from_string (CLUTTER_TYPE_ANIMATION_MODE, name, &res))
|
|
||||||
return res;
|
|
||||||
|
|
||||||
g_warning ("Unable to find the animation mode '%s'", name);
|
|
||||||
|
|
||||||
return CLUTTER_CUSTOM_MODE;
|
return CLUTTER_CUSTOM_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -850,8 +863,8 @@ _clutter_script_parse_alpha (ClutterScript *script,
|
|||||||
}
|
}
|
||||||
|
|
||||||
val = json_object_get_member (object, "mode");
|
val = json_object_get_member (object, "mode");
|
||||||
if (val && json_node_get_string (val) != NULL)
|
if (val)
|
||||||
mode = clutter_script_resolve_animation_mode (json_node_get_string (val));
|
mode = clutter_script_resolve_animation_mode (val);
|
||||||
|
|
||||||
if (mode == CLUTTER_CUSTOM_MODE)
|
if (mode == CLUTTER_CUSTOM_MODE)
|
||||||
{
|
{
|
||||||
|
@ -103,7 +103,7 @@ gboolean clutter_script_parse_node (ClutterScript *script,
|
|||||||
GType clutter_script_get_type_from_symbol (const gchar *symbol);
|
GType clutter_script_get_type_from_symbol (const gchar *symbol);
|
||||||
GType clutter_script_get_type_from_class (const gchar *name);
|
GType clutter_script_get_type_from_class (const gchar *name);
|
||||||
|
|
||||||
gulong clutter_script_resolve_animation_mode (const gchar *namer);
|
gulong clutter_script_resolve_animation_mode (JsonNode *node);
|
||||||
|
|
||||||
gboolean clutter_script_enum_from_string (GType gtype,
|
gboolean clutter_script_enum_from_string (GType gtype,
|
||||||
const gchar *string,
|
const gchar *string,
|
||||||
|
@ -45,6 +45,7 @@ test_conformance_SOURCES = \
|
|||||||
test-script-parser.c \
|
test-script-parser.c \
|
||||||
test-actor-destroy.c \
|
test-actor-destroy.c \
|
||||||
test-behaviours.c \
|
test-behaviours.c \
|
||||||
|
test-animator.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
# For convenience, this provides a way to easily run individual unit tests:
|
# For convenience, this provides a way to easily run individual unit tests:
|
||||||
|
88
tests/conform/test-animator.c
Normal file
88
tests/conform/test-animator.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#include <clutter/clutter.h>
|
||||||
|
|
||||||
|
#include "test-conform-common.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
test_animator_properties (TestConformSimpleFixture *fixture,
|
||||||
|
gconstpointer dummy)
|
||||||
|
{
|
||||||
|
ClutterScript *script = clutter_script_new ();
|
||||||
|
GObject *animator = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
gchar *test_file;
|
||||||
|
GList *keys;
|
||||||
|
|
||||||
|
test_file = clutter_test_get_data_file ("test-animator-2.json");
|
||||||
|
clutter_script_load_from_file (script, test_file, &error);
|
||||||
|
if (g_test_verbose () && error)
|
||||||
|
g_print ("Error: %s", error->message);
|
||||||
|
g_assert (error == NULL);
|
||||||
|
|
||||||
|
animator = clutter_script_get_object (script, "animator");
|
||||||
|
g_assert (CLUTTER_IS_ANIMATOR (animator));
|
||||||
|
|
||||||
|
/* get all the keys */
|
||||||
|
keys = clutter_animator_get_keys (CLUTTER_ANIMATOR (animator),
|
||||||
|
NULL, NULL, -1.0);
|
||||||
|
g_assert_cmpint (g_list_length (keys), ==, 3);
|
||||||
|
|
||||||
|
{
|
||||||
|
const ClutterAnimatorKey *key = g_list_nth_data (keys, 1);
|
||||||
|
GValue value = { 0, };
|
||||||
|
|
||||||
|
g_assert (key != NULL);
|
||||||
|
|
||||||
|
if (g_test_verbose ())
|
||||||
|
{
|
||||||
|
g_print ("keys[1] = \n"
|
||||||
|
".object = %s\n"
|
||||||
|
".progress = %.2f\n"
|
||||||
|
".name = '%s'\n"
|
||||||
|
".type = '%s'\n",
|
||||||
|
clutter_get_script_id (clutter_animator_key_get_object (key)),
|
||||||
|
clutter_animator_key_get_progress (key),
|
||||||
|
clutter_animator_key_get_property_name (key),
|
||||||
|
g_type_name (clutter_animator_key_get_property_type (key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (clutter_animator_key_get_object (key) != NULL);
|
||||||
|
g_assert_cmpfloat (clutter_animator_key_get_progress (key), ==, 0.2);
|
||||||
|
g_assert_cmpstr (clutter_animator_key_get_property_name (key), ==, "x");
|
||||||
|
|
||||||
|
g_assert (clutter_animator_key_get_property_type (key) == G_TYPE_FLOAT);
|
||||||
|
|
||||||
|
g_value_init (&value, G_TYPE_FLOAT);
|
||||||
|
g_assert (clutter_animator_key_get_value (key, &value));
|
||||||
|
g_assert_cmpfloat (g_value_get_float (&value), ==, 150.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (keys);
|
||||||
|
g_object_unref (script);
|
||||||
|
g_free (test_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_animator_base (TestConformSimpleFixture *fixture,
|
||||||
|
gconstpointer dummy)
|
||||||
|
{
|
||||||
|
ClutterScript *script = clutter_script_new ();
|
||||||
|
GObject *animator = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
guint duration = 0;
|
||||||
|
gchar *test_file;
|
||||||
|
|
||||||
|
test_file = clutter_test_get_data_file ("test-animator-1.json");
|
||||||
|
clutter_script_load_from_file (script, test_file, &error);
|
||||||
|
if (g_test_verbose () && error)
|
||||||
|
g_print ("Error: %s", error->message);
|
||||||
|
g_assert (error == NULL);
|
||||||
|
|
||||||
|
animator = clutter_script_get_object (script, "animator");
|
||||||
|
g_assert (CLUTTER_IS_ANIMATOR (animator));
|
||||||
|
|
||||||
|
duration = clutter_animator_get_duration (CLUTTER_ANIMATOR (animator));
|
||||||
|
g_assert_cmpint (duration, ==, 1000);
|
||||||
|
|
||||||
|
g_object_unref (script);
|
||||||
|
g_free (test_file);
|
||||||
|
}
|
@ -177,6 +177,8 @@ main (int argc, char **argv)
|
|||||||
TEST_CONFORM_SIMPLE ("/script", test_script_object_property);
|
TEST_CONFORM_SIMPLE ("/script", test_script_object_property);
|
||||||
TEST_CONFORM_SIMPLE ("/script", test_script_animation);
|
TEST_CONFORM_SIMPLE ("/script", test_script_animation);
|
||||||
TEST_CONFORM_SIMPLE ("/script", test_script_named_object);
|
TEST_CONFORM_SIMPLE ("/script", test_script_named_object);
|
||||||
|
TEST_CONFORM_SIMPLE ("/script", test_animator_base);
|
||||||
|
TEST_CONFORM_SIMPLE ("/script", test_animator_properties);
|
||||||
|
|
||||||
TEST_CONFORM_SIMPLE ("/behaviours", test_behaviours);
|
TEST_CONFORM_SIMPLE ("/behaviours", test_behaviours);
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ json_files = \
|
|||||||
test-script-named-object.json \
|
test-script-named-object.json \
|
||||||
test-script-object-property.json \
|
test-script-object-property.json \
|
||||||
test-script-single.json \
|
test-script-single.json \
|
||||||
|
test-animator-1.json \
|
||||||
|
test-animator-2.json \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
png_files = \
|
png_files = \
|
||||||
|
5
tests/data/test-animator-1.json
Normal file
5
tests/data/test-animator-1.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"type" : "ClutterAnimator",
|
||||||
|
"id" : "animator",
|
||||||
|
"duration" : 1000
|
||||||
|
}
|
29
tests/data/test-animator-2.json
Normal file
29
tests/data/test-animator-2.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"type" : "ClutterRectangle",
|
||||||
|
"id" : "foo",
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"width" : 100,
|
||||||
|
"height" : 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "ClutterAnimator",
|
||||||
|
"id" : "animator",
|
||||||
|
"duration" : 1000,
|
||||||
|
|
||||||
|
"properties" : [
|
||||||
|
{
|
||||||
|
"object" : "foo",
|
||||||
|
"name" : "x",
|
||||||
|
"ease-in" : true,
|
||||||
|
"interpolation" : "linear",
|
||||||
|
"keys" : [
|
||||||
|
[ 0.0, "easeInCubic", 100.0 ],
|
||||||
|
[ 0.2, "easeOutCubic", 150.0 ],
|
||||||
|
[ 0.8, "linear", 200.0 ]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user