diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index 09a66f3..500ed82 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -152,9 +152,11 @@ void list_draw(struct screen *display, struct gui_synclist *list)
     int icon_yoffset = 0; /* to center the icon */
     bool show_title;
     struct viewport *list_text_vp = &list_text[screen];
-
+    int indent = 0;
+    int char_width;
     line_height = parent->line_height;
     display->set_viewport(parent);
+    char_width = display->getstringsize("M", NULL, NULL);
     display->clear_viewport();
     display->scroll_stop(list_text_vp);
     *list_text_vp = *parent;
@@ -247,9 +249,29 @@ void list_draw(struct screen *display, struct gui_synclist *list)
         unsigned char *entry_name;
         int text_pos = 0;
         int line = i - start;
+        indent = 0;
         s = list->callback_get_item_name(i, list->data, entry_buffer,
                                          sizeof(entry_buffer));
         entry_name = P2STR(s);
+        while (*entry_name == '\t')
+        {
+            indent++;
+            entry_name++;
+        }
+        if (indent)
+        {
+            if (icon_width)
+                indent *= icon_width;
+            else
+                indent *= char_width;
+        }
+        if (indent)
+        {
+            list_icons.x += indent;
+            list_text_vp->x += indent;
+            list_text_vp->width -= indent;
+        }
+            
         display->set_viewport(list_text_vp);
         style = STYLE_DEFAULT;
         /* position the string at the correct offset place */
@@ -351,6 +373,12 @@ void list_draw(struct screen *display, struct gui_synclist *list)
                             line*line_height + draw_offset + icon_yoffset,
                             Icon_Cursor);
         }
+        if (indent)
+        {
+            list_icons.x -= indent;
+            list_text_vp->x -= indent;
+            list_text_vp->width += indent;
+        }
     }
     display->set_viewport(parent);
     display->update_viewport();
diff --git a/apps/plugins/random_folder_advance_config.c b/apps/plugins/random_folder_advance_config.c
index f459aa0..9292ca2 100644
--- a/apps/plugins/random_folder_advance_config.c
+++ b/apps/plugins/random_folder_advance_config.c
@@ -5,9 +5,8 @@
  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  *                     \/            \/     \/    \/            \/
- * $Id$
  *
- * Copyright (C) 2006 Jonathan Gordon
+ * Copyright (C) 2011 Jonathan Gordon
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -18,360 +17,386 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "inttypes.h"
 #include "config.h"
+#include "core_alloc.h"
+#include "filetypes.h"
+#include "language.h"
+#include "list.h"
+#include "lang.h"
+#include "settings.h"
 #include "plugin.h"
-#include "file.h"
 
+#define RFA_FILE ROCKBOX_DIR "/folder_advance_list.dat"
+
+/*
+ * Order for changing child states:
+ * 1) expand folder (skip to 2 if empty)
+ * 2) collapse and select
+ * 3) unselect
+ */
+
+enum child_state {
+    EXPANDED,
+    SELECTED,
+    COLLAPSED
+};
 
 
-static bool cancel;
-static int fd;
-static int dirs_count;
-static int lasttick;
-#define RFA_FILE ROCKBOX_DIR "/folder_advance_list.dat"
-#define RFADIR_FILE ROCKBOX_DIR "/folder_advance_dir.txt"
-#define RFA_FILE_TEXT ROCKBOX_DIR "/folder_advance_list.txt"
-#define MAX_REMOVED_DIRS 10
+struct child {
+    char* name;
+    struct folder *folder;
+    enum child_state state;
+};
 
