From 4c887c7062647c44a33c5dddeeff321298db6ba1 Mon Sep 17 00:00:00 2001
From: Nikias Bassen
Date: Wed, 14 Jul 2010 23:58:27 +0200
Subject: Make opening folders possible, manipulating still to come

---
 data/Makefile.am      |   2 +-
 data/foldermarker.png | Bin 0 -> 301 bytes
 src/gui.c             | 364 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 362 insertions(+), 4 deletions(-)
 create mode 100644 data/foldermarker.png

diff --git a/data/Makefile.am b/data/Makefile.am
index f1f45b2..866b85d 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,6 +1,6 @@
 pixmapdir = $(pkgdatadir)
 
-PIX = background.png dot.png folder.png
+PIX = background.png dot.png folder.png foldermarker.png
 
 pixmap_DATA = $(PIX)
 
diff --git a/data/foldermarker.png b/data/foldermarker.png
new file mode 100644
index 0000000..8a5c852
Binary files /dev/null and b/data/foldermarker.png differ
diff --git a/src/gui.c b/src/gui.c
index 6feadfc..d0cd371 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -52,6 +52,8 @@
 #define MAX_PAGE_ITEMS 16
 #define PAGE_X_OFFSET(i) ((gfloat)(i)*(gfloat)(STAGE_WIDTH))
 
+#define FOLDER_ANIM_DURATION 500
+
 const char CLOCK_FONT[] = "FreeSans Bold 12px";
 ClutterColor clock_text_color = { 255, 255, 255, 210 };
 
@@ -62,6 +64,8 @@ ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };  /* Black */
 ClutterColor battery_color = { 0xff, 0xff, 0xff, 0x9f };
 ClutterColor spinner_color = { 0xff, 0xff, 0xff, 0xf0 };
 
+const char FOLDER_LARGE_FONT[] = "FreeSans Bold 18px";
+
 GtkWidget *clutter_gtk_widget;
 
 const ClutterActorBox dock_area = { 0.0, STAGE_HEIGHT - DOCK_HEIGHT, STAGE_WIDTH, STAGE_HEIGHT };
@@ -88,6 +92,13 @@ ClutterTimeline *clock_timeline = NULL;
 GMutex *selected_mutex = NULL;
 SBItem *selected_item = NULL;
 
+ClutterActor *folder_marker = NULL;
+
+ClutterActor *aniupper = NULL;
+ClutterActor *anilower = NULL;
+ClutterActor *folder = NULL;
+gfloat split_pos = 0.0;
+
 GMutex *icon_loader_mutex = NULL;
 static int icons_loaded = 0;
 static int total_icons = 0;
@@ -778,6 +789,318 @@ static gboolean page_indicator_clicked_cb(ClutterActor *actor, ClutterButtonEven
     return TRUE;
 }
 
