static ClutterAlpha * layout_manager_real_begin_animation (ClutterLayoutManager *manager, guint duration, gulong mode) { ClutterTimeline *timeline; ClutterAlpha *alpha; alpha = g_object_get_qdata (G_OBJECT (manager), quark_layout_alpha); if (alpha != NULL) { clutter_alpha_set_mode (alpha, mode); timeline = clutter_alpha_get_timeline (alpha); clutter_timeline_set_duration (timeline, duration); clutter_timeline_rewind (timeline); return alpha; }; timeline = clutter_timeline_new (duration); alpha = clutter_alpha_new_full (timeline, mode); /* let the alpha take ownership of the timeline */ g_object_unref (timeline); g_signal_connect_swapped (timeline, "completed", G_CALLBACK (clutter_layout_manager_end_animation), manager); g_signal_connect_swapped (timeline, "new-frame", G_CALLBACK (clutter_layout_manager_layout_changed), manager); g_object_set_qdata_full (G_OBJECT (manager), quark_layout_alpha, alpha, (GDestroyNotify) g_object_unref); clutter_timeline_start (timeline); return alpha; }
static void interpolation_completed_cb (ClutterTimeline *timeline, MxAdjustment *adjustment) { MxAdjustmentPrivate *priv = adjustment->priv; if (priv->elastic && priv->clamp_value) { if (clutter_timeline_get_direction (priv->interpolation) == CLUTTER_TIMELINE_FORWARD) { clutter_timeline_set_direction (priv->interpolation, CLUTTER_TIMELINE_BACKWARD); clutter_timeline_set_duration (priv->interpolation, 250); clutter_timeline_rewind (priv->interpolation); if (priv->new_position < priv->lower) { priv->old_position = priv->lower; clutter_timeline_start (priv->interpolation); } else if (priv->new_position > (priv->upper - priv->page_size)) { priv->old_position = priv->upper - priv->page_size; clutter_timeline_start (priv->interpolation); } } else { stop_interpolation (adjustment); mx_adjustment_set_value (adjustment, priv->old_position); } } else { stop_interpolation (adjustment); mx_adjustment_set_value (adjustment, priv->new_position); } g_signal_emit (adjustment, signals[INTERPOLATION_COMPLETED], 0); }
void mex_tile_set_important (MexTile *tile, gboolean important) { MexTilePrivate *priv; g_return_if_fail (MEX_IS_TILE (tile)); priv = tile->priv; if (priv->important != important) { priv->important = important; g_object_notify (G_OBJECT (tile), "important"); mx_stylable_set_style_class (MX_STYLABLE (tile), important ? "Important" : NULL); if (clutter_timeline_is_playing (priv->timeline)) clutter_timeline_set_direction (priv->timeline, important ? CLUTTER_TIMELINE_FORWARD : CLUTTER_TIMELINE_BACKWARD); else { if (CLUTTER_ACTOR_IS_MAPPED (tile)) { clutter_timeline_rewind (priv->timeline); clutter_timeline_start (priv->timeline); } else { clutter_timeline_advance (priv->timeline, DURATION); mex_tile_important_new_frame_cb (priv->timeline, 0, tile); mex_tile_timeline_completed_cb (priv->timeline, tile); } } } }
static void mx_expander_update (MxExpander *expander) { MxExpanderPrivate *priv = expander->priv; ClutterActor *child; if (priv->expanded) { clutter_actor_set_name (priv->arrow, "mx-expander-arrow-open"); mx_stylable_set_style_class (MX_STYLABLE (expander), "open-expander"); } /* closed state is set when animation is finished */ child = mx_bin_get_child (MX_BIN (expander)); if (!child) return; /* setup and start the expansion animation */ if (!priv->expanded) { clutter_actor_hide (child); clutter_timeline_set_direction (priv->timeline, CLUTTER_TIMELINE_BACKWARD); } else { clutter_timeline_set_direction (priv->timeline, CLUTTER_TIMELINE_FORWARD); } if (!clutter_timeline_is_playing (priv->timeline)) clutter_timeline_rewind (priv->timeline); clutter_timeline_start (priv->timeline); }
static void mx_label_allocate (ClutterActor *actor, const ClutterActorBox *box, ClutterAllocationFlags flags) { MxLabelPrivate *priv = MX_LABEL (actor)->priv; gboolean label_did_fade = priv->label_should_fade; ClutterActorClass *parent_class; ClutterActorBox child_box; gboolean x_fill, y_fill; gfloat avail_width; parent_class = CLUTTER_ACTOR_CLASS (mx_label_parent_class); parent_class->allocate (actor, box, flags); mx_widget_get_available_area (MX_WIDGET (actor), box, &child_box); avail_width = child_box.x2 - child_box.x1; /* The default behaviour of ClutterText is to align to the * top-left when it gets more space than is needed. Because * of this behaviour, if we're aligning to the left, we can * assign all our horizontal space to the label without * measuring it (i.e. x-fill), and the same applies for * aligning to the top and vertical space. */ x_fill = (priv->x_align == MX_ALIGN_START) ? TRUE : FALSE; y_fill = (priv->y_align == MX_ALIGN_START) ? TRUE : FALSE; mx_allocate_align_fill (priv->label, &child_box, priv->x_align, priv->y_align, x_fill, y_fill); priv->label_should_fade = FALSE; if (priv->fade_out) { /* If we're fading out, make sure the label has its full width * allocated. This ensures that the offscreen effect has the full * label inside its texture. */ gfloat label_width; clutter_actor_get_preferred_width (priv->label, -1, NULL, &label_width); if (label_width > avail_width) { priv->label_should_fade = TRUE; child_box.x2 = child_box.x1 + label_width; } mx_fade_effect_set_bounds (MX_FADE_EFFECT (priv->fade_effect), 0, 0, MIN (label_width, avail_width), 0); } /* Allocate the label */ clutter_actor_allocate (priv->label, &child_box, flags); if (priv->show_tooltip) { PangoLayout *layout; const gchar *text; layout = clutter_text_get_layout (CLUTTER_TEXT (priv->label)); if (pango_layout_is_ellipsized (layout)) text = clutter_text_get_text (CLUTTER_TEXT (priv->label)); else text = NULL; mx_widget_set_tooltip_text (MX_WIDGET (actor), text); } /* Animate in/out the faded end of the label */ if (label_did_fade != priv->label_should_fade) { /* Begin/reverse the fading timeline when necessary */ if (priv->label_should_fade) clutter_timeline_set_direction (priv->fade_timeline, CLUTTER_TIMELINE_FORWARD); else clutter_timeline_set_direction (priv->fade_timeline, CLUTTER_TIMELINE_BACKWARD); if (!clutter_timeline_is_playing (priv->fade_timeline)) clutter_timeline_rewind (priv->fade_timeline); clutter_timeline_start (priv->fade_timeline); } }
/** * clutter_timeline_stop: * @timeline: A #ClutterTimeline * * Stops the #ClutterTimeline and moves to frame 0 **/ void clutter_timeline_stop (ClutterTimeline *timeline) { clutter_timeline_pause (timeline); clutter_timeline_rewind (timeline); }
static gboolean clutter_timeline_do_frame (ClutterTimeline *timeline) { ClutterTimelinePrivate *priv; priv = timeline->priv; g_object_ref (timeline); CLUTTER_TIMESTAMP (SCHEDULER, "Timeline [%p] activated (cur: %ld)\n", timeline, (long) priv->elapsed_time); /* Advance time */ if (priv->direction == CLUTTER_TIMELINE_FORWARD) priv->elapsed_time += priv->msecs_delta; else priv->elapsed_time -= priv->msecs_delta; /* If we have not reached the end of the timeline: */ if (!is_complete (timeline)) { /* Emit the signal */ emit_frame_signal (timeline); check_markers (timeline, priv->msecs_delta); /* Signal pauses timeline ? */ if (!priv->is_playing) { g_object_unref (timeline); return FALSE; } g_object_unref (timeline); return TRUE; } else { /* Handle loop or stop */ ClutterTimelineDirection saved_direction = priv->direction; gint elapsed_time_delta = priv->msecs_delta; guint overflow_msecs = priv->elapsed_time; gint end_msecs; /* Update the current elapsed time in case the signal handlers * want to take a peek. If we clamp elapsed time, then we need * to correpondingly reduce elapsed_time_delta to reflect the correct * range of times */ if (priv->direction == CLUTTER_TIMELINE_FORWARD) { elapsed_time_delta -= (priv->elapsed_time - priv->duration); priv->elapsed_time = priv->duration; } else if (priv->direction == CLUTTER_TIMELINE_BACKWARD) { elapsed_time_delta -= - priv->elapsed_time; priv->elapsed_time = 0; } end_msecs = priv->elapsed_time; /* Emit the signal */ emit_frame_signal (timeline); check_markers (timeline, elapsed_time_delta); /* Did the signal handler modify the elapsed time? */ if (priv->elapsed_time != end_msecs) { g_object_unref (timeline); return TRUE; } /* Note: If the new-frame signal handler paused the timeline * on the last frame we will still go ahead and send the * completed signal */ CLUTTER_NOTE (SCHEDULER, "Timeline [%p] completed (cur: %ld, tot: %ld)", timeline, (long) priv->elapsed_time, (long) priv->msecs_delta); if (!priv->loop && priv->is_playing) { /* We remove the timeout now, so that the completed signal handler * may choose to re-start the timeline * * XXX Perhaps we should remove this earlier, and regardless * of priv->loop. Are we limiting the things that could be done in * the above new-frame signal handler */ set_is_playing (timeline, FALSE); } g_signal_emit (timeline, timeline_signals[COMPLETED], 0); /* Again check to see if the user has manually played with * the elapsed time, before we finally stop or loop the timeline */ if (priv->elapsed_time != end_msecs && !(/* Except allow changing time from 0 -> duration (or vice-versa) since these are considered equivalent */ (priv->elapsed_time == 0 && end_msecs == priv->duration) || (priv->elapsed_time == priv->duration && end_msecs == 0) )) { g_object_unref (timeline); return TRUE; } if (priv->loop) { /* We try and interpolate smoothly around a loop */ if (saved_direction == CLUTTER_TIMELINE_FORWARD) priv->elapsed_time = overflow_msecs - priv->duration; else priv->elapsed_time = priv->duration + overflow_msecs; /* Or if the direction changed, we try and bounce */ if (priv->direction != saved_direction) priv->elapsed_time = priv->duration - priv->elapsed_time; /* If we have overflowed then we are changing the elapsed time without emitting the new frame signal so we need to check for markers again */ check_markers (timeline, priv->direction == CLUTTER_TIMELINE_FORWARD ? priv->elapsed_time : priv->duration - priv->elapsed_time); g_object_unref (timeline); return TRUE; } else { clutter_timeline_rewind (timeline); g_object_unref (timeline); return FALSE; } } }
void aisleriot_slot_renderer_set_animations (AisleriotSlotRenderer *srend, guint n_anims, const AisleriotAnimStart *anims, guint n_unexposed_animated_cards) { AisleriotSlotRendererPrivate *priv; guint i; gint card_num; g_return_if_fail (AISLERIOT_IS_SLOT_RENDERER (srend)); priv = srend->priv; g_return_if_fail (n_anims <= priv->slot->exposed); /* Destroy the current animations */ for (i = 0; i < priv->animations->len; i++) { AnimationData *anim_data; anim_data = &g_array_index (priv->animations, AnimationData, i); if (anim_data->move) g_object_unref (anim_data->move); if (anim_data->rotate) g_object_unref (anim_data->rotate); if (anim_data->depth) g_object_unref (anim_data->depth); clutter_actor_destroy (anim_data->card_tex); g_object_unref (anim_data->card_tex); } g_array_set_size (priv->animations, 0); card_num = priv->slot->cards->len - n_anims; for (i = 0; i < n_anims; i++) { AnimationData anim_data; ClutterAlpha *alpha; ClutterKnot knots[2]; Card card = CARD (priv->slot->cards->data[card_num]); guint card_width, card_height; memset (&anim_data, 0, sizeof (anim_data)); anim_data.card_tex = aisleriot_card_new (priv->cache, anims[i].old_card, card); card_width = clutter_actor_get_width (anim_data.card_tex); card_height = clutter_actor_get_height (anim_data.card_tex); g_object_ref_sink (anim_data.card_tex); if (priv->animation_layer) clutter_container_add (priv->animation_layer, CLUTTER_ACTOR (anim_data.card_tex), NULL); clutter_actor_set_position (anim_data.card_tex, anims[i].cardx, anims[i].cardy); knots[0].x = anims[i].cardx; knots[0].y = anims[i].cardy; aisleriot_game_get_card_offset (priv->slot, card_num, FALSE, &knots[1].x, &knots[1].y); knots[1].x += priv->slot->rect.x; knots[1].y += priv->slot->rect.y; alpha = clutter_alpha_new_full (priv->timeline, CLUTTER_LINEAR); anim_data.move = clutter_behaviour_path_new_with_knots (alpha, knots, G_N_ELEMENTS (knots)); clutter_behaviour_apply (anim_data.move, anim_data.card_tex); if (anims[i].old_card.value != card.value) { int center_x, center_y; center_x = card_width / 2; center_y = card_height / 2; clutter_actor_set_rotation (anim_data.card_tex, CLUTTER_Y_AXIS, 180.0, center_x, center_y, 0); anim_data.rotate = clutter_behaviour_rotate_new (alpha, CLUTTER_Y_AXIS, CLUTTER_ROTATE_CW, 180.0, 0.0); clutter_behaviour_rotate_set_center (CLUTTER_BEHAVIOUR_ROTATE (anim_data.rotate), center_x, center_y, 0); clutter_behaviour_apply (anim_data.rotate, anim_data.card_tex); } if (anims[i].raise) { alpha = clutter_alpha_new_with_func (priv->timeline, aisleriot_slot_sine_animation_mode, NULL, NULL); anim_data.depth = clutter_behaviour_depth_new (alpha, 0, card_height); clutter_behaviour_apply (anim_data.depth, anim_data.card_tex); } g_array_append_val (priv->animations, anim_data); card_num++; } if (n_anims > 0) { clutter_timeline_rewind (priv->timeline); clutter_timeline_start (priv->timeline); } priv->n_unexposed_animated_cards = n_unexposed_animated_cards; clutter_actor_queue_redraw (CLUTTER_ACTOR (srend)); }