Clutter学习(十四):用一个较大的例子来复习

我们已经学习了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;
}

相关链接:我的Clutter相关博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值