## Timelines

#ClutterTimelines abstract a set period of time with a set frame rate at which to call a provided callback.

#ClutterTimelines also extend the timeout sources functionality further by:

1. Having a set duration (in milliseconds) and a set 'frame rate' - that is, the rate at which the callback is called

2. Passing current progress information to the callback

3. Handling 'dropped frames' and guarenteeing the set duration by skipping over frames if the callback cannot keep up with the set frame rate

4. Querying the number of milliseconds elapsed between the current and previous callback.

5. Allowing the timeline to be modified on the fly as well as being stopped, started, looped, rewound and reversed

6. Using a #ClutterTimeoutPool to more efficiently schedule multiple timeout sources without incurring in potential starvation of the main loop slices

A Timeline is created with;

    clutter_timeline_new (n_frames, frames_per_seconds);

Taking a number of frames and a frames per second, or by;

    clutter_timeline_new_for_duration (msecs);

Which takes the duration of the timeline in milliseconds with a default frame rate (See clutter_get_default_frame_rate()).

The speed, duration and number of frames of the timeline then be modifed via the objects properties and API calls. The timeline can be made to loop by settings it "loop" property to %TRUE.

The timelines is started via clutter_timeline_start() and its playback further manipulated by the clutter_timeline_pause(), clutter_timeline_stop(), clutter_timeline_rewind() and clutter_timeline_skip() calls.

By attaching a handler to the timeline's ClutterTimeline::new-frame signal a timeline can then be used to drive an animation by altering an actor's visual properties in this callback. The callback looks like:

    void
    on_new_frame (ClutterTimeline *timeline,
                  gint             frame_num,
                  gpointer         user_data)
    {

    }

The `frame_num` parameter is set to the timeline's current frame number (which is between 0 and the "num-frames" property). This value can be used to compute the state of a particular animation that is dependant on the frame numer. The clutter_timeline_get_progress() function can also be used to get a normalised value of the timeline's current position between 0 and 1.

Timelines can also be played in reverse by setting the direction using clutter_timeline_set_direction(), and can also have a one-time delay set before they begin playing by using clutter_timeline_set_delay().

Timelines can also control a pyshical simulation; the clutter_timeline_get_delta() function allows retrieving the number of frames and milliseconds elapsed since the previous callback to ensure the physics engine to be able to take the actual time elapsed between iterations into account.

Example 9.

The following example demonstrates rotating an actor with a timeline.

    #include <clutter/clutter.h>

    void
    on_new_frame (ClutterTimeline *timeline,
    	      gint             frame_num,
    	      gpointer         data)
    {
      ClutterActor *actor = CLUTTER_ACTOR(data);

      clutter_actor_set_rotation (actor, CLUTTER_Z_AXIS,
                                  (gdouble) frame_num,
                                  clutter_actor_get_width (actor) / 2,
    			      clutter_actor_get_height (actor) / 2,
                                  0);
    }

    int
    main (int argc, char *argv[])
    {
      ClutterTimeline *timeline;

      ClutterActor    *stage, *actor;
      GdkPixbuf       *pixbuf;

      clutter_init (&argc, &argv);

      stage = clutter_stage_get_default ();

      pixbuf = gdk_pixbuf_new_from_file ("an-image.png", NULL);

      actor  = clutter_texture_new_from_pixbuf (pixbuf);

      clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);

      clutter_actor_set_position (actor, 100, 100);

      timeline = clutter_timeline_new_for (360, 60); /* a degree per frame */
      clutter_timeline_set_loop (timeline, TRUE);

      g_signal_connect (timeline, "new-frame", G_CALLBACK (on_new_frame), actor);

      clutter_actor_show_all (stage);

      clutter_timeline_start (timeline);

      clutter_main();

      return 0;
    }

### Note

Multiple timelines can be sequenced in order by means of the #ClutterScore. See the #ClutterScore documentation for more details on using this.