state: Use the Animatable interface

The Animatable interface allows object classes to provide and animate
properties outside of the usual GObject property introspection API.

This change allows ClutterState to defer to the animatable objects the
property introspection and animation, just like ClutterAnimation does.
This commit is contained in:
Emmanuele Bassi 2011-07-15 15:06:31 +01:00
parent 8b03ec9d16
commit f28c1d2d2a
2 changed files with 79 additions and 12 deletions

View File

@ -185,6 +185,7 @@
#include <string.h>
#include "clutter-alpha.h"
#include "clutter-animatable.h"
#include "clutter-animator.h"
#include "clutter-enum-types.h"
#include "clutter-interval.h"
@ -255,6 +256,7 @@ typedef struct _ClutterStateKey
ClutterInterval *interval; /* The interval this key uses for
interpolation */
guint is_animatable : 1;
guint is_inert : 1; /* set if the key is being destroyed due to
weak reference */
gint ref_count; /* reference count for boxed life time */
@ -345,6 +347,7 @@ clutter_state_key_new (State *state,
state_key->object = object;
state_key->property_name = g_intern_string (property_name);
state_key->mode = mode;
state_key->is_animatable = CLUTTER_IS_ANIMATABLE (object);
state_key->alpha = clutter_alpha_new ();
g_object_ref_sink (state_key->alpha);
@ -578,11 +581,10 @@ clutter_state_new_frame (ClutterTimeline *timeline,
if (found_specific || key->source_state == NULL)
{
const GValue *value;
gdouble pre_delay = key->pre_delay + key->pre_pre_delay;
sub_progress = (progress - pre_delay) /
(1.0 - (pre_delay + key->post_delay));
sub_progress = (progress - pre_delay)
/ (1.0 - (pre_delay + key->post_delay));
if (sub_progress >= 0.0)
{
@ -593,10 +595,39 @@ clutter_state_new_frame (ClutterTimeline *timeline,
sub_progress * SLAVE_TIMELINE_LENGTH);
sub_progress = clutter_alpha_get_alpha (key->alpha);
if (key->is_animatable)
{
ClutterAnimatable *animatable;
GValue value = { 0, };
gboolean res;
animatable = CLUTTER_ANIMATABLE (key->object);
g_value_init (&value, clutter_state_key_get_property_type (key));
res =
clutter_animatable_interpolate_value (animatable,
key->property_name,
key->interval,
sub_progress,
&value);
if (res)
clutter_animatable_set_final_state (animatable,
key->property_name,
&value);
g_value_unset (&value);
}
else
{
const GValue *value;
value = clutter_interval_compute (key->interval, sub_progress);
if (value != NULL)
g_object_set_property (key->object, key->property_name, value);
}
}
/* XXX: should the target value of the default destination be
* used even when found a specific source_state key?
@ -710,6 +741,17 @@ clutter_state_change (ClutterState *state,
key->pre_pre_delay = 0;
g_value_init (&initial, clutter_interval_get_value_type (key->interval));
if (key->is_animatable)
{
ClutterAnimatable *animatable;
animatable = CLUTTER_ANIMATABLE (key->object);
clutter_animatable_get_initial_state (animatable,
key->property_name,
&initial);
}
else
g_object_get_property (key->object, key->property_name, &initial);
if (clutter_alpha_get_mode (key->alpha) != key->mode)
@ -796,10 +838,21 @@ static GParamSpec *
get_property_from_object (GObject *gobject,
const gchar *property_name)
{
GObjectClass *klass = G_OBJECT_GET_CLASS (gobject);
GParamSpec *pspec;
if (CLUTTER_IS_ANIMATABLE (gobject))
{
ClutterAnimatable *animatable = CLUTTER_ANIMATABLE (gobject);
pspec = clutter_animatable_find_property (animatable, property_name);
}
else
{
GObjectClass *klass = G_OBJECT_GET_CLASS (gobject);
pspec = g_object_class_find_property (klass, property_name);
}
if (pspec == NULL)
{
g_warning ("Cannot bind property '%s': objects of type '%s' "
@ -1045,6 +1098,17 @@ clutter_state_set_key_internal (ClutterState *state,
g_value_init (&initial,
clutter_interval_get_value_type (key->interval));
if (key->is_animatable)
{
ClutterAnimatable *animatable;
animatable = CLUTTER_ANIMATABLE (key->object);
clutter_animatable_get_initial_state (animatable,
key->property_name,
&initial);
}
else
g_object_get_property (key->object, key->property_name, &initial);
if (clutter_alpha_get_mode (key->alpha) != key->mode)
@ -2061,8 +2125,7 @@ parse_state_transition (JsonArray *array,
}
property = json_array_get_string_element (key, 1);
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (gobject),
property);
pspec = get_property_from_object (gobject, property);
if (pspec == NULL)
{
g_warning ("The object of type '%s' and name '%s' has no "

View File

@ -122,6 +122,8 @@ test_state_main (gint argc,
clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
clutter_actor_set_position (actor, 320.0, 240.0);
clutter_actor_set_reactive (actor, TRUE);
clutter_actor_add_effect_with_name (actor, "fade",
clutter_desaturate_effect_new (0.0));
clutter_state_set (layout_state, NULL, "active",
@ -162,10 +164,12 @@ test_state_main (gint argc,
clutter_state_set (a_state, NULL, "normal",
actor, "opacity", CLUTTER_LINEAR, 0x77,
actor, "rotation-angle-z", CLUTTER_LINEAR, 0.0,
actor, "@effects.fade.factor", CLUTTER_LINEAR, 0.0,
NULL);
clutter_state_set (a_state, NULL, "hover",
actor, "opacity", CLUTTER_LINEAR, 0xff,
actor, "rotation-angle-z", CLUTTER_LINEAR, 10.0,
actor, "@effects.fade.factor", CLUTTER_LINEAR, 1.0,
NULL);
clutter_actor_set_opacity (actor, 0x77);