-char *buffer = NULL;
-size_t buffer_size;
-int num_replaced_dirs = 0;
-char removed_dirs[MAX_REMOVED_DIRS][MAX_PATH];
-struct file_format {
-    int count;
-    char folder[][MAX_PATH];
+struct folder {
+    char *name;
+    struct child *children;
+    int children_count;
+    int depth;
+    
+    struct folder* previous;
 };
-struct file_format *list = NULL;
 
-static void update_screen(bool clear)
+static char *buffer_front, *buffer_end;
+static char* folder_alloc(size_t size)
 {
-    char buf[15];
+    char* retval;
+    /* 32-bit aligned */
+    size = (size + 3) & ~3;
+    if (buffer_front + size > buffer_end)
+    {
+        return NULL;
+    }
+    retval = buffer_front;
+    buffer_front += size;
+    return retval;
+}
+static char* folder_alloc_from_end(size_t size)
+{
+    if (buffer_end - size < buffer_front)
+    {
+        return NULL;
+    }
+    buffer_end -= size;
+    return buffer_end;
+}
+
 
-    rb->snprintf(buf,sizeof(buf),"Folders: %d",dirs_count);
-    FOR_NB_SCREENS(i)
+static char* get_full_path(struct folder *start)
+{
+    static char buffer[MAX_PATH];
+    char *buf = &buffer[MAX_PATH-1];
+    int remaining = MAX_PATH-1;
+    struct folder *this = start;
+    if (start == NULL)
+        return "/";
+    buf[0] = '\0';
+    buf--;
+    remaining--;
+    while (this)
     {
-        if(clear)
-            rb->screens[i]->clear_display();
-        rb->screens[i]->putsxy(0,0,buf);
-        rb->screens[i]->update();
+        int len = rb->strlen(this->name);
+        if (len + 1 > remaining)
+            return NULL;
+        buf -= len + 1;
+        rb->memcpy(buf, this->name, len);
+        buf[len] = '/';
+        this = this->previous;
     }
+    if (remaining < 1)
+        return NULL;
+    /* remove the trailing / */
+    buf[rb->strlen(buf)-1] = '\0';
+    return buf;
+}
+/* support function for qsort() */
+static int compare(const void* p1, const void* p2)
+{
+    struct child *left = (struct child*)p1;
+    struct child *right = (struct child*)p2;
+    return rb->strcasecmp(left->name, right->name);
 }
 
-static void traversedir(char* location, char* name)
+static struct folder* load_folder(struct folder* parent, char *folder)
 {
+    DIR *dir;
+    char* path = get_full_path(parent);
+    char fullpath[MAX_PATH];
     struct dirent *entry;
-    DIR* dir;
-    char fullpath[MAX_PATH], path[MAX_PATH];
-    bool check = false;
-    int i;
-
-    rb->snprintf(fullpath, sizeof(fullpath), "%s/%s", location, name);
+    struct folder* this = (struct folder*)folder_alloc(sizeof(struct folder));
+    int child_count = 0;
+    char *first_child = NULL;
+    
+    rb->snprintf(fullpath, MAX_PATH, "%s/%s", parent ? path : "", folder);
+    
+    if (!this)
+        return NULL;
     dir = rb->opendir(fullpath);
-    if (dir) {
-        entry = rb->readdir(dir);
-        while (entry) {
-            if (cancel)
-                break;
-            /* Skip .. and . */
-            if (entry->d_name[0] == '.')
-            {
-                if (    !rb->strcmp(entry->d_name,".")
-                     || !rb->strcmp(entry->d_name,"..")
-                     || !rb->strcmp(entry->d_name,".rockbox"))
-                    check = false;
-                else check = true;
-            }
-            else check = true;
-
-        /* check if path is removed directory, if so dont enter it */
-        rb->snprintf(path, MAX_PATH, "%s/%s", fullpath, entry->d_name);
-        while(path[0] == '/')
-            rb->strlcpy(path, path + 1, sizeof(path));
-        for(i = 0; i < num_replaced_dirs; i++)
-        {
-            if(!rb->strcmp(path, removed_dirs[i]))
-            {
-                check = false;
-                break;
-            }
+    if (!dir)
+        return NULL;
+    this->previous = parent;
+    this->name = folder;
+    this->children = NULL;
+    this->children_count = 0;
+    this->depth = parent ? parent->depth + 1 : -1;
+    
+    while ((entry = rb->readdir(dir))) {
+        int len = rb->strlen((char *)entry->d_name);
+        struct dirinfo info;
+        
+        info = rb->dir_get_info(dir, entry);
+        
+        /* skip anything not a directory */
+        if ((info.attribute & ATTR_DIRECTORY) == 0) {
+            continue;
         }
-
-            if (check)
-            {
-                struct dirinfo info = rb->dir_get_info(dir, entry);
-                if (info.attribute & ATTR_DIRECTORY) {
-                    char *start;
-                    dirs_count++;
-                    rb->snprintf(path,MAX_PATH,"%s/%s",fullpath,entry->d_name);
-                    start = &path[rb->strlen(path)];
-                    rb->memset(start,0,&path[MAX_PATH-1]-start);
-                    rb->write(fd,path,MAX_PATH);
-                    traversedir(fullpath, entry->d_name);
-                }
-            }
-            if (*rb->current_tick - lasttick > (HZ/2)) {
-                update_screen(false);
-                lasttick = *rb->current_tick;
-                if (rb->action_userabort(TIMEOUT_NOBLOCK))
-                {
-                    cancel = true;
-                    break;
-                }
+        /* skip directories . and .. */
+        if ((((len == 1) && (!rb->strncmp((char *)entry->d_name, ".", 1))) ||
+            ((len == 2) && (!rb->strncmp((char *)entry->d_name, "..", 2))))) {
+            continue;
             }
-
-            entry = rb->readdir(dir);
-        }
-        rb->closedir(dir);
+            char *name = folder_alloc_from_end(len+1);
+        if (!name)
+            return NULL;
+        rb->memcpy(name, (char *)entry->d_name, len+1);
+        child_count++;
+        first_child = name;
+    }
+    rb->closedir(dir);
+    /* now put the names in the array */
+    this->children = (struct child*)folder_alloc(sizeof(struct child) * child_count);
+    if (!this->children)
+        return NULL;
+    while (child_count)
+    {
+        this->children[this->children_count].name = first_child;
+        this->children[this->children_count].folder = NULL;
+        this->children[this->children_count].state = COLLAPSED;
+        this->children_count++;
+        first_child += rb->strlen(first_child) + 1;
+        child_count--;
     }
+    rb->qsort(this->children, this->children_count, sizeof(struct child), compare);
+    return this;
 }
 
-static bool custom_dir(void)
+static int count_items(struct folder *start)
 {
-    DIR* dir_check;
-    char *starts, line[MAX_PATH], formatted_line[MAX_PATH];
-    static int fd2;
-    char buf[11];
-    int i, errors = 0;
+    int count = 0;
+    int i;
+    
+    for (i=0; i<start->children_count; i++)
+    {
+        struct child *foo = &start->children[i];
+        if (foo->state == EXPANDED)
+            count += count_items(foo->folder);
+        count++;
+    }
+    return count;
+}    
 
-    /* populate removed dirs array */
-    if((fd2 = rb->open(RFADIR_FILE,O_RDONLY)) >= 0)
+static struct child* find_index(struct folder *start, int index, struct folder **parent)
+{
+    int i = 0;
+    while (i < start->children_count)
     {
-        while ((rb->read_line(fd2, line, MAX_PATH - 1)) > 0)
+        struct child *foo = &start->children[i];
+        if (i == index)
+        {
+            *parent = start;
+            return foo;
+        }
+        i++;
+        if (foo->state == EXPANDED)
         {
-            if ((line[0] == '-') && (line[1] == '/') &&
-                     (num_replaced_dirs < MAX_REMOVED_DIRS))
+            struct child *bar = find_index(foo->folder, index - i, parent);
+            if (bar)
             {
-                num_replaced_dirs ++;
-                rb->strlcpy(removed_dirs[num_replaced_dirs - 1], line + 2,
-                                sizeof(line));
+                return bar;
             }
+            index -= count_items(foo->folder);
         }
-        rb->close(fd2);
     }
+    return NULL;
+}
 
-    if((fd2 = rb->open(RFADIR_FILE,O_RDONLY)) >= 0)
+static const char * folder_get_name(int selected_item, void * data,
+                                    char * buffer, size_t buffer_len)
+{
+    (void)buffer_len;
+    struct folder *root = (struct folder*)data;
+    struct folder *parent = NULL;
+    struct child *this = find_index(root, selected_item, &parent);
+    
+    buffer[0] = '\0';
+    if (parent->depth >= 0)
     {
-        while ((rb->read_line(fd2, line, MAX_PATH - 1)) > 0)
+        int i = 0;
+        while (i < parent->depth + 1)
         {
-            /* blank lines and removed dirs ignored */
-            if (rb->strlen(line) && ((line[0] != '-') || (line[1] != '/')))
-            {
-                /* remove preceeding '/'s from the line */
-                while(line[0] == '/')
-                    rb->strlcpy(line, line + 1, sizeof(line));
-
-                rb->snprintf(formatted_line, MAX_PATH, "/%s", line);
-
-                dir_check = rb->opendir(formatted_line);
-
-                if (dir_check)
-                {
-                    rb->closedir(dir_check);
-                    starts = &formatted_line[rb->strlen(formatted_line)];
-                    rb->memset(starts, 0, &formatted_line[MAX_PATH-1]-starts);
-                    bool write_line = true;
-
-                    for(i = 0; i < num_replaced_dirs; i++)
-                    {
-                        if(!rb->strcmp(line, removed_dirs[i]))
-                        {
-                             write_line = false;
-                             break;
-                        }
-                    }
-
-                    if(write_line)
-                    {
-                        dirs_count++;
-                        rb->write(fd, formatted_line, MAX_PATH);
-                    }
-
-                    traversedir("", line);
-                }
-                else
-                {
-                     errors ++;
-                     rb->snprintf(buf,sizeof(buf),"Not found:");
-                     FOR_NB_SCREENS(i)
-                     {
-                         rb->screens[i]->puts(0,0,buf);
-                         rb->screens[i]->puts(0, errors, line);
-                     }
-                     update_screen(false);
-                }
-            }
+            rb->strcat(buffer, "\t");
+            i++;
         }
-        rb->close(fd2);
-        if(errors)
-            /* Press button to continue */
-            rb->get_action(CONTEXT_STD, TIMEOUT_BLOCK); 
     }
-    else
-        return false;
-    return true;
+    rb->strcat(buffer, this->name);
+    return buffer;
 }
 
-static void generate(void)
+static enum themable_icons folder_get_icon(int selected_item, void * data)
 {
-    dirs_count = 0;
-    cancel = false;
-    fd = rb->open(RFA_FILE,O_CREAT|O_WRONLY, 0666);
-    rb->write(fd,&dirs_count,sizeof(int));
-    if (fd < 0)
+    struct folder *root = (struct folder*)data;
+    struct folder *parent = NULL;
+    struct child *this = find_index(root, selected_item, &parent);
+    
+    switch (this->state)
     {
-        rb->splashf(HZ, "Couldnt open %s", RFA_FILE);
-        return;
+        case SELECTED:
+            return Icon_Cursor;
+        case COLLAPSED:
+            return Icon_Folder;
+        case EXPANDED:
+            return Icon_Submenu;
     }
-#ifndef HAVE_LCD_CHARCELLS
-    update_screen(true);
-#endif
-    lasttick = *rb->current_tick;
-
-    if(!custom_dir())
-        traversedir("", "");
-
-    rb->lseek(fd,0,SEEK_SET);
-    rb->write(fd,&dirs_count,sizeof(int));
-    rb->close(fd);
-    rb->splash(HZ, "Done");
+    return Icon_NOICON;
 }
-
-static const char* list_get_name_cb(int selected_item, void* data,
-                                    char* buf, size_t buf_len)
+static bool list_dirty;
+static int folder_action_callback(int action, struct gui_synclist *list)
 {
-    (void)data;
-    rb->strlcpy(buf, list->folder[selected_item], buf_len);
-    return buf;
+    struct folder *root = (struct folder*)list->data;
+    if (action == ACTION_STD_OK)
+    {
+        struct folder *parent = NULL;
+        struct child *this = find_index(root, list->selected_item, &parent);        
+        switch (this->state)
+        {
+            case EXPANDED:
+                this->state = SELECTED;
+                break;
+            case SELECTED:
+                this->state = COLLAPSED;
+                if (this->folder && this->folder->children_count == 0)
+                    this->state = COLLAPSED;
+                break;
+            case COLLAPSED:
+                if (this->folder == NULL)
+                    this->folder = load_folder(parent, this->name);
+                this->state = this->folder->children_count == 0 ?
+                SELECTED : EXPANDED;
+        }
+        list->nb_items = count_items(root);
+        list_dirty = true;
+        return ACTION_REDRAW;
+    }
+    return action;
 }
 
-static int load_list(void)
+static struct child* find_from_filename(char* filename, struct folder *root)
 {
-    int myfd = rb->open(RFA_FILE,O_RDONLY);
-    if (myfd < 0)
-        return -1;
-    buffer = rb->plugin_get_audio_buffer(&buffer_size);
-    if (!buffer)
+    char *slash = rb->strchr(filename, '/');
+    int i = 0;
+    if (slash)
+        *slash = '\0';
+    if (!root)
+        return NULL;
+    
+    while (i < root->children_count)
     {
-        return -2;
+        struct child *this = &root->children[i];
+        if (!rb->strcasecmp(this->name, filename))
+        {
+            if (!slash)
+                return this;
+            if (!this->folder)
+                this->folder = load_folder(root, this->name);
+            this->state = EXPANDED;
+            return find_from_filename(slash+1, this->folder);
+        }
+        i++;
     }
-    
-    rb->read(myfd,buffer,buffer_size);
-    rb->close(myfd);
-    list = (struct file_format *)buffer;
-    
-    return 0;
+    return NULL;
 }
 
-static int save_list(void)
+static int save_folders(struct folder *root, int fd)
 {
-    int myfd = rb->creat(RFA_FILE, 0666);
-    if (myfd < 0)
-    {
-        rb->splash(HZ, "Could Not Open " RFA_FILE);
-        return -1;
-    }
-    int dirs_count = 0, i = 0;
-    rb->write(myfd,&dirs_count,sizeof(int));
-    for ( ;i<list->count;i++)
+    int i = 0;
+    int total = 0;
+    
+    while (i < root->children_count)
     {
-        if (list->folder[i][0] != ' ')
+        struct child *this = &root->children[i];
+        if (this->state == SELECTED)
         {
-            dirs_count++;
-            rb->write(myfd,list->folder[i],MAX_PATH);
+            char buffer[MAX_PATH];
+            rb->memset(buffer, 0, MAX_PATH);
+            if (this->folder)
+                rb->snprintf(buffer, MAX_PATH,
+                         "%s", get_full_path(this->folder));
+            else
+                rb->snprintf(buffer, MAX_PATH,
+                            "%s/%s", get_full_path(root), this->name);
+            rb->write(fd, buffer, MAX_PATH);
+            total++;
         }
+        else if (this->state == EXPANDED)
+            total += save_folders(this->folder, fd);
+        i++;
     }
-    rb->lseek(myfd,0,SEEK_SET);
-    rb->write(myfd,&dirs_count,sizeof(int));
-    rb->close(myfd);
-    
-    return 1;
+    return total;
 }
 
-static int edit_list(void)
+void folder_advance_config(void)
 {
-    struct gui_synclist lists;
-    bool exit = false;
-    int button,i;
-    int selection, ret = 0;
+    struct folder *root;
+    struct simplelist_info info;
+    size_t buf_size;
+    int fd;
+    char buf[512];
     
-    /* load the dat file if not already done */
-    if ((list == NULL || list->count == 0) && (i = load_list()) != 0)
+    buffer_front = rb->plugin_get_buffer(&buf_size);
+    buffer_end = buffer_front + buf_size;
+    root = load_folder(NULL, "");
+
+    fd = rb->open_utf8(RFA_FILE, O_RDONLY);
+    if (fd >= 0)
     {
-        rb->splashf(HZ*2, "Could not load %s, rv = %d", RFA_FILE, i);
-        return -1;
+        rb->lseek(fd, 4, SEEK_SET);
+        while (rb->read(fd, buf, MAX_PATH))
+        {
+            char* slash = rb->strchr(buf, '/');
+            struct child *item = find_from_filename(slash ? slash + 1 : buf, root);
+            if (item)
+                item->state = SELECTED;
+        }
+        rb->close(fd);
     }
+    list_dirty = false;
     
-    dirs_count = list->count;
+    rb->simplelist_info_init(&info, "Choose folders for random advance",
+                         count_items(root), root);
+    info.get_name = folder_get_name;
+    info.action_callback = folder_action_callback;
+    info.get_icon = folder_get_icon;
+    rb->simplelist_show_list(&info);
     
-    rb->gui_synclist_init(&lists,list_get_name_cb,0, false, 1, NULL);
-    rb->gui_synclist_set_icon_callback(&lists,NULL);
-    rb->gui_synclist_set_nb_items(&lists,list->count);
-    rb->gui_synclist_limit_scroll(&lists,true);
-    rb->gui_synclist_select_item(&lists, 0);
-    
-    while (!exit)
+    if (list_dirty )//FIXME&& rb->yesno_pop(ID2P(LANG_SAVE_CHANGES)))
     {
-        rb->gui_synclist_draw(&lists);
-        button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
-        if (rb->gui_synclist_do_button(&lists,&button,LIST_WRAP_UNLESS_HELD))
-            continue;
-        selection = rb->gui_synclist_get_sel_pos(&lists);
-        switch (button)
+        fd = rb->open(RFA_FILE, O_CREAT|O_TRUNC|O_RDWR);
+        if (fd >= 0)
         {
-            case ACTION_STD_OK:
-                list->folder[selection][0] = ' ';
-                list->folder[selection][1] = '\0';
-                break;
-            case ACTION_STD_CONTEXT:
-            {
-                int len;
-                MENUITEM_STRINGLIST(menu, "Remove Menu", NULL,
-                                    "Remove Folder", "Remove Folder Tree");
-
-                switch (rb->do_menu(&menu, NULL, NULL, false))
-                {
-                    case 0:
-                        list->folder[selection][0] = ' ';
-                        list->folder[selection][1] = '\0';
-                        break;
-                    case 1:
-                    {
-                        char temp[MAX_PATH];
-                        rb->strcpy(temp,list->folder[selection]);
-                        len = rb->strlen(temp);
-                        for (i=0;i<list->count;i++)
-                        {
-                            if (!rb->strncmp(list->folder[i],temp,len))
-                            {
-                                list->folder[i][0] = ' ';
-                                list->folder[i][1] = '\0';
-                            }
-                        }
-                    }
-                    break;
-                }
-            }
-            break;
-            case ACTION_STD_CANCEL:
-            {
-                MENUITEM_STRINGLIST(menu, "Exit Menu", NULL,
-                                    "Save and Exit", "Ignore Changes and Exit");
-
-                switch (rb->do_menu(&menu, NULL, NULL, false))
-                {
-                    case 0:
-                        save_list();
-                    case 1:
-                        exit = true;
-                        ret = -2;
-                }
-            }
-            break;
+            int count = 0;
+            rb->write(fd, &count, 4);
+            count = save_folders(root, fd);
+            rb->lseek(fd, 0, SEEK_SET);
+            rb->write(fd, &count, 4);
+            rb->close(fd);
         }
     }
-    return ret;
 }
-
+#if 0
 static int export_list_to_file_text(void)
 {
     int i = 0;
@@ -617,15 +642,14 @@ static enum plugin_status main_menu(void)
     }
     return PLUGIN_OK;
 }
-
+#endif
 enum plugin_status plugin_start(const void* parameter)
 {
     (void)parameter;
 #ifdef HAVE_TOUCHSCREEN
     rb->touchscreen_set_mode(rb->global_settings->touch_mode);
 #endif
+    folder_advance_config();
 
-    cancel = false;
-    
-    return main_menu();
+    return PLUGIN_OK;//main_menu();
 }
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 979a14d..93d496f 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -731,7 +731,7 @@ Lyre prototype 1 */
  * plenty of RAM. Both features can be enabled independently. */
 #if (MEMORYSIZE >= 8) && !defined(BOOTLOADER) && !defined(__PCTOOL__) \
     && !defined(APPLICATION)
-#define HAVE_DIRCACHE
+//#define HAVE_DIRCACHE
 #ifdef HAVE_TAGCACHE
 #define HAVE_TC_RAMCACHE
 #endif
