diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index faa9480cc..2f325161b 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -47,6 +47,7 @@ BUILT_SOURCES = $(MARSHALFILES) $(ENUMFILES)
source_h = \
$(srcdir)/clutter-actor.h \
$(srcdir)/clutter-alpha.h \
+ $(srcdir)/clutter-animatable.h \
$(srcdir)/clutter-animation.h \
$(srcdir)/clutter-backend.h \
$(srcdir)/clutter-behaviour.h \
@@ -137,6 +138,7 @@ CLEANFILES = $(STAMPFILES)
source_c = \
clutter-actor.c \
clutter-alpha.c \
+ clutter-animatable.c \
clutter-animation.c \
clutter-backend.c \
clutter-behaviour.c \
diff --git a/clutter/clutter-animatable.c b/clutter/clutter-animatable.c
new file mode 100644
index 000000000..fb2b88b19
--- /dev/null
+++ b/clutter/clutter-animatable.c
@@ -0,0 +1,117 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2009 Intel Corporation.
+ *
+ * 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, see .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+/**
+ * SECTION:clutter-animatable
+ * @short_description: Interface for animatable classes
+ *
+ * #ClutterAnimatable is an interface that allows a #GObject class
+ * to control how a #ClutterAnimation will animate a property.
+ *
+ * Each #ClutterAnimatable should implement the animate_property()
+ * virtual function of the interface to compute the animation state
+ * between two values of an interval depending on a progress factor,
+ * expressed as a floating point value.
+ *
+ * If a #ClutterAnimatable is animated by a #ClutterAnimation
+ * instance, the #ClutterAnimation will call
+ * clutter_animatable_animate_property() passing the name of the
+ * currently animated property; the initial and final values of
+ * the animation interval; the progress factor. The #ClutterAnimatable
+ * implementation should return the computed value for the animated
+ * property.
+ *
+ * #ClutterAnimatable is available since Clutter 1.0
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-animatable.h"
+#include "clutter-debug.h"
+#include "clutter-private.h"
+
+GType
+clutter_animatable_get_type (void)
+{
+ static GType a_type = 0;
+
+ if (G_UNLIKELY (a_type == 0))
+ a_type = g_type_register_static_simple (G_TYPE_INTERFACE,
+ I_("ClutterAnimatable"),
+ sizeof (ClutterAnimatableIface),
+ NULL, 0, NULL, 0);
+
+ return a_type;
+}
+
+/**
+ * clutter_animatable_animate_property:
+ * @animatable: a #ClutterAnimatable
+ * @animation: a #ClutterAnimation
+ * @property_name: the name of the animated property
+ * @initial_value: the initial value of the animation interval
+ * @final_value: the final value of the animation interval
+ * @progress: the progress factor
+ * @value: return location for the animation value
+ *
+ * Calls the animate_property() virtual function for @animatable.
+ *
+ * The @initial_value and @final_value #GValues must contain
+ * the same type; @value must have been initialized to the same
+ * type of @initial_value and @final_value.
+ *
+ * All implementation of the #ClutterAnimatable interface must
+ * implement this function.
+ *
+ * Since: 1.0
+ */
+void
+clutter_animatable_animate_property (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ const GValue *initial_value,
+ const GValue *final_value,
+ gdouble progress,
+ GValue *value)
+{
+ g_return_if_fail (CLUTTER_IS_ANIMATABLE (animatable));
+ g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
+ g_return_if_fail (property_name != NULL);
+ g_return_if_fail (initial_value != NULL && final_value != NULL);
+ g_return_if_fail (G_VALUE_TYPE (initial_value) != G_TYPE_INVALID);
+ g_return_if_fail (G_VALUE_TYPE (final_value) != G_TYPE_INVALID);
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (G_VALUE_TYPE (value) == G_VALUE_TYPE (initial_value) &&
+ G_VALUE_TYPE (value) == G_VALUE_TYPE (final_value));
+
+ CLUTTER_ANIMATABLE_GET_IFACE (animatable)->animate_property (animatable,
+ animation,
+ property_name,
+ initial_value,
+ final_value,
+ progress,
+ value);
+}
diff --git a/clutter/clutter-animatable.h b/clutter/clutter-animatable.h
new file mode 100644
index 000000000..aee717ac4
--- /dev/null
+++ b/clutter/clutter-animatable.h
@@ -0,0 +1,80 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2009 Intel Corporation.
+ *
+ * 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, see .
+ *
+ * Author:
+ * Emmanuele Bassi
+ */
+
+#ifndef __CLUTTER_ANIMATABLE_H__
+#define __CLUTTER_ANIMATABLE_H__
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_ANIMATABLE (clutter_animatable_get_type ())
+#define CLUTTER_ANIMATABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ANIMATABLE, ClutterAnimatable))
+#define CLUTTER_IS_ANIMATABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ANIMATABLE))
+#define CLUTTER_ANIMATABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_ANIMATABLE, ClutterAnimatableIface))
+
+typedef struct _ClutterAnimatable ClutterAnimatable; /* dummy typedef */
+typedef struct _ClutterAnimatableIface ClutterAnimatableIface;
+
+/**
+ * ClutterAnimatableIface:
+ * @animate_property: virtual function for animating a property
+ *
+ * Base interface for #GObjects that can be animated by a
+ * a #ClutterAnimation.
+ *
+ * Since: 1.0
+ */
+struct _ClutterAnimatableIface
+{
+ /*< private >*/
+ GTypeInterface parent_iface;
+
+ /*< public >*/
+ void (* animate_property) (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ const GValue *initial_value,
+ const GValue *final_value,
+ gdouble progress,
+ GValue *value);
+};
+
+GType clutter_animatable_get_type (void) G_GNUC_CONST;
+
+void clutter_animatable_animate_property (ClutterAnimatable *animatable,
+ ClutterAnimation *animation,
+ const gchar *property_name,
+ const GValue *initial_value,
+ const GValue *final_value,
+ gdouble progress,
+ GValue *value);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_ANIMATABLE_H__ */
diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c
index eae81250d..fb5f3c48d 100644
--- a/clutter/clutter-animation.c
+++ b/clutter/clutter-animation.c
@@ -27,12 +27,12 @@
* @short_description: Simple implicit animations
*
* #ClutterAnimation is an object providing simple, implicit animations
- * for #ClutterActors.
+ * for #GObjects.
*
* #ClutterAnimation instances will bind a #GObject property belonging
- * to a #ClutterActor to a #ClutterInterval, and will then use a
- * #ClutterTimeline to interpolate the property between the initial
- * and final values of the interval.
+ * to a #GObject to a #ClutterInterval, and will then use a #ClutterTimeline
+ * to interpolate the property between the initial and final values of the
+ * interval.
*
* For convenience, it is possible to use the clutter_actor_animate()
* function call which will take care of setting up and tearing down
@@ -50,6 +50,7 @@
#include
#include "clutter-alpha.h"
+#include "clutter-animatable.h"
#include "clutter-animation.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
@@ -60,7 +61,7 @@ enum
{
PROP_0,
- PROP_ACTOR,
+ PROP_OBJECT,
PROP_MODE,
PROP_DURATION,
PROP_LOOP,
@@ -79,7 +80,7 @@ enum
struct _ClutterAnimationPrivate
{
- ClutterActor *actor;
+ GObject *object;
GHashTable *properties;
@@ -96,7 +97,7 @@ struct _ClutterAnimationPrivate
static guint animation_signals[LAST_SIGNAL] = { 0, };
-static GQuark quark_actor_animation = 0;
+static GQuark quark_object_animation = 0;
G_DEFINE_TYPE (ClutterAnimation, clutter_animation, G_TYPE_INITIALLY_UNOWNED);
@@ -118,16 +119,14 @@ clutter_animation_dispose (GObject *gobject)
{
ClutterAnimationPrivate *priv = CLUTTER_ANIMATION (gobject)->priv;
- if (priv->actor)
+ if (priv->object)
{
g_object_weak_unref (G_OBJECT (gobject),
on_animation_weak_notify,
- priv->actor);
- g_object_set_qdata (G_OBJECT (priv->actor),
- quark_actor_animation,
- NULL);
- g_object_unref (priv->actor);
- priv->actor = NULL;
+ priv->object);
+ g_object_set_qdata (priv->object, quark_object_animation, NULL);
+ g_object_unref (priv->object);
+ priv->object = NULL;
}
if (priv->timeline)
@@ -168,8 +167,8 @@ clutter_animation_set_property (GObject *gobject,
switch (prop_id)
{
- case PROP_ACTOR:
- clutter_animation_set_actor (animation, g_value_get_object (value));
+ case PROP_OBJECT:
+ clutter_animation_set_object (animation, g_value_get_object (value));
break;
case PROP_MODE:
@@ -208,8 +207,8 @@ clutter_animation_get_property (GObject *gobject,
switch (prop_id)
{
- case PROP_ACTOR:
- g_value_set_object (value, priv->actor);
+ case PROP_OBJECT:
+ g_value_set_object (value, priv->object);
break;
case PROP_MODE:
@@ -253,7 +252,7 @@ clutter_animation_class_init (ClutterAnimationClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
- quark_actor_animation =
+ quark_object_animation =
g_quark_from_static_string ("clutter-actor-animation");
g_type_class_add_private (klass, sizeof (ClutterAnimationPrivate));
@@ -266,18 +265,18 @@ clutter_animation_class_init (ClutterAnimationClass *klass)
gobject_class->finalize = clutter_animation_finalize;
/**
- * ClutterAnimation:actor:
+ * ClutterAnimation:objct:
*
- * The actor to which the animation applies.
+ * The #GObject to which the animation applies.
*
* Since: 1.0
*/
- pspec = g_param_spec_object ("actor",
- "Actor",
- "Actor to which the animation applies",
- CLUTTER_TYPE_ACTOR,
+ pspec = g_param_spec_object ("object",
+ "Object",
+ "Object to which the animation applies",
+ G_TYPE_OBJECT,
CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_ACTOR, pspec);
+ g_object_class_install_property (gobject_class, PROP_OBJECT, pspec);
/**
* ClutterAnimation:mode:
@@ -427,7 +426,7 @@ clutter_animation_update_property_internal (ClutterAnimation *animation,
* @property_name: the property to control
* @interval: a #ClutterInterval
*
- * Binds @interval to the @property_name of the #ClutterActor
+ * Binds @interval to the @property_name of the #GObject
* attached to @animation. The #ClutterAnimation will take
* ownership of the passed #ClutterInterval.
*
@@ -451,10 +450,10 @@ clutter_animation_bind_property (ClutterAnimation *animation,
priv = animation->priv;
- if (G_UNLIKELY (!priv->actor))
+ if (G_UNLIKELY (!priv->object))
{
g_warning ("Cannot bind property `%s': the animation has no "
- "actor set. You need to call clutter_animation_set_actor() "
+ "object set. You need to call clutter_animation_set_object() "
"first to be able to bind a property",
property_name);
return;
@@ -468,14 +467,14 @@ clutter_animation_bind_property (ClutterAnimation *animation,
return;
}
- klass = G_OBJECT_GET_CLASS (priv->actor);
+ klass = G_OBJECT_GET_CLASS (priv->object);
pspec = g_object_class_find_property (klass, property_name);
if (!pspec)
{
- g_warning ("Cannot bind property `%s': actors of type `%s' have "
+ g_warning ("Cannot bind property `%s': objects of type `%s' have "
"no such property",
property_name,
- g_type_name (G_OBJECT_TYPE (priv->actor)));
+ g_type_name (G_OBJECT_TYPE (priv->object)));
return;
}
@@ -592,14 +591,14 @@ clutter_animation_update_property (ClutterAnimation *animation,
return;
}
- klass = G_OBJECT_GET_CLASS (priv->actor);
+ klass = G_OBJECT_GET_CLASS (priv->object);
pspec = g_object_class_find_property (klass, property_name);
if (!pspec)
{
- g_warning ("Cannot bind property `%s': actors of type `%s' have "
+ g_warning ("Cannot bind property `%s': objects of type `%s' have "
"no such property",
property_name,
- g_type_name (G_OBJECT_TYPE (priv->actor)));
+ g_type_name (G_OBJECT_TYPE (priv->object)));
return;
}
@@ -664,10 +663,18 @@ on_alpha_notify (GObject *gobject,
ClutterAnimationPrivate *priv = animation->priv;
GList *properties, *p;
guint32 alpha_value;
+ gboolean is_animatable = FALSE;
+ ClutterAnimatable *animatable = NULL;
alpha_value = clutter_alpha_get_alpha (CLUTTER_ALPHA (gobject));
- g_object_freeze_notify (G_OBJECT (priv->actor));
+ if (CLUTTER_IS_ANIMATABLE (priv->object))
+ {
+ animatable = CLUTTER_ANIMATABLE (priv->object);
+ is_animatable = TRUE;
+ }
+
+ g_object_freeze_notify (priv->object);
properties = g_hash_table_get_keys (priv->properties);
for (p = properties; p != NULL; p = p->next)
@@ -683,16 +690,37 @@ on_alpha_notify (GObject *gobject,
g_value_init (&value, clutter_interval_get_value_type (interval));
factor = (gdouble) alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
- clutter_interval_compute_value (interval, factor, &value);
- g_object_set_property (G_OBJECT (priv->actor), p_name, &value);
+ if (is_animatable)
+ {
+ const GValue *initial, *final;
+
+ initial = clutter_interval_peek_initial_value (interval);
+ final = clutter_interval_peek_final_value (interval);
+
+ CLUTTER_NOTE (ANIMATION, "Animatable property `%s'", p_name);
+ clutter_animatable_animate_property (animatable, animation,
+ p_name,
+ initial, final,
+ factor,
+ &value);
+
+ g_object_set_property (priv->object, p_name, &value);
+ }
+ else
+ {
+ CLUTTER_NOTE (ANIMATION, "Standard property `%s'", p_name);
+
+ if (clutter_interval_compute_value (interval, factor, &value))
+ g_object_set_property (priv->object, p_name, &value);
+ }
g_value_unset (&value);
}
g_list_free (properties);
- g_object_thaw_notify (G_OBJECT (priv->actor));
+ g_object_thaw_notify (priv->object);
}
/*
@@ -709,7 +737,7 @@ on_animation_weak_notify (gpointer data,
clutter_actor_get_gid (CLUTTER_ACTOR (actor)),
actor);
- g_object_set_qdata (actor, quark_actor_animation, NULL);
+ g_object_set_qdata (actor, quark_object_animation, NULL);
}
ClutterAnimation *
@@ -719,66 +747,64 @@ clutter_animation_new (void)
}
/**
- * clutter_animation_set_actor:
+ * clutter_animation_set_object:
* @animation: a #ClutterAnimation
- * @actor: a #ClutterActor
+ * @object: a #GObject
*
- * Attaches @animation to @actor. The #ClutterAnimation will take a
- * reference on @actor.
+ * Attaches @animation to @object. The #ClutterAnimation will take a
+ * reference on @object.
*
* Since: 1.0
*/
void
-clutter_animation_set_actor (ClutterAnimation *animation,
- ClutterActor *actor)
+clutter_animation_set_object (ClutterAnimation *animation,
+ GObject *object)
{
ClutterAnimationPrivate *priv;
g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
- g_return_if_fail (CLUTTER_IS_ACTOR (actor));
+ g_return_if_fail (G_IS_OBJECT (object));
priv = animation->priv;
- g_object_ref (actor);
+ g_object_ref (object);
- if (priv->actor)
+ if (priv->object)
{
g_object_weak_unref (G_OBJECT (animation),
on_animation_weak_notify,
- priv->actor);
- g_object_set_qdata (G_OBJECT (priv->actor),
- quark_actor_animation,
- NULL);
- g_object_unref (priv->actor);
+ priv->object);
+ g_object_set_qdata (priv->object, quark_object_animation, NULL);
+ g_object_unref (priv->object);
}
- priv->actor = actor;
+ priv->object = object;
g_object_weak_ref (G_OBJECT (animation),
on_animation_weak_notify,
- priv->actor);
- g_object_set_qdata (G_OBJECT (priv->actor),
- quark_actor_animation,
+ priv->object);
+ g_object_set_qdata (G_OBJECT (priv->object),
+ quark_object_animation,
animation);
- g_object_notify (G_OBJECT (animation), "actor");
+ g_object_notify (G_OBJECT (animation), "object");
}
/**
- * clutter_animation_get_actor:
+ * clutter_animation_get_object:
* @animation: a #ClutterAnimation
*
- * Retrieves the #ClutterActor attached to @animation.
+ * Retrieves the #GObject attached to @animation.
*
- * Return value: a #ClutterActor
+ * Return value: a #GObject
*
* Since: 1.0
*/
-ClutterActor *
-clutter_animation_get_actor (ClutterAnimation *animation)
+GObject *
+clutter_animation_get_object (ClutterAnimation *animation)
{
g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL);
- return animation->priv->actor;
+ return animation->priv->object;
}
static inline void
@@ -1125,7 +1151,7 @@ clutter_animation_setup_valist (ClutterAnimation *animation,
GObjectClass *klass;
const gchar *property_name;
- klass = G_OBJECT_GET_CLASS (priv->actor);
+ klass = G_OBJECT_GET_CLASS (priv->object);
property_name = first_property_name;
while (property_name != NULL)
@@ -1145,10 +1171,10 @@ clutter_animation_setup_valist (ClutterAnimation *animation,
pspec = g_object_class_find_property (klass, property_name);
if (!pspec)
{
- g_warning ("Cannot bind property `%s': actors of type `%s' do "
+ g_warning ("Cannot bind property `%s': objects of type `%s' do "
"not have this property",
property_name,
- g_type_name (G_OBJECT_TYPE (priv->actor)));
+ g_type_name (G_OBJECT_TYPE (priv->object)));
break;
}
@@ -1178,9 +1204,7 @@ clutter_animation_setup_valist (ClutterAnimation *animation,
GValue initial = { 0, };
g_value_init (&initial, G_PARAM_SPEC_VALUE_TYPE (pspec));
- g_object_get_property (G_OBJECT (priv->actor),
- property_name,
- &initial);
+ g_object_get_property (priv->object, property_name, &initial);
interval =
clutter_interval_new_with_values (G_PARAM_SPEC_VALUE_TYPE (pspec),
@@ -1199,7 +1223,7 @@ clutter_animation_setup_valist (ClutterAnimation *animation,
g_value_unset (&initial);
}
else
- g_object_set_property (G_OBJECT (priv->actor), property_name, &final);
+ g_object_set_property (priv->object, property_name, &final);
g_value_unset (&final);
@@ -1254,7 +1278,7 @@ clutter_actor_animate_with_alpha (ClutterActor *actor,
return NULL;
}
- animation = g_object_get_qdata (G_OBJECT (actor), quark_actor_animation);
+ animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation);
if (G_LIKELY (!animation))
{
animation = clutter_animation_new ();
@@ -1265,7 +1289,7 @@ clutter_actor_animate_with_alpha (ClutterActor *actor,
clutter_animation_set_timeline (animation, timeline);
clutter_animation_set_alpha (animation, alpha);
- clutter_animation_set_actor (animation, actor);
+ clutter_animation_set_object (animation, G_OBJECT (actor));
va_start (args, first_property_name);
clutter_animation_setup_valist (animation, first_property_name, args);
@@ -1311,7 +1335,7 @@ clutter_actor_animate_with_timeline (ClutterActor *actor,
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL);
g_return_val_if_fail (first_property_name != NULL, NULL);
- animation = g_object_get_qdata (G_OBJECT (actor), quark_actor_animation);
+ animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation);
if (G_LIKELY (!animation))
{
animation = clutter_animation_new ();
@@ -1323,7 +1347,7 @@ clutter_actor_animate_with_timeline (ClutterActor *actor,
clutter_animation_set_timeline (animation, timeline);
clutter_animation_set_alpha (animation, NULL);
clutter_animation_set_mode (animation, mode);
- clutter_animation_set_actor (animation, actor);
+ clutter_animation_set_object (animation, G_OBJECT (actor));
va_start (args, first_property_name);
clutter_animation_setup_valist (animation, first_property_name, args);
@@ -1406,7 +1430,7 @@ clutter_actor_animate (ClutterActor *actor,
g_return_val_if_fail (duration > 0, NULL);
g_return_val_if_fail (first_property_name != NULL, NULL);
- animation = g_object_get_qdata (G_OBJECT (actor), quark_actor_animation);
+ animation = g_object_get_qdata (G_OBJECT (actor), quark_object_animation);
if (G_LIKELY (!animation))
{
/* if there is no animation already attached to the actor,
@@ -1416,7 +1440,7 @@ clutter_actor_animate (ClutterActor *actor,
animation = clutter_animation_new ();
clutter_animation_set_timeline (animation, NULL);
clutter_animation_set_alpha (animation, NULL);
- clutter_animation_set_actor (animation, actor);
+ clutter_animation_set_object (animation, G_OBJECT (actor));
CLUTTER_NOTE (ANIMATION, "Created new Animation [%p]", animation);
}
diff --git a/clutter/clutter-animation.h b/clutter/clutter-animation.h
index 115e0a0b5..061d4e439 100644
--- a/clutter/clutter-animation.h
+++ b/clutter/clutter-animation.h
@@ -97,9 +97,9 @@ GType clutter_animation_get_type (void) G_GNUC_CONST;
ClutterAnimation * clutter_animation_new (void);
-void clutter_animation_set_actor (ClutterAnimation *animation,
- ClutterActor *actor);
-ClutterActor * clutter_animation_get_actor (ClutterAnimation *animation);
+void clutter_animation_set_object (ClutterAnimation *animation,
+ GObject *object);
+GObject * clutter_animation_get_object (ClutterAnimation *animation);
void clutter_animation_set_mode (ClutterAnimation *animation,
ClutterAnimationMode mode);
ClutterAnimationMode clutter_animation_get_mode (ClutterAnimation *animation);
diff --git a/clutter/clutter-interval.c b/clutter/clutter-interval.c
index 5f2924d09..efdf58dff 100644
--- a/clutter/clutter-interval.c
+++ b/clutter/clutter-interval.c
@@ -57,9 +57,18 @@
#include
#include
+#include "clutter-color.h"
+#include "clutter-fixed.h"
#include "clutter-interval.h"
#include "clutter-units.h"
-#include "clutter-fixed.h"
+
+typedef struct
+{
+ GType value_type;
+ ClutterProgressFunc func;
+} ProgressData;
+
+static GHashTable *progress_funcs = NULL;
enum
{
@@ -171,19 +180,39 @@ clutter_interval_real_validate (ClutterInterval *interval,
return TRUE;
}
-static void
+static gboolean
clutter_interval_real_compute_value (ClutterInterval *interval,
gdouble factor,
GValue *value)
{
GValue *initial, *final;
GType value_type;
+ gboolean retval = FALSE;
initial = clutter_interval_peek_initial_value (interval);
final = clutter_interval_peek_final_value (interval);
value_type = clutter_interval_get_value_type (interval);
+ if (G_UNLIKELY (progress_funcs != NULL))
+ {
+ ProgressData *p_data;
+
+ p_data =
+ g_hash_table_lookup (progress_funcs, GUINT_TO_POINTER (value_type));
+
+ /* if we have a progress function, and that function was
+ * successful in computing the progress, then we bail out
+ * as fast as we can
+ */
+ if (p_data != NULL)
+ {
+ retval = p_data->func (initial, final, factor, value);
+ if (retval)
+ return retval;
+ }
+ }
+
switch (G_TYPE_FUNDAMENTAL (value_type))
{
case G_TYPE_INT:
@@ -196,6 +225,8 @@ clutter_interval_real_compute_value (ClutterInterval *interval,
res = (factor * (ib - ia)) + ia;
g_value_set_int (value, res);
+
+ retval = TRUE;
}
break;
@@ -209,6 +240,8 @@ clutter_interval_real_compute_value (ClutterInterval *interval,
res = (factor * (ib - (gdouble) ia)) + ia;
g_value_set_uint (value, res);
+
+ retval = TRUE;
}
break;
@@ -222,6 +255,8 @@ clutter_interval_real_compute_value (ClutterInterval *interval,
res = (factor * (ib - (gdouble) ia)) + ia;
g_value_set_uchar (value, res);
+
+ retval = TRUE;
}
break;
@@ -239,6 +274,8 @@ clutter_interval_real_compute_value (ClutterInterval *interval,
g_value_set_double (value, res);
else
g_value_set_float (value, res);
+
+ retval = TRUE;
}
break;
@@ -247,11 +284,35 @@ clutter_interval_real_compute_value (ClutterInterval *interval,
g_value_set_boolean (value, TRUE);
else
g_value_set_boolean (value, FALSE);
+
+ retval = TRUE;
+ break;
+
+ case G_TYPE_BOXED:
+ if (value_type == CLUTTER_TYPE_COLOR)
+ {
+ const ClutterColor *ia, *ib;
+ ClutterColor res = { 0, };
+
+ ia = clutter_value_get_color (initial);
+ ib = clutter_value_get_color (final);
+
+ res.red = (factor * (ib->red - (gdouble) ia->red)) + ia->red;
+ res.green = (factor * (ib->green - (gdouble) ia->green)) + ia->green;
+ res.blue = (factor * (ib->blue - (gdouble) ia->blue)) + ia->blue;
+ res.alpha = (factor * (ib->alpha - (gdouble) ia->alpha)) + ia->alpha;
+
+ clutter_value_set_color (value, &res);
+
+ retval = TRUE;
+ }
break;
default:
break;
}
+
+ return retval;
}
static void
@@ -818,19 +879,99 @@ clutter_interval_validate (ClutterInterval *interval,
* Computes the value between the @interval boundaries given the
* progress @factor and puts it into @value.
*
+ * Return value: %TRUE if the operation was successful
+ *
* Since: 1.0
*/
-void
+gboolean
clutter_interval_compute_value (ClutterInterval *interval,
gdouble factor,
GValue *value)
{
- g_return_if_fail (CLUTTER_IS_INTERVAL (interval));
- g_return_if_fail (value != NULL);
+ g_return_val_if_fail (CLUTTER_IS_INTERVAL (interval), FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
factor = CLAMP (factor, 0.0, 1.0);
- CLUTTER_INTERVAL_GET_CLASS (interval)->compute_value (interval,
- factor,
- value);
+ return CLUTTER_INTERVAL_GET_CLASS (interval)->compute_value (interval,
+ factor,
+ value);
+}
+
+/**
+ * clutter_interval_register_progress_func:
+ * @value_type: a #GType
+ * @func: a #ClutterProgressFunc, or %NULL to unset a previously
+ * set progress function
+ *
+ * Sets the progress function for a given @value_type, like:
+ *
+ * |[
+ * clutter_interval_register_progress_func (MY_TYPE_FOO,
+ * my_foo_progress);
+ * ]|
+ *
+ * Whenever a #ClutterInterval instance using the default
+ * #ClutterInterval::compute_value implementation is set as an
+ * interval between two #GValue of type @value_type, it will call
+ * @func to establish the value depending on the given progress,
+ * for instance:
+ *
+ * |[
+ * static gboolean
+ * my_int_progress (const GValue *a,
+ * const GValue *b,
+ * gdouble progress,
+ * GValue *retval)
+ * {
+ * gint ia = g_value_get_int (a);
+ * gint ib = g_value_get_int (b);
+ * gint res = factor * (ib - ia) + ia;
+ *
+ * g_value_set_int (retval, res);
+ *
+ * return TRUE;
+ * }
+ *
+ * clutter_interval_register_progress_func (G_TYPE_INT, my_int_progress);
+ * ]|
+ *
+ * To unset a previously set progress function of a #GType, pass %NULL
+ * for @func.
+ *
+ * Since: 1.0
+ */
+void
+clutter_interval_register_progress_func (GType value_type,
+ ClutterProgressFunc func)
+{
+ ProgressData *progress_func;
+
+ g_return_if_fail (value_type != G_TYPE_INVALID);
+
+ if (G_UNLIKELY (progress_funcs == NULL))
+ progress_funcs = g_hash_table_new (NULL, NULL);
+
+ progress_func =
+ g_hash_table_lookup (progress_funcs, GUINT_TO_POINTER (value_type));
+ if (G_UNLIKELY (progress_func))
+ {
+ if (func == NULL)
+ {
+ g_hash_table_remove (progress_funcs, GUINT_TO_POINTER (value_type));
+ g_slice_free (ProgressData, progress_func);
+ }
+ else
+ progress_func->func = func;
+ }
+ else
+ {
+ progress_func = g_slice_new (ProgressData);
+ progress_func->value_type = value_type;
+ progress_func->func = func;
+
+ g_hash_table_replace (progress_funcs,
+ GUINT_TO_POINTER (value_type),
+ progress_func);
+ }
}
diff --git a/clutter/clutter-interval.h b/clutter/clutter-interval.h
index 56d155f28..72ae5304c 100644
--- a/clutter/clutter-interval.h
+++ b/clutter/clutter-interval.h
@@ -44,6 +44,34 @@ typedef struct _ClutterInterval ClutterInterval;
typedef struct _ClutterIntervalPrivate ClutterIntervalPrivate;
typedef struct _ClutterIntervalClass ClutterIntervalClass;
+/**
+ * ClutterProgressFunc:
+ * @a: the initial value of an interval
+ * @b: the final value of an interval
+ * @progress: the progress factor, between 0 and 1
+ * @retval: the value used to store the progress
+ *
+ * Prototype of the progress function used to compute the value
+ * between the two ends @a and @b of an interval depending on
+ * the value of @progress.
+ *
+ * The #GValue in @retval is already initialized with the same
+ * type as @a and @b.
+ *
+ * This function will be called by #ClutterInterval if the
+ * type of the values of the interval was registered using
+ * clutter_interval_register_progress_func().
+ *
+ * Return value: %TRUE if the function successfully computed
+ * the value and stored it inside @retval
+ *
+ * Since: 1.0
+ */
+typedef gboolean (* ClutterProgressFunc) (const GValue *a,
+ const GValue *b,
+ gdouble progress,
+ GValue *retval);
+
/**
* ClutterInterval:
*
@@ -79,7 +107,7 @@ struct _ClutterIntervalClass
/*< public >*/
gboolean (* validate) (ClutterInterval *interval,
GParamSpec *pspec);
- void (* compute_value) (ClutterInterval *interval,
+ gboolean (* compute_value) (ClutterInterval *interval,
gdouble factor,
GValue *value);
@@ -122,10 +150,13 @@ void clutter_interval_get_interval (ClutterInterval *interval,
gboolean clutter_interval_validate (ClutterInterval *interval,
GParamSpec *pspec);
-void clutter_interval_compute_value (ClutterInterval *interval,
+gboolean clutter_interval_compute_value (ClutterInterval *interval,
gdouble factor,
GValue *value);
+void clutter_interval_register_progress_func (GType value_type,
+ ClutterProgressFunc func);
+
G_END_DECLS
#endif /* __CLUTTER_INTERVAL_H__ */
diff --git a/clutter/clutter.h b/clutter/clutter.h
index 817dbef6c..8306ee50a 100644
--- a/clutter/clutter.h
+++ b/clutter/clutter.h
@@ -30,6 +30,7 @@
#include "clutter-actor.h"
#include "clutter-alpha.h"
+#include "clutter-animatable.h"
#include "clutter-animation.h"
#include "clutter-backend.h"
#include "clutter-behaviour-depth.h"
diff --git a/doc/reference/clutter/clutter-docs.xml b/doc/reference/clutter/clutter-docs.xml
index baeb0b5bf..a9ecc8a0f 100644
--- a/doc/reference/clutter/clutter-docs.xml
+++ b/doc/reference/clutter/clutter-docs.xml
@@ -105,6 +105,7 @@
+
diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt
index 3f0a8429f..6f3864908 100644
--- a/doc/reference/clutter/clutter-sections.txt
+++ b/doc/reference/clutter/clutter-sections.txt
@@ -169,6 +169,35 @@ ClutterCloneTexturePrivate
clutter_clone_texture_get_type
+
+clutter-cairo-texture
+ClutterCairoTexture
+ClutterCairoTexture
+ClutterCairoTextureClass
+clutter_cairo_texture_new
+clutter_cairo_texture_set_surface_size
+clutter_cairo_texture_get_surface_size
+
+
+clutter_cairo_texture_create
+clutter_cairo_texture_create_region
+
+
+clutter_cairo_set_source_color
+
+
+CLUTTER_TYPE_CAIRO_TEXTURE
+CLUTTER_CAIRO_TEXTURE
+CLUTTER_IS_CAIRO_TEXTURE
+CLUTTER_CAIRO_TEXTURE_CLASS
+CLUTTER_IS_CAIRO_TEXTURE_CLASS
+CLUTTER_CAIRO_TEXTURE_GET_CLASS
+
+
+ClutterCairoTexturePrivate
+clutter_cairo_texture_get_type
+
+
clutter-group
ClutterGroup
@@ -1507,8 +1536,8 @@ ClutterAnimation
ClutterAnimationClass
ClutterAnimationMode
clutter_animation_new
-clutter_animation_set_actor
-clutter_animation_get_actor
+clutter_animation_set_object
+clutter_animation_get_object
clutter_animation_set_mode
clutter_animation_get_mode
clutter_animation_set_duration
@@ -1567,6 +1596,10 @@ clutter_interval_get_interval
clutter_interval_compute_value
clutter_interval_validate
+
+ClutterProgressFunc
+clutter_interval_register_progress_func
+
CLUTTER_TYPE_INTERVAL
CLUTTER_INTERVAL
@@ -1688,6 +1721,23 @@ ClutterTextPrivate
clutter_text_get_type
+
+clutter-animatable
+ClutterAnimatable
+ClutterAnimatable
+ClutterAnimatableIface
+clutter_animatable_animate_property
+
+
+CLUTTER_TYPE_ANIMATABLE
+CLUTTER_ANIMATABLE
+CLUTTER_IS_ANIMATABLE
+CLUTTER_ANIMATABLE_GET_IFACE
+
+
+clutter_animatable_get_type
+
+
Key Bindings
clutter-binding-pool
diff --git a/doc/reference/clutter/clutter.types b/doc/reference/clutter/clutter.types
index f59698f02..c4fc972dc 100644
--- a/doc/reference/clutter/clutter.types
+++ b/doc/reference/clutter/clutter.types
@@ -28,3 +28,4 @@ clutter_shader_get_type
clutter_child_meta_get_type
clutter_cairo_texture_get_type
clutter_text_get_type
+clutter_animatable_get_type
diff --git a/tests/interactive/test-animation.c b/tests/interactive/test-animation.c
index 000e02bd8..ee0ff7337 100644
--- a/tests/interactive/test-animation.c
+++ b/tests/interactive/test-animation.c
@@ -23,13 +23,12 @@ on_button_press (ClutterActor *actor,
ClutterAnimation *animation;
gint old_x, old_y, new_x, new_y;
guint old_width, old_height, new_width, new_height;
- guint8 old_op, new_op;
gdouble new_angle;
ClutterVertex vertex = { 0, };
+ ClutterColor new_color = { 0, };
clutter_actor_get_position (actor, &old_x, &old_y);
clutter_actor_get_size (actor, &old_width, &old_height);
- old_op = clutter_actor_get_opacity (actor);
/* determine the final state of the animation depending on
* the state of the actor
@@ -40,8 +39,12 @@ on_button_press (ClutterActor *actor,
new_y = old_y - 100;
new_width = old_width + 200;
new_height = old_height + 200;
- new_op = 255;
new_angle = 360.0;
+
+ new_color.red = 0xdd;
+ new_color.green = 0x44;
+ new_color.blue = 0xdd;
+ new_color.alpha = 0xff;
}
else
{
@@ -49,8 +52,12 @@ on_button_press (ClutterActor *actor,
new_y = old_y + 100;
new_width = old_width - 200;
new_height = old_height - 200;
- new_op = 128;
new_angle = 0.0;
+
+ new_color.red = 0x44;
+ new_color.green = 0xdd;
+ new_color.blue = 0x44;
+ new_color.alpha = 0x88;
}
vertex.x = CLUTTER_UNITS_FROM_FLOAT ((float) new_width / 2);
@@ -62,7 +69,7 @@ on_button_press (ClutterActor *actor,
"y", new_y,
"width", new_width,
"height", new_height,
- "opacity", new_op,
+ "color", &new_color,
"rotation-angle-z", new_angle,
"fixed::rotation-center-z", &vertex,
"fixed::reactive", FALSE,