actor: Add generic transition support

ClutterActor should be able to hold all transitions, even the ones that
have been explicitly created.

This will allow to add new transitions types in the future, like the
keyframe-based one, or the transition group.
This commit is contained in:
Emmanuele Bassi 2012-03-15 16:40:41 +00:00
parent 3638c1efed
commit 4bd3583dbf
4 changed files with 179 additions and 32 deletions

View File

@ -16614,10 +16614,24 @@ typedef struct _TransitionClosure
{ {
ClutterActor *actor; ClutterActor *actor;
ClutterTransition *transition; ClutterTransition *transition;
GParamSpec *property; gchar *name;
gulong completed_id; gulong completed_id;
} TransitionClosure; } TransitionClosure;
static void
transition_closure_free (gpointer data)
{
if (G_LIKELY (data != NULL))
{
TransitionClosure *clos = data;
g_signal_handler_disconnect (clos->transition, clos->completed_id);
g_free (clos->name);
g_slice_free (TransitionClosure, clos);
}
}
static void static void
on_transition_completed (ClutterTransition *transition, on_transition_completed (ClutterTransition *transition,
TransitionClosure *clos) TransitionClosure *clos)
@ -16626,11 +16640,8 @@ on_transition_completed (ClutterTransition *transition,
info = _clutter_actor_get_animation_info (clos->actor); info = _clutter_actor_get_animation_info (clos->actor);
g_hash_table_remove (info->transitions, clos->property->name); /* this will take care of cleaning clos for us */
g_hash_table_remove (info->transitions, clos->name);
g_signal_handler_disconnect (transition, clos->completed_id);
g_slice_free (TransitionClosure, clos);
} }
void void
@ -16638,7 +16649,7 @@ _clutter_actor_update_transition (ClutterActor *actor,
GParamSpec *pspec, GParamSpec *pspec,
...) ...)
{ {
ClutterTransition *transition; TransitionClosure *clos;
ClutterInterval *interval; ClutterInterval *interval;
const ClutterAnimationInfo *info; const ClutterAnimationInfo *info;
va_list var_args; va_list var_args;
@ -16652,8 +16663,8 @@ _clutter_actor_update_transition (ClutterActor *actor,
if (info->transitions == NULL) if (info->transitions == NULL)
return; return;
transition = g_hash_table_lookup (info->transitions, pspec->name); clos = g_hash_table_lookup (info->transitions, pspec->name);
if (transition == NULL) if (clos == NULL)
return; return;
va_start (var_args, pspec); va_start (var_args, pspec);
@ -16673,11 +16684,11 @@ _clutter_actor_update_transition (ClutterActor *actor,
goto out; goto out;
} }
interval = clutter_transition_get_interval (transition); interval = clutter_transition_get_interval (clos->transition);
clutter_interval_set_initial_value (interval, &initial); clutter_interval_set_initial_value (interval, &initial);
clutter_interval_set_final_value (interval, &final); clutter_interval_set_final_value (interval, &final);
clutter_timeline_rewind (CLUTTER_TIMELINE (transition)); clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
out: out:
g_value_unset (&initial); g_value_unset (&initial);
@ -16704,6 +16715,7 @@ _clutter_actor_create_transition (ClutterActor *actor,
ClutterAnimationInfo *info; ClutterAnimationInfo *info;
ClutterTransition *res = NULL; ClutterTransition *res = NULL;
gboolean call_restore = FALSE; gboolean call_restore = FALSE;
TransitionClosure *clos;
va_list var_args; va_list var_args;
info = _clutter_actor_get_animation_info (actor); info = _clutter_actor_get_animation_info (actor);
@ -16715,19 +16727,20 @@ _clutter_actor_create_transition (ClutterActor *actor,
} }
if (info->transitions == NULL) if (info->transitions == NULL)
info->transitions = g_hash_table_new (g_str_hash, g_str_equal); info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL,
transition_closure_free);
va_start (var_args, pspec); va_start (var_args, pspec);
res = g_hash_table_lookup (info->transitions, pspec->name); clos = g_hash_table_lookup (info->transitions, pspec->name);
if (res == NULL) if (clos == NULL)
{ {
ClutterInterval *interval; ClutterInterval *interval;
GValue initial = G_VALUE_INIT; GValue initial = G_VALUE_INIT;
GValue final = G_VALUE_INIT; GValue final = G_VALUE_INIT;
GType ptype; GType ptype;
char *error; char *error;
TransitionClosure *clos;
ptype = G_PARAM_SPEC_VALUE_TYPE (pspec); ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
@ -16764,24 +16777,10 @@ _clutter_actor_create_transition (ClutterActor *actor,
clutter_transition_set_interval (res, interval); clutter_transition_set_interval (res, interval);
clutter_transition_set_remove_on_complete (res, TRUE); clutter_transition_set_remove_on_complete (res, TRUE);
clutter_timeline_set_delay (CLUTTER_TIMELINE (res), clutter_actor_add_transition (actor, pspec->name, res);
info->cur_state->easing_delay);
clutter_timeline_set_duration (CLUTTER_TIMELINE (res),
info->cur_state->easing_duration);
clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (res),
info->cur_state->easing_mode);
clos = g_slice_new (TransitionClosure);
clos->actor = actor;
clos->transition = res;
clos->property = pspec;
clos->completed_id =
g_signal_connect (res, "completed",
G_CALLBACK (on_transition_completed),
clos);
g_hash_table_insert (info->transitions, (gpointer) pspec->name, res);
} }
else
res = clos->transition;
out: out:
if (call_restore) if (call_restore)
@ -16792,6 +16791,130 @@ out:
return res; return res;
} }
/**
* clutter_actor_add_transition:
* @self: a #ClutterActor
* @name: the name of the transition to add
* @transition: the #ClutterTransition to add
*
* Adds a @transition to the #ClutterActor's list of animations.
*
* The @name string is a per-actor unique identifier of the @transition: only
* one #ClutterTransition can be associated to the specified @name.
*
* The @transition will be given the easing duration, mode, and delay
* associated to the actor's current easing state; it is possible to modify
* these values after calling clutter_actor_add_transition().
*
* This function is usually called implicitly when modifying an animatable
* property.
*
* Since: 1.10
*/
void
clutter_actor_add_transition (ClutterActor *self,
const char *name,
ClutterTransition *transition)
{
ClutterTimeline *timeline;
TransitionClosure *clos;
ClutterAnimationInfo *info;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
g_return_if_fail (name != NULL);
g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
info = _clutter_actor_get_animation_info (self);
if (info->cur_state == NULL)
{
g_warning ("No easing state is defined for the actor '%s'; you "
"must call clutter_actor_save_easing_state() before "
"calling clutter_actor_add_transition().",
_clutter_actor_get_debug_name (self));
return;
}
if (info->transitions == NULL)
info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL,
transition_closure_free);
if (g_hash_table_lookup (info->transitions, name) != NULL)
{
g_warning ("A transition with name '%s' already exists for "
"the actor '%s'",
name,
_clutter_actor_get_debug_name (self));
return;
}
timeline = CLUTTER_TIMELINE (transition);
clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
clos = g_slice_new (TransitionClosure);
clos->actor = self;
clos->transition = transition;
clos->name = g_strdup (name);
clos->completed_id = g_signal_connect (timeline, "completed",
G_CALLBACK (on_transition_completed),
clos);
g_hash_table_insert (info->transitions, clos->name, clos);
}
/**
* clutter_actor_remove_transition:
* @self: a #ClutterActor
* @name: the name of the transition to remove
*
* Removes the transition stored inside a #ClutterActor using @name
* identifier.
*
* Since: 1.10
*/
void
clutter_actor_remove_transition (ClutterActor *self,
const char *name)
{
const ClutterAnimationInfo *info;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
g_return_if_fail (name != NULL);
info = _clutter_actor_get_animation_info_or_defaults (self);
if (info->transitions == NULL)
return;
g_hash_table_remove (info->transitions, name);
}
/**
* clutter_actor_remove_all_transitions:
* @self: a #ClutterActor
*
* Removes all transitions associated to @self.
*
* Since: 1.10
*/
void
clutter_actor_remove_all_transitions (ClutterActor *self)
{
const ClutterAnimationInfo *info;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
info = _clutter_actor_get_animation_info_or_defaults (self);
if (info->transitions == NULL)
return;
g_hash_table_remove_all (info->transitions);
}
/** /**
* clutter_actor_set_easing_duration: * clutter_actor_set_easing_duration:
* @self: a #ClutterActor * @self: a #ClutterActor

View File

@ -643,19 +643,37 @@ void clutter_actor_get_transformation_matrix
CoglMatrix *matrix); CoglMatrix *matrix);
/* Implicit animations */ /* Implicit animations */
CLUTTER_AVAILABLE_IN_1_10
void clutter_actor_save_easing_state (ClutterActor *self); void clutter_actor_save_easing_state (ClutterActor *self);
CLUTTER_AVAILABLE_IN_1_10
void clutter_actor_restore_easing_state (ClutterActor *self); void clutter_actor_restore_easing_state (ClutterActor *self);
CLUTTER_AVAILABLE_IN_1_10
void clutter_actor_set_easing_mode (ClutterActor *self, void clutter_actor_set_easing_mode (ClutterActor *self,
ClutterAnimationMode mode); ClutterAnimationMode mode);
CLUTTER_AVAILABLE_IN_1_10
ClutterAnimationMode clutter_actor_get_easing_mode (ClutterActor *self); ClutterAnimationMode clutter_actor_get_easing_mode (ClutterActor *self);
CLUTTER_AVAILABLE_IN_1_10
void clutter_actor_set_easing_duration (ClutterActor *self, void clutter_actor_set_easing_duration (ClutterActor *self,
guint msecs); guint msecs);
CLUTTER_AVAILABLE_IN_1_10
guint clutter_actor_get_easing_duration (ClutterActor *self); guint clutter_actor_get_easing_duration (ClutterActor *self);
CLUTTER_AVAILABLE_IN_1_10
void clutter_actor_set_easing_delay (ClutterActor *self, void clutter_actor_set_easing_delay (ClutterActor *self,
guint msecs); guint msecs);
CLUTTER_AVAILABLE_IN_1_10
guint clutter_actor_get_easing_delay (ClutterActor *self); guint clutter_actor_get_easing_delay (ClutterActor *self);
CLUTTER_AVAILABLE_IN_1_10
ClutterTransition * clutter_actor_get_transition (ClutterActor *self, ClutterTransition * clutter_actor_get_transition (ClutterActor *self,
const char *name); const char *name);
CLUTTER_AVAILABLE_IN_1_10
void clutter_actor_add_transition (ClutterActor *self,
const char *name,
ClutterTransition *transition);
CLUTTER_AVAILABLE_IN_1_10
void clutter_actor_remove_transition (ClutterActor *self,
const char *name);
CLUTTER_AVAILABLE_IN_1_10
void clutter_actor_remove_all_transitions (ClutterActor *self);
G_END_DECLS G_END_DECLS