+static void gui_folder_align_icons(SBItem *item, gboolean animated)
+{
+    if (!item || !item->subitems)
+        return;
+
+    gint count = g_list_length(item->subitems);
+
+    gfloat ypos = 8.0 + 18.0 + 12.0;
+    gfloat xpos = 16.0;
+    gint i = 0;
+
+    /* set positions */
+    for (i = 0; i < count; i++) {
+        SBItem *si = g_list_nth_data(item->subitems, i);
+        if (!si) {
+            debug_printf("%s: item is null for i=%d\n", __func__, i);
+            continue;
+        }
+        if (!si->texture) {
+            debug_printf("%s: i=%d item->texture is null\n", __func__, i);
+            continue;
+        }
+        ClutterActor *icon = clutter_actor_get_parent(si->texture);
+        if (!icon) {
+            continue;
+        }
+
+        if (si != selected_item) {
+            if (animated) {
+                clutter_actor_animate(icon, CLUTTER_EASE_OUT_QUAD, 250, "x", xpos, "y", ypos, NULL);
+            } else {
+                clutter_actor_set_position(icon, xpos, ypos);
+            }
+        }
+
+        if (((i + 1) % 4) == 0) {
+            xpos = 16.0;
+            ypos += 88.0;
+        } else {
+            xpos += 76.0;
+        }
+    }
+}
+
+static gboolean folderview_close_finish(gpointer user_data)
+{
+    SBItem *item = (SBItem*)user_data;
+
+    ClutterActor *label = clutter_group_get_nth_child(CLUTTER_GROUP(folder), 1);
+
+    const gchar *oldname = clutter_text_get_text(CLUTTER_TEXT(item->label));
+    const gchar *newname = clutter_text_get_text(CLUTTER_TEXT(label));
+    if (g_str_equal(oldname, newname) == FALSE) {
+        gfloat oldwidth = clutter_actor_get_width(item->label);
+        clutter_text_set_text(CLUTTER_TEXT(item->label), newname);
+        plist_dict_remove_item(item->node, "displayName");
+        plist_dict_insert_item(item->node, "displayName", plist_new_string(newname));
+        gfloat newwidth = clutter_actor_get_width(item->label);
+        gfloat xshift = -(newwidth-oldwidth)/2;
+        clutter_actor_move_by(item->label, xshift, 0);
+    }
+    clutter_actor_show(item->label);
+
+    ClutterActor *newparent = clutter_actor_get_parent(item->texture);
+    GList *subitems = item->subitems;
+    guint i;
+    for (i = 0; i < g_list_length(subitems); i++) {
+        SBItem *si = g_list_nth_data(subitems, i);
+        ClutterActor *actor = clutter_actor_get_parent(si->texture);
+        clutter_actor_reparent(actor, newparent);
+        clutter_actor_hide(actor);
+    }
+    clutter_actor_destroy(folder);
+    folder = NULL;
+    clutter_actor_destroy(aniupper);
+    aniupper = NULL;
+    clutter_actor_destroy(anilower);
+    anilower = NULL;
+    split_pos = 0.0;
+
+    /* un-dim sb and dock items */
+    GList *page = g_list_nth_data(sbpages, current_page);
+    SBItem *it;
+    ClutterActor *act;
+    for (i = 0; i < g_list_length(page); i++) {
+        it = g_list_nth_data(page, i);
+        act = clutter_actor_get_parent(it->texture);
+        clutter_actor_set_opacity(act, 255);
+    }
+    for (i = 0; i < g_list_length(dockitems); i++) {
+        it = g_list_nth_data(dockitems, i);
+        act = clutter_actor_get_parent(it->texture);
+        clutter_actor_set_opacity(act, 255);
+    }
+
+    /* show page indicators */
+    clutter_actor_show(page_indicator_group);
+
+    clutter_actor_set_reactive(item->texture, TRUE);
+
+    return FALSE;
+}
+
+static gboolean folderview_close_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer user_data)
+{
+    /* discard double clicks */
+    if (event->click_count > 1) {
+        return FALSE;
+    }
+
+    SBItem *item = (SBItem*)user_data;
+
+    clutter_actor_set_reactive(item->texture, FALSE);
+
+    clutter_actor_set_reactive(aniupper, FALSE);
+    clutter_actor_set_reactive(anilower, FALSE);
+
+    clutter_actor_raise_top(aniupper);
+    clutter_actor_raise_top(anilower);
+    clutter_actor_animate(aniupper, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", 0.0, NULL);
+    clutter_actor_animate(anilower, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", 0.0, NULL);
+    clutter_actor_animate(folder, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", split_pos, NULL);
+
+    clutter_threads_add_timeout(FOLDER_ANIM_DURATION, (GSourceFunc)folderview_close_finish, user_data);
+
+    return TRUE;
+}
+
+static gboolean folderview_open_finish(gpointer user_data)
+{
+    ClutterActor *marker = clutter_group_get_nth_child(CLUTTER_GROUP(folder), 2);
+
+    clutter_actor_raise_top(folder);
+    clutter_actor_show(marker);
+
+    g_signal_connect(aniupper, "button-press-event", G_CALLBACK(folderview_close_cb), user_data);
+    g_signal_connect(anilower, "button-press-event", G_CALLBACK(folderview_close_cb), user_data);
+
+    return FALSE;
+}
+
+static void folderview_open(SBItem *item)
+{
+    GList *page = g_list_nth_data(sbpages, current_page);
+    guint i;
+    SBItem *it;
+    ClutterActor *act;
+    gfloat ypos = 0;
+    gfloat xpos = 0;
+
+    gboolean is_dock_folder = FALSE;
+
+    /* dim the springboard icons */
+    for (i = 0; i < g_list_length(page); i++) {
+        it = g_list_nth_data(page, i);
+        act = clutter_actor_get_parent(it->texture);
+        if (item == it) {
+            clutter_actor_set_opacity(act, 255);
+            ypos = 24.0+(gfloat)((int)(i / 4)+1) * 88.0;
+            xpos = 16 + ((i % 4))*76.0;
+            clutter_actor_hide(it->label);
+        } else {
+            clutter_actor_set_opacity(act, 64);
+        }
+    }
+
+    /* dim the dock icons */
+    guint count = g_list_length(dockitems);
+    for (i = 0; i < count; i++) {
+        it = g_list_nth_data(dockitems, i);
+        act = clutter_actor_get_parent(it->texture);
+        if (item == it) {
+            clutter_actor_set_opacity(act, 255);
+	    ypos = STAGE_HEIGHT-DOCK_HEIGHT-12.0;
+	    gfloat spacing = 16.0;
+	    if (count > 4) {
+		spacing = 3.0; 
+	    }
+            gfloat totalwidth = count*60.0 + (count-1) * spacing;
+	    xpos = (STAGE_WIDTH - totalwidth)/2.0 + (i*60.0) + (i*spacing);
+            clutter_actor_hide(it->label);
+	    is_dock_folder = TRUE;
+        } else {
+            clutter_actor_set_opacity(act, 64);
+        }
+    }
+
+    /* hide page indicators */
+    clutter_actor_hide(page_indicator_group);
+
+    /* make snapshot from the stage */
+    guchar *shot = clutter_stage_read_pixels(CLUTTER_STAGE(stage), 0, 0, STAGE_WIDTH, STAGE_HEIGHT);
+    if (!shot) {
+        printf("Error creating stage snapshot!\n");
+        return;
+    }
+
+    /* upper */
+    aniupper = clutter_texture_new();
+    clutter_texture_set_from_rgb_data(CLUTTER_TEXTURE(aniupper), shot, TRUE, STAGE_WIDTH, ypos, STAGE_WIDTH*4, 4, CLUTTER_TEXTURE_NONE, NULL);
+    clutter_container_add_actor(CLUTTER_CONTAINER(stage), aniupper);
+    clutter_actor_set_position(aniupper, 0, 0);
+    clutter_actor_set_reactive(aniupper, TRUE);
+    clutter_actor_show(aniupper);
+    clutter_actor_raise_top(aniupper);
+
+    /* lower */
+    anilower = clutter_texture_new();
+    clutter_texture_set_from_rgb_data(CLUTTER_TEXTURE(anilower), shot, TRUE, STAGE_WIDTH, STAGE_HEIGHT, STAGE_WIDTH*4, 4, CLUTTER_TEXTURE_NONE, NULL);
+    clutter_container_add_actor(CLUTTER_CONTAINER(stage), anilower);
+    clutter_actor_set_position(anilower, 0, 0);
+    clutter_actor_set_clip(anilower, 0.0, ypos, (gfloat)(STAGE_WIDTH), (gfloat)(STAGE_HEIGHT)-ypos);
+    clutter_actor_set_reactive(anilower, TRUE);
+    clutter_actor_show(anilower);
+    clutter_actor_raise_top(anilower);
+
+    /* create folder container */
+    folder = clutter_group_new();
+    clutter_container_add_actor(CLUTTER_CONTAINER(stage), folder);
+    clutter_actor_raise_top(folder);
+    clutter_actor_set_position(folder, 0, ypos);
+    clutter_actor_show(folder);
+
+    /* folder background rect */
+    ClutterColor folderbg = {0x70, 0x70, 0x70, 255};
+    act = clutter_rectangle_new_with_color(&folderbg);
+    ClutterColor folderbd = {0xe0, 0xe0, 0xe0, 255};
+    clutter_rectangle_set_border_color(CLUTTER_RECTANGLE(act), &folderbd);
+    clutter_rectangle_set_border_width(CLUTTER_RECTANGLE(act), 1);
+    clutter_actor_set_size(act, STAGE_WIDTH, 1);
+    clutter_actor_set_position(act, 0, 0);
+    clutter_actor_set_reactive(act, TRUE);
+    clutter_container_add_actor(CLUTTER_CONTAINER(folder), act);
+    clutter_actor_show(act);
+
+    /* create folder name label */
+    const gchar *ltext = clutter_text_get_text(CLUTTER_TEXT(item->label));
+    ClutterColor lcolor;
+    clutter_text_get_color(CLUTTER_TEXT(item->label), &lcolor);
+    ClutterActor *lbl = clutter_text_new_full(FOLDER_LARGE_FONT, ltext, &lcolor);
+    clutter_container_add_actor(CLUTTER_CONTAINER(folder), lbl);
+    clutter_actor_set_position(lbl, 16.0, 8.0);
+    clutter_text_set_editable(CLUTTER_TEXT(lbl), TRUE);
+    clutter_text_set_selectable(CLUTTER_TEXT(lbl), TRUE);
+    clutter_text_set_single_line_mode(CLUTTER_TEXT(lbl), TRUE);
+    clutter_text_set_line_wrap(CLUTTER_TEXT(lbl), FALSE);
+    clutter_actor_set_reactive(lbl, TRUE);
+    ClutterColor selcolor = {0, 0, 0xa0, 200};
+    ClutterColor curcolor = {0, 0, 0xa0, 255};
+    clutter_text_set_selection_color(CLUTTER_TEXT(lbl), &selcolor);
+    clutter_text_set_cursor_color(CLUTTER_TEXT(lbl), &curcolor);
+
+    /* calculate height */
+    gfloat fh = 8.0 + 18.0 + 8.0;
+    if (item->subitems && (g_list_length(item->subitems) > 0)) {
+        fh += (((g_list_length(item->subitems)-1)/4) + 1)*88.0;
+    } else {
+        fh += 88.0;
+    }
+
+    /* folder marker */
+    ClutterActor *marker = clutter_clone_new(folder_marker);
+    clutter_actor_unparent(marker);
+    clutter_container_add_actor(CLUTTER_CONTAINER(folder), marker);
+    if (is_dock_folder) {
+	clutter_actor_set_rotation(marker, CLUTTER_Z_AXIS, 180.0, 29.0, 8.0, 0.0);
+	clutter_actor_set_position(marker, xpos, fh-2.0);
+        clutter_actor_hide(marker);
+    } else {
+        clutter_actor_set_position(marker, xpos, -14.0);
+        clutter_actor_show(marker);
+    }
+
+    /* reparent the icons to the folder */
+    for (i = 0; i < g_list_length(item->subitems); i++) {
+        SBItem *si = g_list_nth_data(item->subitems, i);
+        ClutterActor *a = clutter_actor_get_parent(si->texture);
+        clutter_actor_reparent(a, folder);
+        clutter_actor_set_position(a, 0, 0);
+        clutter_actor_show(a);
+    }
+
+    /* align folder icons */
+    gui_folder_align_icons(item, FALSE);
+
+    /* distance to move upwards */
+    gfloat move_up_by = 0;
+    if (is_dock_folder) {
+	move_up_by = fh;
+    } else {
+        if ((ypos + fh) > (STAGE_HEIGHT - DOCK_HEIGHT/2)) {
+            move_up_by = (ypos + fh) - (STAGE_HEIGHT - DOCK_HEIGHT/2);
+	}
+    }
+
+    clutter_actor_raise_top(folder);
+    clutter_actor_raise_top(anilower);
+
+    /* now animate the actors */
+    clutter_actor_animate(act, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "height", fh, NULL);
+    clutter_actor_animate(folder, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", ypos-move_up_by, NULL);
+
+    clutter_actor_animate(aniupper, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", (gfloat) -move_up_by, NULL);
+    clutter_actor_animate(anilower, CLUTTER_EASE_IN_OUT_QUAD, FOLDER_ANIM_DURATION, "y", (gfloat) fh-move_up_by, NULL);
+
+    free(shot);
+
+    split_pos = ypos;
+
+    clutter_threads_add_timeout(FOLDER_ANIM_DURATION, (GSourceFunc)folderview_open_finish, item);
+}
+
 static gboolean item_button_press_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer user_data)
 {
     if (!user_data) {
@@ -790,12 +1113,21 @@ static gboolean item_button_press_cb(ClutterActor *actor, ClutterButtonEvent *ev
     }
 
     /* discard double clicks */
-    if (event->click_count > 1) {
+    if (event->click_count > 2) {
         return FALSE;
     }
 
     SBItem *item = (SBItem*)user_data;
 
+    if (event->click_count == 2) {
+        if (item->is_folder) {
+            folderview_open(item);
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    }
+    
     char *strval = sbitem_get_display_name(item);
 
     g_mutex_lock(selected_mutex);
@@ -924,6 +1256,16 @@ static gboolean stage_key_press_cb(ClutterActor *actor, ClutterEvent *event, gpo
     return TRUE;
 }
 
+static gboolean subitem_button_press_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer user_data)
+{
+    return TRUE;
+}
+
+static gboolean subitem_button_release_cb(ClutterActor *actor, ClutterButtonEvent *event, gpointer user_data)
+{
+    return TRUE;
+}
+
 static void gui_draw_subitems(SBItem *item)
 {
     ClutterActor *grp = clutter_actor_get_parent(item->texture);
@@ -937,6 +1279,8 @@ static void gui_draw_subitems(SBItem *item)
             clutter_container_add_actor(CLUTTER_CONTAINER(sgrp), actor);
             clutter_actor_set_position(actor, 0.0, 0.0);
             clutter_actor_set_reactive(actor, TRUE);
+            g_signal_connect(actor, "button-press-event", G_CALLBACK(subitem_button_press_cb), item);
+            g_signal_connect(actor, "button-release-event", G_CALLBACK(subitem_button_release_cb), item);
             clutter_actor_show(actor);
 
             actor = subitem->label;
@@ -1173,8 +1517,8 @@ static void gui_set_iconstate(plist_t iconstate, const char *format_version)
 
         /* load dock icons */
         debug_printf("%s: processing dock\n", __func__);
-        num_dock_items = gui_load_icon_row(dock, &dockitems);
-        total_icons += num_dock_items;
+        total_icons += gui_load_icon_row(dock, &dockitems);
+        num_dock_items = g_list_length(dockitems);
         if (total > 1) {
             /* get all page icons */
             int p, r, rows;
@@ -1497,6 +1841,20 @@ GtkWidget *gui_init()
         clutter_container_add_actor(CLUTTER_CONTAINER(stage), page_indicator);
     }
 
+    /* folder marker */
+    folder_marker = clutter_texture_new();
+    clutter_texture_set_load_async(CLUTTER_TEXTURE(folder_marker), TRUE);
+    clutter_texture_set_from_file(CLUTTER_TEXTURE(folder_marker), SBMGR_DATA "/foldermarker.png", &err);
+     if (err) {
+        fprintf(stderr, "Could not load texture " SBMGR_DATA "/foldermarker.png" ": %s\n", err->message);
+        g_error_free(err);
+        err = NULL;
+    }  
+    if (folder_marker) {
+        clutter_actor_hide(folder_marker);
+        clutter_container_add_actor(CLUTTER_CONTAINER(stage), folder_marker);
+    }
+
     /* a group for the springboard icons */
     the_sb = clutter_group_new();
     clutter_group_add(CLUTTER_GROUP(stage), the_sb);
-- 
cgit v1.1-32-gdbae