我们已经学习了clutter的基本用法,用一个较大的例子来进行复习,例子来源:http://www.openismus.com/documents/clutter_tutorial/0.9/docs/tutorial/html/sec-full-example.html 。这个教程是基于clutter0.9的,在clutter1.0上需要做小小的改动。下面是clutter1.0上的这个例子的重写:
#include <clutter/clutter.h>
#include <stdlib.h>
const gint ELLIPSE_Y = 390;
const gint ELLIPSE_HEIGHT = 450;
const gint IMAGE_HEIGHT = 100;
double angle_step = 30;
ClutterTimeline * timeline_rotation = NULL, * timeline_moveup = NULL;
ClutterActor * label_filename = NULL;
ClutterBehaviour * behaviour_scale = NULL , * behaviour_path = NULL,
* behaviour_opacity = NULL;
typedef struct Item{
ClutterActor * actor;
ClutterBehaviour * ellipse_behaviour;
gchar * filepath;
}Item;
Item* item_at_front = NULL;
GSList *list_items = 0;
void rotate_all_until_item_is_at_front(Item * item);
gdouble angle_in_360(gdouble angle){
gdouble result = angle;
while(result >= 360)
result -= 360;
return result;
}
void on_foreach_clear_list_items(gpointer data, gpointer user_data)
{
if(data == NULL)
return;
Item* item = (Item*)data;
/* We don't need to unref the actor because the floating reference was taken by the stage. */
g_object_unref (item->ellipse_behaviour);
g_free (item->filepath);
g_free (item);
}
void scale_texture_default(ClutterActor * texture){
int pixbuf_height = 0;
clutter_texture_get_base_size (CLUTTER_TEXTURE (texture), NULL,
&pixbuf_height);
const gdouble scale = pixbuf_height ? IMAGE_HEIGHT / (gdouble)pixbuf_height : 0;
clutter_actor_set_scale (texture, scale, scale);
}
void load_images(const gchar* directory_path){
g_return_if_fail(directory_path);
/* Clear any existing images: */
g_slist_foreach (list_items, on_foreach_clear_list_items, NULL);
g_slist_free (list_items);
/* Create a new list: */
list_items = NULL;
GError * error = NULL;
GDir * dir = g_dir_open(directory_path,0,&error);
if(error) {
g_warning("g_dir_open() failed: %s/n", error->message);
g_clear_error(&error);
return;
}
int i = 0;
const gchar * filename = NULL;
while ( (filename = g_dir_read_name(dir)) != NULL){
gchar* path = g_build_filename (directory_path, filename, NULL);
printf("%2d %s/n",++i, path);
ClutterActor * actor = clutter_texture_new_from_file(path,NULL);
if(actor){
Item * item = g_new0(Item,1);
item -> actor = actor;
item -> filepath = g_strdup (path);
scale_texture_default(item->actor);
list_items = g_slist_append(list_items,item);
}
g_free(path);
}
angle_step = 360.0/i;
printf("total %d image, angel step is %.1f/n",i,angle_step);
}
gboolean on_texture_button_press(ClutterActor * actor ,ClutterEvent * event,
gpointer user_data){
if(timeline_rotation && clutter_timeline_is_playing(timeline_rotation)){
printf("on_texture_button_press() : ignoring/n");
return FALSE;
}else{
printf("on_texture_button_press() : handling/n");
}
Item * item = (Item *) user_data;
rotate_all_until_item_is_at_front(item);
return TRUE;
}
void add_to_ellipse_behaviour(ClutterTimeline *timeline_rotation, gdouble start_angle, Item *item){
g_return_if_fail (timeline_rotation);
ClutterAlpha *alpha = clutter_alpha_new_full (timeline_rotation,
CLUTTER_EASE_OUT_SINE);
/*if start is equal to end, the behaviour will rotate by exacly 360 degrees.*/
item->ellipse_behaviour = clutter_behaviour_ellipse_new (alpha, 320, ELLIPSE_Y, /* x, y */
ELLIPSE_HEIGHT, ELLIPSE_HEIGHT/* width, height */ , CLUTTER_ROTATE_CW,
start_angle, start_angle );
clutter_behaviour_ellipse_set_angle_tilt ( CLUTTER_BEHAVIOUR_ELLIPSE (item->ellipse_behaviour),
CLUTTER_X_AXIS, -90.0);
clutter_behaviour_apply (item->ellipse_behaviour, item->actor);
}
void add_image_actors(ClutterActor * stage){
int x = 20;
int y = 0;
gdouble angle = 0;
GSList * list = list_items;
while(list){
Item * item = (Item *) list->data;
ClutterActor * actor = item->actor;
clutter_actor_set_position(actor,x,y);
y += 100;
clutter_container_add_actor(CLUTTER_CONTAINER(stage),actor);
/* Allow the actor to emit events. By default only the stage does this. */
clutter_actor_set_reactive (actor, TRUE);
g_signal_connect (actor, "button-press-event",
G_CALLBACK (on_texture_button_press), item);
while(angle >= 360)
angle -= 360;
add_to_ellipse_behaviour(timeline_rotation,angle,item);
angle += angle_step;
list = g_slist_next(list);
}
}
void on_timeline_moveup_completed(ClutterTimeline* timeline, gpointer user_data)
{
/* Unref this timeline because we have now finished with it: */
g_object_unref (timeline_moveup);
timeline_moveup = NULL;
g_object_unref (behaviour_scale);
behaviour_scale = NULL;
g_object_unref (behaviour_path);
behaviour_path = NULL;
g_object_unref (behaviour_opacity);
behaviour_opacity = NULL;
}
void on_timeline_rotation_completed(ClutterTimeline * timeline, gpointer user_data){
ClutterActor * actor = item_at_front->actor;
timeline_moveup = clutter_timeline_new(1200 /* milliseconds */);
/*for Scaling*/
ClutterAlpha *alpha = clutter_alpha_new_full (timeline_moveup, CLUTTER_EASE_OUT_SINE);
gdouble scale_start = 0;
clutter_actor_get_scale (actor, &scale_start, NULL);
const gdouble scale_end = scale_start * 1.80;
behaviour_scale = clutter_behaviour_scale_new (alpha, scale_start, scale_start, scale_end, scale_end);
clutter_behaviour_apply (behaviour_scale, actor);
/* Move the item up the y axis: */
ClutterKnot knots[2];
knots[0].x = clutter_actor_get_x (actor);
knots[0].y = clutter_actor_get_y (actor);
knots[1].x = knots[0].x - 80;
knots[1].y = knots[0].y - 255;
printf("move from (%d,%d) to (%d, %d)/n",knots[0].x,knots[0].y,knots[1].x,knots[1].y);
behaviour_path = clutter_behaviour_path_new_with_knots (alpha, knots, G_N_ELEMENTS(knots));
clutter_behaviour_apply (behaviour_path, actor);
/*Show the file name */
clutter_text_set_text (CLUTTER_TEXT (label_filename), item_at_front->filepath);
behaviour_opacity = clutter_behaviour_opacity_new (alpha, 0, 255);
clutter_behaviour_apply (behaviour_opacity, label_filename);
/*After it complete unref the param */
g_signal_connect (timeline_moveup, "completed", G_CALLBACK (on_timeline_moveup_completed), NULL);
clutter_timeline_start (timeline_moveup);
}
void rotate_all_until_item_is_at_front(Item * item){
g_return_if_fail (item);
clutter_timeline_stop(timeline_rotation);
if(timeline_moveup != NULL)
clutter_timeline_stop(timeline_moveup);
clutter_actor_set_opacity (label_filename, 0);
/* Get the item's position in the list: */
const gint pos = g_slist_index (list_items, item);
printf("We want to show pos = %d/n",pos);
g_assert (pos != -1);
if(!item_at_front && list_items)
item_at_front = (Item*)list_items->data;
gint pos_front = 0;
if(item_at_front)
pos_front = g_slist_index (list_items, item_at_front);
printf("Current front pos is %d/n",pos_front);
g_assert (pos_front != -1);
/* Calculate the end angle of the first item: */
const gdouble angle_front = 90;
gdouble angle_start = angle_front - (angle_step * pos_front);
angle_start= angle_in_360(angle_start);
gdouble angle_end = angle_front - (angle_step * pos);
printf("angle (%.0f %.0f)/n",angle_start,angle_end);
gdouble angle_diff = 0;
GSList *list = list_items;
gint i = 0;
while(list){
Item * this_item = (Item*)list->data;
/* Reset its size: */
scale_texture_default (this_item->actor);
angle_start = angle_in_360 (angle_start);
angle_end = angle_in_360 (angle_end);
if(item_at_front == item)
angle_end += 360;
angle_end = angle_in_360 (angle_end);
clutter_behaviour_ellipse_set_angle_start (
CLUTTER_BEHAVIOUR_ELLIPSE (this_item->ellipse_behaviour), angle_start);
clutter_behaviour_ellipse_set_angle_end (
CLUTTER_BEHAVIOUR_ELLIPSE (this_item->ellipse_behaviour), angle_end);
if(this_item == item){
if(angle_start < angle_end)
angle_diff = angle_end - angle_start;
else
angle_diff = 360 - (angle_start - angle_end);
printf(" debug: angle diff=%f/n", angle_diff);
}
// printf("%2d angle %.0f,%.0f/n", ++i,angle_start,angle_end);
angle_end += angle_step;
angle_start += angle_step;
list = g_slist_next(list);
}
const gint count = g_slist_length(list_items);
gint pos_to_move = count + pos_front - pos;
if(pos_to_move > count)
pos_to_move -= count;
int duration = (int) (5000.0/count * pos_to_move);
printf("old is %d want %d pos to move = %d duration = %d/n", pos_front,pos,pos_to_move,duration);
clutter_timeline_set_duration (timeline_rotation, duration);
item_at_front = item;
clutter_timeline_start (timeline_rotation);
}
int main(int argc, char * argv[]){
clutter_init(&argc,&argv);
ClutterColor stage_color = {0xB0,0xB0,0xB0,0xff};
ClutterActor * stage = clutter_stage_get_default();
clutter_actor_set_size(stage,800,600);
clutter_stage_set_color(CLUTTER_STAGE(stage),&stage_color);
/* Create and add a label actor, hidden at first: */
label_filename = clutter_text_new();
ClutterColor label_color = {0x00,0x00,0x00,0xff};
clutter_text_set_color( CLUTTER_TEXT(label_filename),&label_color);
clutter_text_set_font_name (CLUTTER_TEXT (label_filename), "微软雅黑 18");
clutter_actor_set_position (label_filename, 10, 10);
clutter_actor_set_opacity (label_filename, 0);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), label_filename);
/* Add a plane under the ellipse of images: */
ClutterColor rect_color = { 0xff, 0xff, 0xdf, 0xff }; /* white */
ClutterActor *rect = clutter_rectangle_new_with_color (&rect_color);
clutter_actor_set_height (rect, ELLIPSE_HEIGHT + 20);
clutter_actor_set_width (rect, clutter_actor_get_width (stage) + 100);
clutter_actor_set_position (rect, -(clutter_actor_get_width(rect) - clutter_actor_get_width(stage)) / 2,
ELLIPSE_Y + IMAGE_HEIGHT - (clutter_actor_get_height (rect) / 2));
clutter_actor_set_rotation (rect, CLUTTER_X_AXIS, 90.0, 0.0, (clutter_actor_get_height (rect) / 2.0), 0.0);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
timeline_rotation = clutter_timeline_new(5000);
g_signal_connect (timeline_rotation, "completed", G_CALLBACK (on_timeline_rotation_completed), NULL);
/* Add an actor for each image: */
load_images("./images/");
add_image_actors(stage);
if(list_items)
rotate_all_until_item_is_at_front ((Item*)list_items->data);
clutter_actor_show_all(stage);
clutter_main();
g_object_unref (timeline_rotation);
return EXIT_SUCCESS;
}