View File

@ -30,6 +30,7 @@ clutter_actor_add_constraint
clutter_actor_add_constraint_with_name clutter_actor_add_constraint_with_name
clutter_actor_add_effect clutter_actor_add_effect
clutter_actor_add_effect_with_name clutter_actor_add_effect_with_name
clutter_actor_add_transition
clutter_actor_align_get_type clutter_actor_align_get_type
clutter_actor_allocate clutter_actor_allocate
clutter_actor_allocate_align_fill clutter_actor_allocate_align_fill
@ -194,12 +195,14 @@ clutter_actor_realize
clutter_actor_remove_action clutter_actor_remove_action
clutter_actor_remove_action_by_name clutter_actor_remove_action_by_name
clutter_actor_remove_all_children clutter_actor_remove_all_children
clutter_actor_remove_all_transitions
clutter_actor_remove_constraint clutter_actor_remove_constraint
clutter_actor_remove_constraint_by_name clutter_actor_remove_constraint_by_name
clutter_actor_remove_child clutter_actor_remove_child
clutter_actor_remove_clip clutter_actor_remove_clip
clutter_actor_remove_effect clutter_actor_remove_effect
clutter_actor_remove_effect_by_name clutter_actor_remove_effect_by_name
clutter_actor_remove_transition
clutter_actor_reparent clutter_actor_reparent
clutter_actor_replace_child clutter_actor_replace_child
clutter_actor_restore_easing_state clutter_actor_restore_easing_state

View File

@ -464,6 +464,9 @@ clutter_actor_get_easing_mode
clutter_actor_set_easing_delay clutter_actor_set_easing_delay
clutter_actor_get_easing_delay clutter_actor_get_easing_delay
clutter_actor_get_transition clutter_actor_get_transition
clutter_actor_add_transition
clutter_actor_remove_transition
clutter_actor_remove_all_transitions
<SUBSECTION> <SUBSECTION>
clutter_actor_set_reactive clutter_actor_set_reactive