Initial multi screen support by Kévin Ferrare (Patch #1318081)


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7666 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/SOURCES b/apps/SOURCES
index 26af159..07c121f 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -31,6 +31,15 @@
 filetree.c
 wps-display.c
 wps.c
+
+screen_access.c
+gui/buttonbar.c
+gui/icon.c
+gui/list.c
+gui/scrollbar.c
+gui/splash.c
+gui/statusbar.c
+
 #ifdef HAVE_LCD_CHARCELLS
 player/icons.c
 player/keyboard.c
diff --git a/apps/dbtree.c b/apps/dbtree.c
index e3704ac..9ea0706 100644
--- a/apps/dbtree.c
+++ b/apps/dbtree.c
@@ -43,6 +43,7 @@
 #include "lang.h"
 #include "keyboard.h"
 #include "autoconf.h"
+#include "list.h"
 
 static int db_play_folder(struct tree_context* c);
 static int db_search(struct tree_context* c, char* string);
@@ -69,17 +70,18 @@
         c->filesindir = 0;
         return 0;
     }
-    
+
     c->dentry_size = 2;
     c->dirfull = false;
 
-    DEBUGF("db_load() table: %d extra: 0x%x  firstpos: %d\n", table, extra, c->firstpos);
+    DEBUGF("db_load() table: %d extra: 0x%x  firstpos: %d\n", table, extra,
+                                                              c->firstpos);
 
     if (!table) {
         table = root;
         c->currtable = table;
     }
-    
+
     switch (table) {
         case root: {
             static const int tables[] = {allartists, allalbums, allsongs,
@@ -138,28 +140,28 @@
             return i;
 
         case allsongs:
-            DEBUGF("dbload table allsongs\n");                
+            DEBUGF("dbload table allsongs\n");
             offset = tagdbheader.songstart + c->firstpos * SONGENTRY_SIZE;
             itemcount = tagdbheader.songcount;
             stringlen = tagdbheader.songlen;
             break;
 
         case allalbums:
-            DEBUGF("dbload table allalbums\n");                
+            DEBUGF("dbload table allalbums\n");
             offset = tagdbheader.albumstart + c->firstpos * ALBUMENTRY_SIZE;
             itemcount = tagdbheader.albumcount;
             stringlen = tagdbheader.albumlen;
             break;
 
         case allartists:
-            DEBUGF("dbload table allartists\n");                
+            DEBUGF("dbload table allartists\n");
             offset = tagdbheader.artiststart + c->firstpos * ARTISTENTRY_SIZE;
             itemcount = tagdbheader.artistcount;
             stringlen = tagdbheader.artistlen;
             break;
 
         case albums4artist:
-            DEBUGF("dbload table albums4artist\n");                
+            DEBUGF("dbload table albums4artist\n");
             /* 'extra' is offset to the artist */
             safeplacelen = tagdbheader.albumarraylen * 4;
             safeplace = (void*)(end_of_nbuf - safeplacelen);
@@ -199,13 +201,13 @@
             break;
 
         case songs4artist:
-            DEBUGF("dbload table songs4artist\n");                
+            DEBUGF("dbload table songs4artist\n");
             /* 'extra' is offset to the artist, used as filter */
             offset = tagdbheader.songstart + c->firstpos * SONGENTRY_SIZE;
             itemcount = tagdbheader.songcount;
             stringlen = tagdbheader.songlen;
             break;
-            
+
         default:
             DEBUGF("Unsupported table %d\n", table);
             return -1;
@@ -248,7 +250,8 @@
             case songs4album:
             case songs4artist:
                 rc = read(tagdb_fd, intbuf, 12);
-                skip = SONGENTRY_SIZE-stringlen-12; /* skip the rest of the song info */
+                 /* skip the rest of the song info */
+                skip = SONGENTRY_SIZE-stringlen-12;
                 if (rc < 12) {
                     DEBUGF("%d read(%d) returned %d\n", i, 12, rc);
                     return -1;
@@ -287,7 +290,7 @@
 
         if(table==songs4artist)
                 c->dirlength=hits;
-        
+
         /* next name is stored immediately after this */
         nptr = (void*)nptr + strlen((char*)nptr) + 1;
         if ((void*)nptr + stringlen > (void*)end_of_nbuf) {
@@ -314,7 +317,7 @@
         dptr[1] = extra; /* offset to artist */
         hits++;
     }
-    
+
     c->filesindir = hits;
 
     return hits;
@@ -350,7 +353,7 @@
             count = tagdbheader.songcount;
             size = SONGENTRY_SIZE;
             break;
-            
+
         default:
             DEBUGF("Invalid table %d\n", c->currtable);
             return 0;
@@ -384,7 +387,7 @@
                 c->dirfull = true;
                 break;
             }
-    
+
             nptr += strlen(nptr) + 1;
             while ((unsigned long)nptr & 3)
                 nptr++;
@@ -403,25 +406,24 @@
 int db_enter(struct tree_context* c)
 {
     int rc = 0;
-    int offset = (c->dircursor + c->dirstart) * c->dentry_size + 1;
+    int offset = (c->selected_item) * c->dentry_size + 1;
     int newextra = ((int*)c->dircache)[offset];
 
     if (c->dirlevel >= MAX_DIR_LEVELS)
         return 0;
-    
-    c->dirpos[c->dirlevel] = c->dirstart;
-    c->cursorpos[c->dirlevel] = c->dircursor;
+
+    c->selected_item_history[c->dirlevel]=c->selected_item;
     c->table_history[c->dirlevel] = c->currtable;
     c->extra_history[c->dirlevel] = c->currextra;
     c->pos_history[c->dirlevel] = c->firstpos;
     c->dirlevel++;
-    
+
     switch (c->currtable) {
         case root:
             c->currtable = newextra;
             c->currextra = newextra;
             break;
-            
+
         case allartists:
         case searchartists:
             c->currtable = albums4artist;
@@ -457,13 +459,13 @@
             else
                 c->currtable = newextra;
             break;
-            
+
         default:
             c->dirlevel--;
             break;
     }
-
-    c->dirstart = c->dircursor = c->firstpos = 0;
+    c->selected_item=0;
+    gui_synclist_select_item(&tree_lists, c->selected_item);
 
     return rc;
 }
@@ -471,8 +473,8 @@
 void db_exit(struct tree_context* c)
 {
     c->dirlevel--;
-    c->dirstart = c->dirpos[c->dirlevel];
-    c->dircursor = c->cursorpos[c->dirlevel];
+    c->selected_item=c->selected_item_history[c->dirlevel];
+    gui_synclist_select_item(&tree_lists, c->selected_item);
     c->currtable = c->table_history[c->dirlevel];
     c->currextra = c->extra_history[c->dirlevel];
     c->firstpos  = c->pos_history[c->dirlevel];
@@ -481,9 +483,8 @@
 int db_get_filename(struct tree_context* c, char *buf, int buflen)
 {
     int rc;
-    int filenum = c->dircursor + c->dirstart;
-    int pathoffset = ((int*)c->dircache)[filenum * c->dentry_size + 1];
-    
+    int pathoffset = ((int*)c->dircache)[c->selected_item * c->dentry_size + 1];
+
     lseek(tagdb_fd, pathoffset, SEEK_SET);
     rc = read(tagdb_fd, buf, buflen);
 
@@ -498,7 +499,6 @@
 {
     char buf[MAX_PATH];
     int rc, i;
-    int filenum = c->dircursor + c->dirstart;
 
     if (playlist_create(NULL, NULL) < 0) {
         DEBUGF("Failed creating playlist\n");
@@ -506,7 +506,7 @@
     }
 
     /* TODO: add support for very long tables */
-    
+
     for (i=0; i < c->filesindir; i++) {
         int pathoffset = ((int*)c->dircache)[i * c->dentry_size + 1];
         lseek(tagdb_fd, pathoffset, SEEK_SET);
@@ -520,11 +520,12 @@
     }
 
     if (global_settings.playlist_shuffle)
-        filenum = playlist_shuffle(current_tick, filenum);
+        c->selected_item = playlist_shuffle(current_tick, c->selected_item);
     if (!global_settings.play_selected)
-        filenum = 0;
+        c->selected_item = 0;
+    gui_synclist_select_item(&tree_lists, c->selected_item);
 
-    playlist_start(filenum,0);
+    playlist_start(c->selected_item,0);
 
     return 0;
 }
diff --git a/apps/filetree.c b/apps/filetree.c
index 37a66c6..e8b8df7 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -79,12 +79,12 @@
     struct dircache_entry *entry;
     struct entry* dircache = c->dircache;
     DIRCACHED *dir;
-    
+
     dir = opendir_cached(c->currdir);
     if(!dir)
         return;
-
-    for (i=0; i < c->filesindir; i++) /* mark all files as non talking, except the .talk ones */
+    /* mark all files as non talking, except the .talk ones */
+    for (i=0; i < c->filesindir; i++)
     {
         if (dircache[i].attr & ATTR_DIRECTORY)
             continue; /* we're not touching directories */
@@ -100,7 +100,7 @@
             dircache[i].attr |= TREE_ATTR_THUMBNAIL; /* set */
         }
     }
-    
+
     while((entry = readdir_cached(dir)) != 0) /* walk directory */
     {
         int ext_pos;
@@ -110,13 +110,13 @@
             || (entry->attribute & ATTR_DIRECTORY) /* no file */
             || strcasecmp(&entry->d_name[ext_pos], file_thumbnail_ext))
         {   /* or doesn't end with ".talk", no candidate */
-            continue; 
+            continue;
         }
-        
+
         /* terminate the (disposable) name in dir buffer,
            this truncates off the ".talk" without needing an extra buffer */
         entry->d_name[ext_pos] = '\0';
-        
+
         /* search corresponding file in dir cache */
         for (i=0; i < c->filesindir; i++)
         {
@@ -187,7 +187,7 @@
     return 0; /* never reached */
 }
 
-/* load and sort directory into dircache.  returns NULL on failure. */
+/* load and sort directory into dircache. returns NULL on failure. */
 int ft_load(struct tree_context* c, const char* tempdir)
 {
     int i;
@@ -256,7 +256,7 @@
             boot_cluster = entry->startcluster;
         }
 #endif
-        
+
         /* filter out non-visible files */
         if ((!(dptr->attr & ATTR_DIRECTORY) && (
             (*c->dirfilter == SHOW_PLAYLIST &&
@@ -289,7 +289,7 @@
         name_buffer_used += len + 1;
 
         if (dptr->attr & ATTR_DIRECTORY) /* count the remaining dirs */
-            c->dirsindir++; 
+            c->dirsindir++;
     }
     c->filesindir = i;
     c->dirlength = i;
@@ -297,7 +297,7 @@
 
     qsort(c->dircache,i,sizeof(struct entry),compare);
 
-    /* If thumbnail talking is enabled, make an extra run to mark files with 
+    /* If thumbnail talking is enabled, make an extra run to mark files with
        associated thumbnails, so we don't do unsuccessful spinups later. */
     if (global_settings.talk_file == 3)
         check_file_thumbnails(c); /* map .talk to ours */
@@ -310,7 +310,7 @@
     int rc = 0;
     char buf[MAX_PATH];
     struct entry *dircache = c->dircache;
-    struct entry* file = &dircache[c->dircursor + c->dirstart];
+    struct entry* file = &dircache[c->selected_item];
     bool reload_dir = false;
     bool start_wps = false;
     bool exit_func = false;
@@ -322,13 +322,10 @@
 
     if (file->attr & ATTR_DIRECTORY) {
         memcpy(c->currdir, buf, sizeof(c->currdir));
-        if ( c->dirlevel < MAX_DIR_LEVELS ) {
-            c->dirpos[c->dirlevel] = c->dirstart;
-            c->cursorpos[c->dirlevel] = c->dircursor;
-        }
+        if ( c->dirlevel < MAX_DIR_LEVELS )
+            c->selected_item_history[c->dirlevel] = c->selected_item;
         c->dirlevel++;
-        c->dircursor=0;
-        c->dirstart=0;
+        c->selected_item=0;
     }
     else {
         int seed = current_tick;
@@ -357,8 +354,7 @@
 
                 if (playlist_create(c->currdir, NULL) != -1)
                 {
-                    start_index =
-                        ft_build_playlist(c, c->dircursor + c->dirstart);
+                    start_index = ft_build_playlist(c, c->selected_item);
                     if (global_settings.playlist_shuffle)
                     {
                         start_index = playlist_shuffle(seed, start_index);
@@ -497,14 +493,13 @@
             exit_func = true;
 
         c->dirlevel--;
-        if ( c->dirlevel < MAX_DIR_LEVELS ) {
-            c->dirstart = c->dirpos[c->dirlevel];
-            c->dircursor = c->cursorpos[c->dirlevel];
-        }
+        if ( c->dirlevel < MAX_DIR_LEVELS )
+            c->selected_item=c->selected_item_history[c->dirlevel];
         else
-            c->dirstart = c->dircursor = 0;
+            c->selected_item=0;
 
-        if (c->dirstart == -1)
+        /* if undefined position */
+        if (c->selected_item == -1)
             strcpy(lastfile, buf);
     }
     else
diff --git a/apps/gui/buttonbar.c b/apps/gui/buttonbar.c
new file mode 100644
index 0000000..be87b1b
--- /dev/null
+++ b/apps/gui/buttonbar.c
@@ -0,0 +1,126 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) Linus Nielsen Feltzing (2002), Kévin FERRARE (2005)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "buttonbar.h"
+
+#ifdef HAS_BUTTONBAR
+
+#include "lcd.h"
+#include "font.h"
+#include "string.h"
+#include "settings.h"
+
+void gui_buttonbar_init(struct gui_buttonbar * buttonbar)
+{
+    gui_buttonbar_unset(buttonbar);
+}
+
+void gui_buttonbar_set_display(struct gui_buttonbar * buttonbar,
+                               struct screen * display)
+{
+    buttonbar->display = display;
+}
+
+void gui_buttonbar_draw_button(struct gui_buttonbar * buttonbar, int num)
+{
+    int xpos, ypos, button_width, text_width;
+    int fw, fh;
+    struct screen * display = buttonbar->display;
+    
+    display->setfont(FONT_SYSFIXED);
+    display->getstringsize("M", &fw, &fh);
+
+    button_width = display->width/BUTTONBAR_MAX_BUTTONS;
+    xpos = num * button_width;
+    ypos = display->height - fh;
+
+    if(buttonbar->caption[num][0] != 0)
+    {
+        /* center the text */
+        text_width = fw * strlen(buttonbar->caption[num]);
+        display->putsxy(xpos + (button_width - text_width)/2,
+                        ypos, buttonbar->caption[num]);
+    }
+
+    display->set_drawmode(DRMODE_COMPLEMENT);
+    display->fillrect(xpos, ypos, button_width - 1, fh);
+    display->set_drawmode(DRMODE_SOLID);
+    display->setfont(FONT_UI);
+}
+
+void gui_buttonbar_set(struct gui_buttonbar * buttonbar,
+                       const char *caption1,
+                       const char *caption2,
+                       const char *caption3)
+{
+    gui_buttonbar_unset(buttonbar);
+    if(caption1)
+    {
+        strncpy(buttonbar->caption[0], caption1, 7);
+        buttonbar->caption[0][7] = 0;
+    }
+    if(caption2)
+    {
+        strncpy(buttonbar->caption[1], caption2, 7);
+        buttonbar->caption[1][7] = 0;
+    }
+    if(caption3)
+    {
+        strncpy(buttonbar->caption[2], caption3, 7);
+        buttonbar->caption[2][7] = 0;
+    }
+}
+
+void gui_buttonbar_unset(struct gui_buttonbar * buttonbar)
+{
+    int i;
+    for(i = 0;i < BUTTONBAR_MAX_BUTTONS;++i)
+        buttonbar->caption[i][0] = 0;
+}
+
+void gui_buttonbar_draw(struct gui_buttonbar * buttonbar)
+{
+    struct screen * display = buttonbar->display;
+    int i;
+    
+    display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+    display->fillrect(0, display->height - BUTTONBAR_HEIGHT,
+                      display->width, BUTTONBAR_HEIGHT);
+    display->set_drawmode(DRMODE_SOLID);
+
+    for(i = 0;i < BUTTONBAR_MAX_BUTTONS;++i)
+        gui_buttonbar_draw_button(buttonbar, i);
+    display->update_rect(0, display->height - BUTTONBAR_HEIGHT,
+                         display->width, BUTTONBAR_HEIGHT);
+}
+
+bool gui_buttonbar_isset(struct gui_buttonbar * buttonbar)
+{
+    /* If all buttons are unset, the button bar is considered disabled */
+    if(!global_settings.buttonbar)
+        return(false);
+    int i;
+    for(i = 0;i < BUTTONBAR_MAX_BUTTONS;++i)
+        if(buttonbar->caption[i] != 0)
+            return true;
+    return false;
+}
+
+#endif /* HAS_BUTTONBAR */
diff --git a/apps/gui/buttonbar.h b/apps/gui/buttonbar.h
new file mode 100644
index 0000000..ee7b8d0
--- /dev/null
+++ b/apps/gui/buttonbar.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Kévin FERRARE
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _GUI_BUTTONBAR_H_
+#define _GUI_BUTTONBAR_H_
+#include "config.h"
+#include "button.h"
+#if CONFIG_KEYPAD == RECORDER_PAD
+
+#define HAS_BUTTONBAR
+#define BUTTONBAR_HEIGHT 8
+#define BUTTONBAR_MAX_BUTTONS 3
+#define BUTTONBAR_CAPTION_LENGTH 8
+#include "screen_access.h"
+
+struct gui_buttonbar
+{
+    char caption[BUTTONBAR_MAX_BUTTONS][BUTTONBAR_CAPTION_LENGTH];
+    struct screen * display;
+};
+
+/*
+ * Initializes the buttonbar
+ *  - buttonbar : the buttonbar
+ */
+extern void gui_buttonbar_init(struct gui_buttonbar * buttonbar);
+
+/*
+ * Attach the buttonbar to a screen
+ *  - buttonbar : the buttonbar
+ *  - display : the display to attach the buttonbar
+ */
+extern void gui_buttonbar_set_display(struct gui_buttonbar * buttonbar,
+                                      struct screen * display);
+
+/*
+ * Set the caption of the items of the buttonbar
+ *  - buttonbar : the buttonbar
+ *  - caption1,2,3 : the first, second and thirds items of the bar
+ */
+extern void gui_buttonbar_set(struct gui_buttonbar * buttonbar,
+                              const char *caption1,
+                              const char *caption2,
+                              const char *caption3);
+
+/*
+ * Disable the buttonbar
+ *  - buttonbar : the buttonbar
+ */
+extern void gui_buttonbar_unset(struct gui_buttonbar * buttonbar);
+
+/*
+ * Draw the buttonbar on it's attached screen
+ *  - buttonbar : the buttonbar
+ */
+extern void gui_buttonbar_draw(struct gui_buttonbar * buttonbar);
+
+/*
+ * Returns true if the buttonbar has something to display, false otherwise
+ *  - buttonbar : the buttonbar
+ */
+extern bool gui_buttonbar_isset(struct gui_buttonbar * buttonbar);
+
+#endif  /* CONFIG_KEYPAD == RECORDER_PAD */
+#endif /* _GUI_BUTTONBAR_H_ */
diff --git a/apps/gui/icon.c b/apps/gui/icon.c
new file mode 100644
index 0000000..4d174d3
--- /dev/null
+++ b/apps/gui/icon.c
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) Robert E. Hak(2002), Kévin FERRARE (2005)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "icon.h"
+#include "screen_access.h"
+#include "icons.h"
+
+/* Count in letter positions, NOT pixels */
+void screen_put_iconxy(struct screen * display, int x, int y, ICON icon)
+{
+#ifdef HAVE_LCD_BITMAP
+    if(icon==0)/* Don't display invalid icons */
+        return;
+    int xpos, ypos;
+    xpos = x*CURSOR_WIDTH;
+    ypos = y*display->char_height + display->getymargin();
+    if ( display->char_height > CURSOR_HEIGHT )/* center the cursor */
+        ypos += (display->char_height - CURSOR_HEIGHT) / 2;
+    display->mono_bitmap(icon, xpos, ypos, CURSOR_WIDTH, CURSOR_HEIGHT);
+#else
+    display->putc(x, y, icon);
+#endif
+}
+
+void screen_put_cursorxy(struct screen * display, int x, int y)
+{
+#ifdef HAVE_LCD_BITMAP
+    screen_put_iconxy(display, x, y, bitmap_icons_6x8[Icon_Cursor]);
+#else
+    screen_put_iconxy(display, x, y, CURSOR_CHAR);
+#endif
+}
diff --git a/apps/gui/icon.h b/apps/gui/icon.h
new file mode 100644
index 0000000..46faf09
--- /dev/null
+++ b/apps/gui/icon.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Kévin FERRARE
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _GUI_ICON_H_
+#define _GUI_ICON_H_
+#include "lcd.h"
+#include "screen_access.h"
+/* Defines a type for the icons since it's not the same thing on
+ * char-based displays and bitmap displays */
+#ifdef HAVE_LCD_BITMAP
+    #define ICON const unsigned char *
+#else
+    #define ICON unsigned short
+#endif
+
+#define CURSOR_CHAR 0x92
+#define CURSOR_WIDTH 6
+#define CURSOR_HEIGHT 8
+/*
+ * Draws a cursor at a given position
+ * - screen : the screen where we put the cursor
+ * - x, y : the position, in character, not in pixel !!
+ */
+extern void screen_put_cursorxy(struct screen * screen, int x, int y);
+
+/*
+ * Put an icon on a screen at a given position
+ * (the position is given in characters)
+ * - screen : the screen where we put our icon
+ * - x, y : the position, in character, not in pixel !!
+ * - icon : the icon to put
+ */
+extern void screen_put_iconxy(struct screen * screen, int x, int y, ICON icon);
+
+#endif /*_GUI_ICON_H_*/
diff --git a/apps/gui/list.c b/apps/gui/list.c
new file mode 100644
index 0000000..bb3eb7c
--- /dev/null
+++ b/apps/gui/list.c
@@ -0,0 +1,499 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Kévin FERRARE
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "lcd.h"
+#include "font.h"
+#include "button.h"
+#include "sprintf.h"
+#include "settings.h"
+#include "kernel.h"
+
+#include "screen_access.h"
+#include "list.h"
+#include "scrollbar.h"
+#include "statusbar.h"
+
+#ifdef HAVE_LCD_CHARCELLS
+#define SCROLL_LIMIT 1
+#else
+#define SCROLL_LIMIT 2
+#endif
+
+
+
+void gui_list_init(struct gui_list * gui_list,
+         void (*callback_get_item_icon)(int selected_item, ICON * icon),
+         char * (*callback_get_item_name)(int selected_item, char *buffer))
+{
+    gui_list->callback_get_item_icon = callback_get_item_icon;
+    gui_list->callback_get_item_name = callback_get_item_name;
+    gui_list->display = NULL;
+    gui_list_set_nb_items(gui_list, 0);
+    gui_list->selected_item = 0;
+    gui_list->start_item = 0;
+}
+
+void gui_list_set_nb_items(struct gui_list * gui_list, int nb_items)
+{
+    gui_list->nb_items = nb_items;
+}
+
+void gui_list_set_display(struct gui_list * gui_list, struct screen * display)
+{
+    if(gui_list->display != 0) /* we switched from a previous display */
+        gui_list->display->stop_scroll();
+    gui_list->display = display;
+#ifdef HAVE_LCD_CHARCELLS
+    display->double_height(false);
+#endif
+    gui_list_put_selection_in_screen(gui_list, false);
+}
+
+void gui_list_put_selection_in_screen(struct gui_list * gui_list,
+                                      bool put_from_end)
+{
+    struct screen * display = gui_list->display;
+    if(put_from_end)
+    {
+        int list_end = gui_list->selected_item + SCROLL_LIMIT - 1;
+        if(list_end > gui_list->nb_items)
+            list_end = gui_list->nb_items;
+        gui_list->start_item = list_end - display->nb_lines;
+    }
+    else
+    {
+        int list_start = gui_list->selected_item - SCROLL_LIMIT + 1;
+        if(list_start + display->nb_lines > gui_list->nb_items)
+            list_start = gui_list->nb_items - display->nb_lines;
+        gui_list->start_item = list_start;
+    }
+    if(gui_list->start_item < 0)
+        gui_list->start_item = 0;
+}
+
+void gui_list_get_selected_item_name(struct gui_list * gui_list, char *buffer)
+{
+    gui_list->callback_get_item_name(gui_list->selected_item, buffer);
+}
+
+int gui_list_get_selected_item_position(struct gui_list * gui_list)
+{
+    return gui_list->selected_item;
+}
+
+void gui_list_draw(struct gui_list * gui_list)
+{
+    struct screen * display=gui_list->display;
+    int cursor_pos = 0;
+    int icon_pos = 1;
+    int text_pos;
+    bool draw_icons = (gui_list->callback_get_item_icon != NULL &&
+                       global_settings.show_icons) ;
+    bool draw_cursor;
+    int i;
+    
+    /* Adjust the position of icon, cursor, text */
+#ifdef HAVE_LCD_BITMAP
+    bool draw_scrollbar = (global_settings.scrollbar &&
+                           display->nb_lines < gui_list->nb_items);
+
+    int list_y_start = screen_get_text_y_start(gui_list->display);
+    int list_y_end = screen_get_text_y_end(gui_list->display);
+    
+    draw_cursor = !global_settings.invert_cursor;
+    text_pos = 0; /* here it's in pixels */
+    if(draw_scrollbar)
+    {
+        ++cursor_pos;
+        ++icon_pos;
+        text_pos += SCROLLBAR_WIDTH;
+    }
+    if(!draw_cursor)
+    {
+        --icon_pos;
+    }
+    else
+        text_pos += CURSOR_WIDTH;
+    
+    if(draw_icons)
+        text_pos += 8;
+#else
+    draw_cursor = true;
+    if(draw_icons)
+        text_pos = 2; /* here it's in chars */
+    else
+        text_pos = 1;
+#endif
+    /* The drawing part */
+#ifdef HAVE_LCD_BITMAP
+    /* clear the drawing area */
+    display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+    display->fillrect(0, list_y_start,
+                      display->width, list_y_end - list_y_start);
+    display->set_drawmode(DRMODE_SOLID);
+
+    /* FIXME: should not be handled here, but rather in the
+     * code that changes fonts */
+    screen_update_nblines(display);
+
+    display->stop_scroll();
+    display->setmargins(text_pos, list_y_start);
+#else
+    display->clear_display();
+#endif
+
+    for(i = 0;i < display->nb_lines;++i)
+    {
+        char entry_buffer[MAX_PATH];
+        char * entry_name;
+        int current_item = gui_list->start_item + i;
+        
+        /* When there are less items to display than the
+         * current available space on the screen, we stop*/
+        if(current_item >= gui_list->nb_items)
+            break;
+        entry_name = gui_list->callback_get_item_name(current_item,
+                                                      entry_buffer);
+        if(current_item == gui_list->selected_item)
+        {
+            /* The selected item must be displayed scrolling */
+#ifdef HAVE_LCD_BITMAP
+            if (global_settings.invert_cursor)/* Display inverted-line-style*/
+                display->puts_scroll_style(0, i, entry_name, STYLE_INVERT);
+            else
+                display->puts_scroll(0, i, entry_name);
+#else
+                display->puts_scroll(text_pos, i, entry_name);
+#endif
+
+            if(draw_cursor)
+                screen_put_cursorxy(display, cursor_pos, i);
+        }
+        else
+        {/* normal item */
+#ifdef HAVE_LCD_BITMAP
+            display->puts(0, i, entry_name);
+#else
+            display->puts(text_pos, i, entry_name);
+#endif
+        }
+        /* Icons display */
+        if(draw_icons)
+        {
+            ICON icon;
+            gui_list->callback_get_item_icon(current_item, &icon);
+            screen_put_iconxy(display, icon_pos, i, icon);
+        }
+    }
+#ifdef HAVE_LCD_BITMAP
+    /* Draw the scrollbar if needed*/
+    if(draw_scrollbar)
+    {
+        int scrollbar_y_end = display->char_height *
+                              display->nb_lines + list_y_start;
+        gui_scrollbar_draw(display, 0, list_y_start, SCROLLBAR_WIDTH-1,
+                           scrollbar_y_end - list_y_start, gui_list->nb_items,
+                           gui_list->start_item,
+                           gui_list->start_item + display->nb_lines, VERTICAL);
+    }
+    display->update_rect(0, list_y_start, display->width,
+                         list_y_end - list_y_start);
+#else
+#ifdef SIMULATOR
+    display->update();
+#endif
+#endif
+}
+
+void gui_list_select_item(struct gui_list * gui_list, int item_number)
+{
+    if( item_number > gui_list->nb_items-1 || item_number < 0 )
+        return;
+    gui_list->selected_item = item_number;
+    gui_list_put_selection_in_screen(gui_list, false);
+}
+
+void gui_list_select_next(struct gui_list * gui_list)
+{
+    int item_pos;
+    int end_item;
+    int nb_lines = gui_list->display->nb_lines;
+    
+    ++gui_list->selected_item;
+
+    if( gui_list->selected_item >= gui_list->nb_items )
+    {
+        /* we have already reached the bottom of the list */
+        gui_list->selected_item = 0;
+        gui_list->start_item = 0;
+    }
+    else
+    {
+        item_pos = gui_list->selected_item - gui_list->start_item;
+        end_item = gui_list->start_item + nb_lines;
+        /* we start scrolling vertically when reaching the line
+         * (nb_lines-SCROLL_LIMIT)
+         * and when we are not in the last part of the list*/
+        if( item_pos > nb_lines-SCROLL_LIMIT && end_item < gui_list->nb_items )
+            ++gui_list->start_item;
+    }
+}
+
+void gui_list_select_previous(struct gui_list * gui_list)
+{
+    int item_pos;
+    int nb_lines = gui_list->display->nb_lines;
+
+    --gui_list->selected_item;
+    if( gui_list->selected_item < 0 )
+    {
+        /* we have aleady reached the top of the list */
+        int start;
+        gui_list->selected_item = gui_list->nb_items-1;
+        start = gui_list->nb_items-nb_lines;
+        if( start < 0 )
+            gui_list->start_item = 0;
+        else
+            gui_list->start_item = start;
+    }
+    else
+    {
+        item_pos = gui_list->selected_item - gui_list->start_item;
+        if( item_pos < SCROLL_LIMIT-1 && gui_list->start_item > 0 )
+            --gui_list->start_item;
+    }
+}
+
+void gui_list_select_next_page(struct gui_list * gui_list, int nb_lines)
+{
+    if(gui_list->selected_item == gui_list->nb_items-1)
+        gui_list->selected_item = 0;
+    else
+    {
+        gui_list->selected_item += nb_lines;
+        if(gui_list->selected_item > gui_list->nb_items-1)
+            gui_list->selected_item = gui_list->nb_items-1;
+    }
+    gui_list_put_selection_in_screen(gui_list, true);
+}
+
+void gui_list_select_previous_page(struct gui_list * gui_list, int nb_lines)
+{
+    if(gui_list->selected_item == 0)
+        gui_list->selected_item = gui_list->nb_items - 1;
+    else
+    {
+        gui_list->selected_item -= nb_lines;
+        if(gui_list->selected_item < 0)
+            gui_list->selected_item = 0;
+    }
+    gui_list_put_selection_in_screen(gui_list, false);
+}
+
+void gui_list_add_item(struct gui_list * gui_list)
+{
+    ++gui_list->nb_items;
+    /* if only one item in the list, select it */
+    if(gui_list->nb_items == 1)
+        gui_list->selected_item = 0;
+}
+
+void gui_list_del_item(struct gui_list * gui_list)
+{
+    int nb_lines = gui_list->display->nb_lines;
+
+    if(gui_list->nb_items > 0)
+    {
+        int dist_selected_from_end = gui_list->nb_items
+            - gui_list->selected_item - 1;
+        int dist_start_from_end = gui_list->nb_items
+            - gui_list->start_item - 1;
+        if(dist_selected_from_end == 0)
+        {
+            /* Oops we are removing the selected item,
+               select the previous one */
+            --gui_list->selected_item;
+        }
+        --gui_list->nb_items;
+        
+        /* scroll the list if needed */
+        if( (dist_start_from_end < nb_lines) && (gui_list->start_item != 0) )
+            --gui_list->start_item;
+    }
+}
+
+/*
+ * Synchronized lists stuffs
+ */
+void gui_synclist_init(
+    struct gui_synclist * lists,
+    void (*callback_get_item_icon)(int selected_item, ICON * icon),
+    char * (*callback_get_item_name)(int selected_item, char *buffer)
+    )
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;i++)
+    {
+        gui_list_init(&(lists->gui_list[i]), callback_get_item_icon,
+                      callback_get_item_name);
+        gui_list_set_display(&(lists->gui_list[i]), &(screens[i]));
+    }
+}
+
+void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;i++)
+    {
+        gui_list_set_nb_items(&(lists->gui_list[i]), nb_items);
+    }
+}
+
+void gui_synclist_get_selected_item_name(struct gui_synclist * lists,
+                                         char *buffer)
+{
+    gui_list_get_selected_item_name(&(lists->gui_list[0]), buffer);
+}
+
+int  gui_synclist_get_selected_item_position(struct gui_synclist * lists)
+{
+    return gui_list_get_selected_item_position(&(lists->gui_list[0]));
+}
+
+void gui_synclist_draw(struct gui_synclist * lists)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;i++)
+        gui_list_draw(&(lists->gui_list[i]));
+}
+
+void gui_synclist_select_item(struct gui_synclist * lists, int item_number)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;i++)
+        gui_list_select_item(&(lists->gui_list[i]), item_number);
+}
+
+void gui_synclist_select_next(struct gui_synclist * lists)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;i++)
+        gui_list_select_next(&(lists->gui_list[i]));
+}
+
+void gui_synclist_select_previous(struct gui_synclist * lists)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;i++)
+        gui_list_select_previous(&(lists->gui_list[i]));
+}
+
+void gui_synclist_select_next_page(struct gui_synclist * lists,
+                                   enum screen_type screen)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;i++)
+        gui_list_select_next_page(&(lists->gui_list[i]),
+                                  screens[screen].nb_lines);
+}
+
+void gui_synclist_select_previous_page(struct gui_synclist * lists,
+                                       enum screen_type screen)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;i++)
+        gui_list_select_previous_page(&(lists->gui_list[i]),
+                                      screens[screen].nb_lines);
+}
+
+void gui_synclist_add_item(struct gui_synclist * lists)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;i++)
+        gui_list_add_item(&(lists->gui_list[i]));
+}
+
+void gui_synclist_del_item(struct gui_synclist * lists)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;i++)
+        gui_list_del_item(&(lists->gui_list[i]));
+}
+
+bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button)
+{
+    switch(button)
+    {
+        case LIST_PREV:
+        case LIST_PREV | BUTTON_REPEAT:
+#ifdef LIST_RC_PREV
+        case LIST_RC_PREV:
+        case LIST_RC_PREV | BUTTON_REPEAT:
+#endif
+            gui_synclist_select_previous(lists);
+            gui_synclist_draw(lists);
+            return true;
+
+        case LIST_NEXT:
+        case LIST_NEXT | BUTTON_REPEAT:
+#ifdef LIST_RC_NEXT
+        case LIST_RC_NEXT:
+        case LIST_RC_NEXT | BUTTON_REPEAT:
+#endif
+            gui_synclist_select_next(lists);
+            gui_synclist_draw(lists);
+            return true;
+/* for pgup / pgdown, we are obliged to have a different behaviour depending on the screen
+ * for which the user pressed the key since for example, remote and main screen doesn't
+ * have the same number of lines*/
+#ifdef LIST_PGUP
+        case LIST_PGUP:
+        case LIST_PGUP | BUTTON_REPEAT:
+            gui_synclist_select_previous_page(lists, SCREEN_MAIN);
+            gui_synclist_draw(lists);
+            return true;
+#endif
+
+#ifdef LIST_RC_PGUP
+        case LIST_RC_PGUP:
+        case LIST_RC_PGUP | BUTTON_REPEAT:
+            gui_synclist_select_previous_page(lists, SCREEN_REMOTE);
+            gui_synclist_draw(lists);
+            return true;
+#endif
+
+#ifdef LIST_PGDN
+        case LIST_PGDN:
+        case LIST_PGDN | BUTTON_REPEAT:
+            gui_synclist_select_next_page(lists, SCREEN_MAIN);
+            gui_synclist_draw(lists);
+            return true;
+#endif
+
+#ifdef LIST_RC_PGDN
+        case LIST_RC_PGDN:
+        case LIST_RC_PGDN | BUTTON_REPEAT:
+            gui_synclist_select_next_page(lists, SCREEN_REMOTE);
+            gui_synclist_draw(lists);
+            return true;
+#endif
+    }
+    return false;
+}
diff --git a/apps/gui/list.h b/apps/gui/list.h
new file mode 100644
index 0000000..fd553f3
--- /dev/null
+++ b/apps/gui/list.h
@@ -0,0 +1,232 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Kévin FERRARE
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _GUI_LIST_H_
+#define _GUI_LIST_H_
+
+#include "config.h"
+#include "icon.h"
+#include "screen_access.h"
+
+#define SCROLLBAR_WIDTH  6
+
+/* Key assignement */
+#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
+    (CONFIG_KEYPAD == IRIVER_H300_PAD)
+#define LIST_NEXT      BUTTON_DOWN
+#define LIST_PREV      BUTTON_UP
+#define LIST_PGUP      (BUTTON_ON | BUTTON_UP)
+#define LIST_PGDN      (BUTTON_ON | BUTTON_DOWN)
+#define LIST_RC_NEXT   BUTTON_RC_FF
+#define LIST_RC_PREV   BUTTON_RC_REW
+#define LIST_RC_PGUP   BUTTON_RC_SOURCE
+#define LIST_RC_PGDN   BUTTON_RC_BITRATE
+
+#elif CONFIG_KEYPAD == RECORDER_PAD
+#define LIST_NEXT      BUTTON_DOWN
+#define LIST_PREV      BUTTON_UP
+#define LIST_PGUP      (BUTTON_ON | BUTTON_UP)
+#define LIST_PGDN      (BUTTON_ON | BUTTON_DOWN)
+#define LIST_RC_NEXT   BUTTON_RC_RIGHT
+#define LIST_RC_PREV   BUTTON_RC_LEFT
+
+#elif CONFIG_KEYPAD == PLAYER_PAD
+#define LIST_NEXT      BUTTON_RIGHT
+#define LIST_PREV      BUTTON_LEFT
+#define LIST_RC_NEXT   BUTTON_RC_RIGHT
+#define LIST_RC_PREV   BUTTON_RC_LEFT
+
+#elif CONFIG_KEYPAD == ONDIO_PAD
+#define LIST_NEXT      BUTTON_DOWN
+#define LIST_PREV      BUTTON_UP
+
+#elif CONFIG_KEYPAD == GMINI100_PAD
+#define LIST_NEXT      BUTTON_DOWN
+#define LIST_PREV      BUTTON_UP
+#define LIST_PGUP      (BUTTON_ON | BUTTON_UP)
+#define LIST_PGDN      (BUTTON_ON | BUTTON_DOWN)
+#endif
+
+
+struct gui_list
+{
+    int nb_items;
+    int selected_item;
+    int start_item; /* the item that is displayed at the top of the screen */
+
+    void (*callback_get_item_icon)(int selected_item, ICON * icon);
+    char * (*callback_get_item_name)(int selected_item, char *buffer);
+
+    struct screen * display;
+    int line_scroll_limit;
+};
+
+/*
+ * Initializes a scrolling list
+ *  - gui_list : the list structure to initialize
+ *  - callback_get_item_icon : pointer to a function that associates an icon
+ *    to a given item number
+ *  - callback_get_item_name : pointer to a function that associates a label
+ *    to a given item number
+ */
+extern void gui_list_init(struct gui_list * gui_list,
+            void (*callback_get_item_icon)(int selected_item, ICON * icon),
+            char * (*callback_get_item_name)(int selected_item, char *buffer)
+            );
+
+/*
+ * Sets the numburs of items the list can currently display
+ * note that the list's context like the currently pointed item is resetted
+ *  - gui_list : the list structure to initialize
+ *  - nb_items : the numbers of items you want
+ */
+extern void gui_list_set_nb_items(struct gui_list * gui_list, int nb_items);
+
+/*
+ * Puts the selection in the screen
+ *  - gui_list : the list structure
+ *  - put_from_end : if true, selection will be put as close from
+ *                   the end of the list as possible, else, it's
+ *                   from the beginning
+ */
+extern void gui_list_put_selection_in_screen(struct gui_list * gui_list,
+                                             bool put_from_end);
+
+/*
+ * Attach the scrolling list to a screen
+ * (The previous screen attachement is lost)
+ *  - gui_list : the list structure
+ *  - display : the screen to attach
+ */
+extern void gui_list_set_display(struct gui_list * gui_list,
+                                 struct screen * display);
+
+/*
+ * Gives the name of the selected object
+ *  - gui_list : the list structure
+ *  - buffer : a buffer which is filled with the name
+ */
+extern void gui_list_get_selected_item_name(struct gui_list * gui_list,
+                                            char *buffer);
+
+/*
+ * Gives the position of the selected item
+ *  - gui_list : the list structure
+ * Returns the position
+ */
+extern int gui_list_get_selected_item_position(struct gui_list * gui_list);
+
+/*
+ * Selects an item in the list
+ *  - gui_list : the list structure
+ *  - item_number : the number of the item which will be selected
+ */
+extern void gui_list_select_item(struct gui_list * gui_list, int item_number);
+
+/*
+ * Draws the list on the attached screen
+ * - gui_list : the list structure
+ */
+extern void gui_list_draw(struct gui_list * gui_list);
+
+/*
+ * Selects the next item in the list
+ * (Item 0 gets selected if the end of the list is reached)
+ * - gui_list : the list structure
+ */
+extern void gui_list_select_next(struct gui_list * gui_list);
+
+/*
+ * Selects the previous item in the list
+ * (Last item in the list gets selected if the list beginning is reached)
+ * - gui_list : the list structure
+ */
+extern void gui_list_select_previous(struct gui_list * gui_list);
+
+/*
+ * Go to next page if any, else selects the last item in the list
+ * - gui_list : the list structure
+ * - nb_lines : the number of lines to try to move the cursor
+ */
+extern void gui_list_select_next_page(struct gui_list * gui_list,
+                                      int nb_lines);
+
+/*
+ * Go to previous page if any, else selects the first item in the list
+ * - gui_list : the list structure
+ * - nb_lines : the number of lines to try to move the cursor
+ */
+extern void gui_list_select_previous_page(struct gui_list * gui_list,
+                                          int nb_lines);
+
+/*
+ * Adds an item to the list (the callback will be asked for one more item)
+ * - gui_list : the list structure
+ */
+extern void gui_list_add_item(struct gui_list * gui_list);
+
+/*
+ * Removes an item to the list (the callback will be asked for one less item)
+ * - gui_list : the list structure
+ */
+extern void gui_list_del_item(struct gui_list * gui_list);
+
+
+/*
+ * This part handles as many lists as there are connected screens
+ * (the api is similar to the ones above)
+ * The lists on the screens are synchronized ;
+ * theirs items and selected items are the same, but of course,
+ * they can be displayed on screens with different sizes
+ * The final aim is to let the programmer handle many lists in one
+ * function call and make its code independant from the number of screens
+ */
+struct gui_synclist
+{
+    struct gui_list gui_list[NB_SCREENS];
+};
+
+extern void gui_synclist_init(struct gui_synclist * lists,
+             void (*callback_get_item_icon)(int selected_item, ICON * icon),
+             char * (*callback_get_item_name)(int selected_item, char *buffer)
+             );
+extern void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items);
+extern void gui_synclist_get_selected_item_name(struct gui_synclist * lists,
+                                                char *buffer);
+extern int  gui_synclist_get_selected_item_position(struct gui_synclist * lists);
+extern void gui_synclist_draw(struct gui_synclist * lists);
+extern void gui_synclist_select_item(struct gui_synclist * lists,
+                                     int item_number);
+extern void gui_synclist_select_next(struct gui_synclist * lists);
+extern void gui_synclist_select_previous(struct gui_synclist * lists);
+extern void gui_synclist_select_next_page(struct gui_synclist * lists,
+                                          enum screen_type screen);
+extern void gui_synclist_select_previous_page(struct gui_synclist * lists,
+                                              enum screen_type screen);
+extern void gui_synclist_add_item(struct gui_synclist * lists);
+extern void gui_synclist_del_item(struct gui_synclist * lists);
+/*
+ * Do the action implied by the given button,
+ * returns true if something has been done, false otherwise
+ *  - lists : the synchronized lists
+ *  - button : the keycode of a pressed button
+ */
+extern bool gui_synclist_do_button(struct gui_synclist * lists, unsigned button);
+
+#endif /* _GUI_LIST_H_ */
diff --git a/apps/gui/scrollbar.c b/apps/gui/scrollbar.c
new file mode 100644
index 0000000..9d5717f
--- /dev/null
+++ b/apps/gui/scrollbar.c
@@ -0,0 +1,106 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) Markus Braun (2002), Kévin FERRARE (2005)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "lcd.h"
+#ifdef HAVE_LCD_BITMAP
+#include "limits.h"
+#include "scrollbar.h"
+#include "screen_access.h"
+
+void gui_scrollbar_draw(struct screen * screen, int x, int y,
+                        int width, int height, int items,
+                        int min_shown, int max_shown,
+                        enum orientation orientation)
+{
+    int min;
+    int max;
+    int inner_len;
+    int start;
+    int size;
+
+    /* draw box */
+    screen->drawrect(x, y, width, height);
+
+    screen->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+
+    /* clear edge pixels */
+    screen->drawpixel(x, y);
+    screen->drawpixel((x + width - 1), y);
+    screen->drawpixel(x, (y + height - 1));
+    screen->drawpixel((x + width - 1), (y + height - 1));
+
+    /* clear pixels in progress bar */
+    screen->fillrect(x + 1, y + 1, width - 2, height - 2);
+
+    /* min should be min */
+    if(min_shown < max_shown) {
+        min = min_shown;
+        max = max_shown;
+    }
+    else {
+        min = max_shown;
+        max = min_shown;
+    }
+
+    /* limit min and max */
+    if(min < 0)
+        min = 0;
+    if(min > items)
+        min = items;
+
+    if(max < 0)
+        max = 0;
+    if(max > items)
+        max = items;
+
+    if (orientation == VERTICAL)
+        inner_len = height - 2;
+    else
+        inner_len = width - 2;
+
+    /* avoid overflows */
+    while (items > (INT_MAX / inner_len)) {
+        items >>= 1;
+        min >>= 1;
+        max >>= 1;
+    }
+
+    /* calc start and end of the knob */
+    if (items > 0 && items > (max - min)) {
+        size = inner_len * (max - min) / items;
+        if (size == 0) { /* width of knob is null */
+            size = 1;
+            start = (inner_len - 1) * min / items;
+        } else {
+            start = (inner_len - size) * min / (items - (max - min));
+        }
+    } else {  /* if null draw full bar */
+        size = inner_len;
+        start = 0;
+    }
+
+    screen->set_drawmode(DRMODE_SOLID);
+
+    if(orientation == VERTICAL)
+        screen->fillrect(x + 1, y + start + 1, width - 2, size);
+    else
+        screen->fillrect(x + start + 1, y + 1, size, height - 2);
+}
+#endif /* HAVE_LCD_BITMAP */
diff --git a/apps/gui/scrollbar.h b/apps/gui/scrollbar.h
new file mode 100644
index 0000000..51c0835
--- /dev/null
+++ b/apps/gui/scrollbar.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2005 Kévin FERRARE
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _GUI_SCROLLBAR_H_
+#define _GUI_SCROLLBAR_H_
+#include <lcd.h>
+#ifdef HAVE_LCD_BITMAP
+
+struct screen;
+
+enum orientation {
+    VERTICAL,
+    HORIZONTAL
+};
+
+/*
+ * Draws a scrollbar on the given screen
+ *  - screen : the screen to put the scrollbar on
+ *  - x : x start position of the scrollbar
+ *  - y : y start position of the scrollbar
+ *  - width : you won't guess =(^o^)=
+ *  - height : I won't tell you either !
+ *  - items : total number of items on the screen
+ *  - min_shown : index of the starting item on the screen
+ *  - max_shown : index of the last item on the screen
+ *  - orientation : either VERTICAL or HORIZONTAL
+ */
+extern void gui_scrollbar_draw(struct screen * screen, int x, int y,
+                               int width, int height, int items,
+                               int min_shown, int max_shown,
+                               enum orientation orientation);
+#endif /* HAVE_LCD_BITMAP */
+#endif /* _GUI_SCROLLBAR_H_ */
diff --git a/apps/gui/splash.c b/apps/gui/splash.c
new file mode 100644
index 0000000..a3cbb19
--- /dev/null
+++ b/apps/gui/splash.c
@@ -0,0 +1,216 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) Daniel Stenberg (2002), Kévin FERRARE (2005)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "stdarg.h"
+#include "string.h"
+#include "stdio.h"
+#include "kernel.h"
+#include "screen_access.h"
+
+
+#ifdef HAVE_LCD_BITMAP
+
+#define SPACE 3 /* pixels between words */
+#define MAXLETTERS 128 /* 16*8 */
+#define MAXLINES 10
+
+#else
+
+#define SPACE 1 /* one letter space */
+#define MAXLETTERS 22 /* 11 * 2 */
+#define MAXLINES 2
+
+#endif
+
+
+void internal_splash(struct screen * screen,
+                    bool center,  const char *fmt, va_list ap)
+{
+    char *next;
+    char *store=NULL;
+    int x=0;
+    int y=0;
+    int w, h;
+    unsigned char splash_buf[MAXLETTERS];
+    unsigned char widths[MAXLINES];
+    int line=0;
+    bool first=true;
+#ifdef HAVE_LCD_BITMAP
+    int maxw=0;
+#endif
+
+#ifdef HAVE_LCD_CHARCELLS
+    screen->double_height (false);
+#endif
+    vsnprintf( splash_buf, sizeof(splash_buf), fmt, ap );
+
+    if(center) {
+        /* first a pass to measure sizes */
+        next = strtok_r(splash_buf, " ", &store);
+        while (next) {
+#ifdef HAVE_LCD_BITMAP
+            screen->getstringsize(next, &w, &h);
+#else
+            w = strlen(next);
+            h = 1; /* store height in characters */
+#endif
+            if(!first) {
+                if(x+w> screen->width) {
+                    /* Too wide, wrap */
+                    y+=h;
+                    line++;
+                    if((y > (screen->height-h)) || (line > screen->nb_lines))
+                        /* STOP */
+                        break;
+                    x=0;
+                    first=true;
+                }
+            }
+            else
+                first = false;
+
+            /* think of it as if the text was written here at position x,y
+               being w pixels/chars wide and h high */
+
+            x += w+SPACE;
+            widths[line]=x-SPACE; /* don't count the trailing space */
+#ifdef HAVE_LCD_BITMAP
+            /* store the widest line */
+            if(widths[line]>maxw)
+                maxw = widths[line];
+#endif
+            next = strtok_r(NULL, " ", &store);
+        }
+
+#ifdef HAVE_LCD_BITMAP
+        /* Start displaying the message at position y. The reason for the
+           added h here is that it isn't added until the end of lines in the
+           loop above and we always break the loop in the middle of a line. */
+        y = (screen->height - (y+h) )/2;
+#else
+        y = 0; /* vertical center on 2 lines would be silly */
+#endif
+        first=true;
+
+        /* Now recreate the string again since the strtok_r() above has ruined
+           the one we already have! Here's room for improvements! */
+        vsnprintf( splash_buf, sizeof(splash_buf), fmt, ap );
+    }
+    va_end( ap );
+
+    if(center)
+    {
+        x = (screen->width-widths[0])/2;
+        if(x < 0)
+            x = 0;
+    }
+
+#ifdef HAVE_LCD_BITMAP
+    /* If we center the display, then just clear the box we need and put
+       a nice little frame and put the text in there! */
+    if(center && (y > 2)) {
+        int xx = (screen->width-maxw)/2 - 2;
+        /* The new graphics routines handle clipping, so no need to check */
+#if LCD_DEPTH > 1
+#ifdef HAVE_LCD_COLOR
+        screen->set_background((struct rgb){LCD_MAX_RED-1, LCD_MAX_GREEN-1,
+                                            LCD_MAX_BLUE-1});
+#else
+        if(screen->depth>1)
+            screen->set_background(LCD_MAX_LEVEL-1);
+#endif
+#endif
+        screen->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+        screen->fillrect(xx, y-2, maxw+4, screen->height-y*2+4);
+        screen->set_drawmode(DRMODE_SOLID);
+        screen->drawrect(xx, y-2, maxw+4, screen->height-y*2+4);
+    }
+    else
+#endif
+        screen->clear_display();
+    line=0;
+    next = strtok_r(splash_buf, " ", &store);
+    while (next) {
+#ifdef HAVE_LCD_BITMAP
+        screen->getstringsize(next, &w, &h);
+#else
+        w = strlen(next);
+        h = 1;
+#endif
+        if(!first) {
+            if(x+w> screen->width) {
+                /* too wide */
+                y+=h;
+                line++; /* goto next line */
+                first=true;
+                if(y > (screen->height-h))
+                    /* STOP */
+                    break;
+                if(center) {
+                    x = (screen->width-widths[line])/2;
+                    if(x < 0)
+                       x = 0;
+                }
+                else
+                    x=0;
+            }
+        }
+        else
+            first=false;
+#ifdef HAVE_LCD_BITMAP
+        screen->putsxy(x, y, next);
+#else
+        screen->puts(x, y, next);
+#endif
+        x += w+SPACE; /*  pixels space! */
+        next = strtok_r(NULL, " ", &store);
+    }
+
+#if defined(HAVE_LCD_BITMAP) && (LCD_DEPTH > 1)
+    if(screen->depth > 1)
+        screen->set_background(LCD_WHITE);
+#endif
+#if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR)
+    screen->update();
+#endif
+}
+
+void gui_splash(struct screen * screen, int ticks,
+                    bool center,  const char *fmt, ...)
+{
+    va_list ap;
+    va_start( ap, fmt );
+    internal_splash(screen, center, fmt, ap);
+    va_end( ap );
+
+    if(ticks)
+        sleep(ticks);
+}
+
+void gui_syncsplash(int ticks, bool center,  const char *fmt, ...)
+{
+    va_list ap;
+    int i;
+    va_start( ap, fmt );
+    for(i=0;i<NB_SCREENS;++i)
+        internal_splash(&(screens[i]), center, fmt, ap);
+    va_end( ap );
+
+    if(ticks)
+        sleep(ticks);
+}
diff --git a/apps/gui/splash.h b/apps/gui/splash.h
new file mode 100644
index 0000000..b0d55db
--- /dev/null
+++ b/apps/gui/splash.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Kévin FERRARE
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/*
+ * Puts a splash message on the given screen for a given period
+ *  - screen : the screen to put the splash on
+ *  - ticks : how long the splash is displayed (in rb ticks)
+ *  - center : FALSE means left-justified, TRUE means
+ *             horizontal and vertical center
+ *  - fmt : what to say *printf style
+ */
+extern void gui_splash(struct screen * screen, int ticks,
+                       bool center,  const char *fmt, ...);
+
+/*
+ * Puts a splash message on all the screens for a given period
+ *  - ticks : how long the splash is displayed (in rb ticks)
+ *  - center : FALSE means left-justified, TRUE means
+ *             horizontal and vertical center
+ *  - fmt : what to say *printf style
+ */
+extern void gui_syncsplash(int ticks, bool center,
+                           const char *fmt, ...);
diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c
new file mode 100644
index 0000000..5ddc194
--- /dev/null
+++ b/apps/gui/statusbar.c
@@ -0,0 +1,508 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) Robert E. Hak (2002), Linus Nielsen Feltzing (2002), Kévin FERRARE (2005)
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "screen_access.h"
+#include "lcd.h"
+#include "font.h"
+#include "kernel.h"
+#include "string.h" /* for memcmp oO*/
+#include "sprintf.h"
+#include "sound.h"
+#include "power.h"
+#include "settings.h"
+#include "icons.h"
+#include "powermgmt.h"
+#include "button.h"
+
+#include "status.h" /* needed for battery_state global var */
+#include "wps.h" /* for keys_locked */
+#include "statusbar.h"
+
+
+/* FIXME: should be removed from icon.h to avoid redefinition,
+   but still needed for compatibility with old system */
+#define STATUSBAR_X_POS                         0
+#define STATUSBAR_Y_POS                         0 /* MUST be a multiple of 8 */
+#define STATUSBAR_HEIGHT                        8
+#define STATUSBAR_BATTERY_X_POS                 0
+#define STATUSBAR_BATTERY_WIDTH                 18
+#define STATUSBAR_PLUG_X_POS                    STATUSBAR_X_POS + \
+                                                STATUSBAR_BATTERY_WIDTH +2
+#define STATUSBAR_PLUG_WIDTH                    7
+#define STATUSBAR_VOLUME_X_POS                  STATUSBAR_X_POS + \
+                                                STATUSBAR_BATTERY_WIDTH + \
+                                                STATUSBAR_PLUG_WIDTH +2+2
+#define STATUSBAR_VOLUME_WIDTH                  16
+#define STATUSBAR_PLAY_STATE_X_POS              STATUSBAR_X_POS + \
+                                                STATUSBAR_BATTERY_WIDTH + \
+                                                STATUSBAR_PLUG_WIDTH + \
+                                                STATUSBAR_VOLUME_WIDTH+2+2+2
+#define STATUSBAR_PLAY_STATE_WIDTH              7
+#define STATUSBAR_PLAY_MODE_X_POS               STATUSBAR_X_POS + \
+                                                STATUSBAR_BATTERY_WIDTH + \
+                                                STATUSBAR_PLUG_WIDTH + \
+                                                STATUSBAR_VOLUME_WIDTH + \
+                                                STATUSBAR_PLAY_STATE_WIDTH + \
+                                                2+2+2+2
+#define STATUSBAR_PLAY_MODE_WIDTH               7
+#define STATUSBAR_SHUFFLE_X_POS                 STATUSBAR_X_POS + \
+                                                STATUSBAR_BATTERY_WIDTH + \
+                                                STATUSBAR_PLUG_WIDTH + \
+                                                STATUSBAR_VOLUME_WIDTH + \
+                                                STATUSBAR_PLAY_STATE_WIDTH + \
+                                                STATUSBAR_PLAY_MODE_WIDTH + \
+                                                2+2+2+2+2
+#define STATUSBAR_SHUFFLE_WIDTH                 7
+#define STATUSBAR_LOCK_X_POS                    STATUSBAR_X_POS + \
+                                                STATUSBAR_BATTERY_WIDTH + \
+                                                STATUSBAR_PLUG_WIDTH + \
+                                                STATUSBAR_VOLUME_WIDTH + \
+                                                STATUSBAR_PLAY_STATE_WIDTH + \
+                                                STATUSBAR_PLAY_MODE_WIDTH + \
+                                                STATUSBAR_SHUFFLE_WIDTH + \
+                                                2+2+2+2+2+2
+#define STATUSBAR_LOCK_WIDTH                    5
+#define STATUSBAR_DISK_WIDTH                    12
+#define STATUSBAR_DISK_X_POS(statusbar_width)   statusbar_width - \
+                                                STATUSBAR_DISK_WIDTH
+#define STATUSBAR_TIME_X_END(statusbar_width)   statusbar_width-1
+
+void gui_statusbar_init(struct gui_statusbar * bar)
+{
+    bar->last_volume = -1; /* -1 means "first update ever" */
+    bar->battery_icon_switch_tick = 0;
+#ifdef HAVE_USB_POWER
+    bar->battery_charge_step = 0;
+#endif
+}
+
+void gui_statusbar_set_screen(struct gui_statusbar * bar,
+                              struct screen * display)
+{
+    bar->display = display;
+    gui_statusbar_draw(bar, false);
+}
+
+void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw)
+{
+#ifdef HAVE_LCD_BITMAP
+    if(!global_settings.statusbar)
+       return;
+#endif
+
+    struct screen * display = bar->display;
+
+#ifdef HAVE_LCD_BITMAP
+    struct tm* tm; /* For Time */
+#else
+    (void)force_redraw; /* players always "redraw" */
+#endif
+
+    bar->info.volume = sound_val2phys(SOUND_VOLUME, global_settings.volume);
+    bar->info.inserted = charger_inserted();
+    bar->info.battlevel = battery_level();
+    bar->info.battery_safe = battery_level_safe();
+
+#ifdef HAVE_LCD_BITMAP
+    tm = get_time();
+    bar->info.hour = tm->tm_hour;
+    bar->info.minute = tm->tm_min;
+    bar->info.shuffle = global_settings.playlist_shuffle;
+#if CONFIG_KEYPAD == IRIVER_H100_PAD
+    bar->info.keylock = button_hold();
+#else
+    bar->info.keylock = keys_locked;
+#endif
+    bar->info.repeat = global_settings.repeat_mode;
+    bar->info.playmode = current_playmode();
+#if CONFIG_LED == LED_VIRTUAL
+    bar->info.led = led_read(HZ/2); /* delay should match polling interval */
+#endif
+#ifdef HAVE_USB_POWER
+    bar->info.usb_power = usb_powered();
+#endif
+
+    /* only redraw if forced to, or info has changed */
+    if (force_redraw ||
+        bar->info.inserted ||
+        !bar->info.battery_safe ||
+        bar->info.redraw_volume ||
+        memcmp(&(bar->info), &(bar->lastinfo), sizeof(struct status_info)))
+    {
+        display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+        display->fillrect(0,0,display->width,8);
+        display->set_drawmode(DRMODE_SOLID);
+
+#else
+
+    /* players always "redraw" */
+    {
+#endif
+
+#ifdef HAVE_CHARGING
+        if (bar->info.inserted) {
+            battery_state = true;
+#if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200
+            /* zero battery run time if charging */
+            if (charge_state > 0) {
+                global_settings.runtime = 0;
+                lasttime = current_tick;
+            }
+
+            /* animate battery if charging */
+            if ((charge_state == 1) ||
+                (charge_state == 2)) {
+#else
+            global_settings.runtime = 0;
+            lasttime = current_tick;
+            {
+#endif
+                /* animate in three steps (34% per step for a better look) */
+                bar->info.battlevel = bar->battery_charge_step * 34;
+                if (bar->info.battlevel > 100)
+                    bar->info.battlevel = 100;
+                if(TIME_AFTER(current_tick, bar->battery_icon_switch_tick)) {
+                    bar->battery_charge_step=(bar->battery_charge_step+1)%4;
+                    bar->battery_icon_switch_tick = current_tick + HZ;
+                }
+            }
+        }
+        else
+#endif /* HAVE_CHARGING */
+        {
+            if (bar->info.battery_safe)
+                battery_state = true;
+            else {
+                /* blink battery if level is low */
+                if(TIME_AFTER(current_tick, bar->battery_icon_switch_tick) &&
+                   (bar->info.battlevel > -1)) {
+                    bar->battery_icon_switch_tick = current_tick+HZ;
+                    battery_state = !battery_state;
+                }
+            }
+        }
+#ifdef HAVE_LCD_BITMAP
+        if (battery_state)
+            gui_statusbar_icon_battery(display, bar->info.battlevel);
+        /* draw power plug if charging */
+        if (bar->info.inserted)
+            display->mono_bitmap(bitmap_icons_7x8[Icon_Plug],
+                                    STATUSBAR_PLUG_X_POS,
+                                    STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH,
+                                    STATUSBAR_HEIGHT);
+#ifdef HAVE_USB_POWER
+        else if (bar->info.usb_power)
+            display->mono_bitmap(bitmap_icons_7x8[Icon_USBPlug],
+                                 STATUSBAR_PLUG_X_POS,
+                                 STATUSBAR_Y_POS, STATUSBAR_PLUG_WIDTH,
+                                 STATUSBAR_HEIGHT);
+#endif
+
+        bar->info.redraw_volume = gui_statusbar_icon_volume(bar,
+                                                bar->info.volume);
+        gui_statusbar_icon_play_state(display, current_playmode() +
+                                                Icon_Play);
+        switch (bar->info.repeat) {
+#ifdef AB_REPEAT_ENABLE
+            case REPEAT_AB:
+                gui_statusbar_icon_play_mode(display, Icon_RepeatAB);
+                break;
+#endif
+
+            case REPEAT_ONE:
+                gui_statusbar_icon_play_mode(display, Icon_RepeatOne);
+                break;
+
+            case REPEAT_ALL:
+            case REPEAT_SHUFFLE:
+                gui_statusbar_icon_play_mode(display, Icon_Repeat);
+                break;
+        }
+        if (bar->info.shuffle)
+            gui_statusbar_icon_shuffle(display);
+        if (bar->info.keylock)
+            gui_statusbar_icon_lock(display);
+#ifdef HAVE_RTC
+        gui_statusbar_time(display, bar->info.hour, bar->info.minute);
+#endif
+#if CONFIG_LED == LED_VIRTUAL
+        if (bar->info.led)
+            statusbar_led();
+#endif
+        display->update_rect(0, 0, display->width, STATUSBAR_HEIGHT);
+        bar->lastinfo = bar->info;
+#endif
+    }
+
+
+#ifndef HAVE_LCD_BITMAP
+    if (bar->info.battlevel > -1)
+        display->icon(ICON_BATTERY, battery_state);
+    display->icon(ICON_BATTERY_1, bar->info.battlevel > 25);
+    display->icon(ICON_BATTERY_2, bar->info.battlevel > 50);
+    display->icon(ICON_BATTERY_3, bar->info.battlevel > 75);
+
+    display->icon(ICON_VOLUME, true);
+    display->icon(ICON_VOLUME_1, bar->info.volume > 10);
+    display->icon(ICON_VOLUME_2, bar->info.volume > 30);
+    display->icon(ICON_VOLUME_3, bar->info.volume > 50);
+    display->icon(ICON_VOLUME_4, bar->info.volume > 70);
+    display->icon(ICON_VOLUME_5, bar->info.volume > 90);
+
+    display->icon(ICON_PLAY, current_playmode() == STATUS_PLAY);
+    display->icon(ICON_PAUSE, current_playmode() == STATUS_PAUSE);
+
+    display->icon(ICON_REPEAT, global_settings.repeat_mode != REPEAT_OFF);
+    display->icon(ICON_1, global_settings.repeat_mode == REPEAT_ONE);
+
+    display->icon(ICON_RECORD, record);
+    display->icon(ICON_AUDIO, audio);
+    display->icon(ICON_PARAM, param);
+    display->icon(ICON_USB, usb);
+#endif
+}
+
+#ifdef HAVE_LCD_BITMAP
+/* from icon.c */
+/*
+ * Print battery icon to status bar
+ */
+void gui_statusbar_icon_battery(struct screen * display, int percent)
+{
+    int fill;
+    char buffer[5];
+    unsigned int width, height;
+
+    /* fill battery */
+    fill = percent;
+    if (fill < 0)
+        fill = 0;
+    if (fill > 100)
+        fill = 100;
+
+#if defined(HAVE_CHARGE_CTRL) && !defined(SIMULATOR) /* Rec v1 target only */
+    /* show graphical animation when charging instead of numbers */
+    if ((global_settings.battery_display) &&
+        (charge_state != 1) &&
+        (percent > -1)) {
+#else /* all others */
+    if (global_settings.battery_display && (percent > -1)) {
+#endif
+        /* Numeric display */
+        display->setfont(FONT_SYSFIXED);
+        snprintf(buffer, sizeof(buffer), "%3d", fill);
+        display->getstringsize(buffer, &width, &height);
+        if (height <= STATUSBAR_HEIGHT)
+            display->putsxy(STATUSBAR_BATTERY_X_POS
+                             + STATUSBAR_BATTERY_WIDTH / 2
+                             - width/2, STATUSBAR_Y_POS, buffer);
+        display->setfont(FONT_UI);
+
+    }
+    else {
+        /* draw battery */
+        display->drawrect(STATUSBAR_BATTERY_X_POS, STATUSBAR_Y_POS, 17, 7);
+        display->vline(STATUSBAR_BATTERY_X_POS + 17, STATUSBAR_Y_POS + 2,
+                       STATUSBAR_Y_POS + 4);
+
+        fill = fill * 15 / 100;
+        display->fillrect(STATUSBAR_BATTERY_X_POS + 1, STATUSBAR_Y_POS + 1,
+                          fill, 5);
+    }
+
+    if (percent == -1) {
+        display->setfont(FONT_SYSFIXED);
+        display->putsxy(STATUSBAR_BATTERY_X_POS + STATUSBAR_BATTERY_WIDTH / 2
+                         - 4, STATUSBAR_Y_POS, "?");
+        display->setfont(FONT_UI);
+    }
+}
+
+/*
+ * Print volume gauge to status bar
+ */
+bool gui_statusbar_icon_volume(struct gui_statusbar * bar, int percent)
+{
+    int i;
+    int volume;
+    int vol;
+    char buffer[4];
+    unsigned int width, height;
+    bool needs_redraw = false;
+    int type = global_settings.volume_type;
+    struct screen * display=bar->display;
+
+    volume = percent;
+    if (volume < 0)
+        volume = 0;
+    if (volume > 100)
+        volume = 100;
+
+    if (volume == 0) {
+        display->mono_bitmap(bitmap_icons_7x8[Icon_Mute],
+                    STATUSBAR_VOLUME_X_POS + STATUSBAR_VOLUME_WIDTH / 2 - 4,
+                    STATUSBAR_Y_POS, 7, STATUSBAR_HEIGHT);
+    }
+    else {
+        /* We want to redraw the icon later on */
+        if (bar->last_volume != volume && bar->last_volume >= 0) {
+            bar->volume_icon_switch_tick = current_tick + HZ;
+        }
+
+        /* If the timeout hasn't yet been reached, we show it numerically
+           and tell the caller that we want to be called again */
+        if (TIME_BEFORE(current_tick,bar->volume_icon_switch_tick)) {
+            type = 1;
+            needs_redraw = true;
+        }
+
+        /* display volume level numerical? */
+        if (type)
+        {
+            display->setfont(FONT_SYSFIXED);
+            snprintf(buffer, sizeof(buffer), "%2d", percent);
+            display->getstringsize(buffer, &width, &height);
+            if (height <= STATUSBAR_HEIGHT)
+            {
+                display->putsxy(STATUSBAR_VOLUME_X_POS
+                                 + STATUSBAR_VOLUME_WIDTH / 2
+                                 - width/2, STATUSBAR_Y_POS, buffer);
+            }
+            display->setfont(FONT_UI);
+        } else {
+            /* display volume bar */
+            vol = volume * 14 / 100;
+            for(i=0; i < vol; i++) {
+                display->vline(STATUSBAR_VOLUME_X_POS + i,
+                               STATUSBAR_Y_POS + 6 - i / 2,
+                               STATUSBAR_Y_POS + 6);
+            }
+        }
+    }
+    bar->last_volume = volume;
+
+    return needs_redraw;
+}
+
+/*
+ * Print play state to status bar
+ */
+void gui_statusbar_icon_play_state(struct screen * display, int state)
+{
+    display->mono_bitmap(bitmap_icons_7x8[state], STATUSBAR_PLAY_STATE_X_POS,
+                    STATUSBAR_Y_POS, STATUSBAR_PLAY_STATE_WIDTH,
+                    STATUSBAR_HEIGHT);
+}
+
+/*
+ * Print play mode to status bar
+ */
+void gui_statusbar_icon_play_mode(struct screen * display, int mode)
+{
+    display->mono_bitmap(bitmap_icons_7x8[mode], STATUSBAR_PLAY_MODE_X_POS,
+                    STATUSBAR_Y_POS, STATUSBAR_PLAY_MODE_WIDTH,
+                    STATUSBAR_HEIGHT);
+}
+
+/*
+ * Print shuffle mode to status bar
+ */
+void gui_statusbar_icon_shuffle(struct screen * display)
+{
+    display->mono_bitmap(bitmap_icons_7x8[Icon_Shuffle],
+                    STATUSBAR_SHUFFLE_X_POS, STATUSBAR_Y_POS,
+                    STATUSBAR_SHUFFLE_WIDTH, STATUSBAR_HEIGHT);
+}
+
+/*
+ * Print lock when keys are locked
+ */
+void gui_statusbar_icon_lock(struct screen * display)
+{
+    display->mono_bitmap(bitmap_icons_5x8[Icon_Lock], STATUSBAR_LOCK_X_POS,
+                    STATUSBAR_Y_POS, 5, 8);
+}
+
+#if CONFIG_LED == LED_VIRTUAL
+/*
+ * no real LED: disk activity in status bar
+ */
+void gui_statusbar_led(struct screen * display)
+{
+    display->mono_bitmap(bitmap_icon_disk, STATUSBAR_DISK_X_POS,
+                    STATUSBAR_Y_POS, STATUSBAR_DISK_WIDTH(screen->width),
+                    STATUSBAR_HEIGHT);
+}
+#endif
+
+
+#ifdef HAVE_RTC
+/*
+ * Print time to status bar
+ */
+void gui_statusbar_time(struct screen * display, int hour, int minute)
+{
+    unsigned char buffer[6];
+    unsigned int width, height;
+    if ( hour >= 0 &&
+         hour <= 23 &&
+         minute >= 0 &&
+         minute <= 59 ) {
+        if ( global_settings.timeformat ) { /* 12 hour clock */
+            hour %= 12;
+            if ( hour == 0 ) {
+                hour += 12;
+            }
+        }
+        snprintf(buffer, sizeof(buffer), "%02d:%02d", hour, minute);
+    }
+    else {
+        strncpy(buffer, "--:--", sizeof buffer);
+    }
+    display->setfont(FONT_SYSFIXED);
+    display->getstringsize(buffer, &width, &height);
+    if (height <= STATUSBAR_HEIGHT) {
+        display->putsxy(STATUSBAR_TIME_X_END(display->width) - width,
+                        STATUSBAR_Y_POS, buffer);
+    }
+    display->setfont(FONT_UI);
+
+}
+#endif
+
+#endif /* HAVE_LCD_BITMAP */
+
+void gui_syncstatusbar_init(struct gui_syncstatusbar * bars)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;++i) {
+        gui_statusbar_init( &(bars->statusbars[i]) );
+        gui_statusbar_set_screen( &(bars->statusbars[i]), &(screens[i]) );
+    }
+}
+
+void gui_syncstatusbar_draw(struct gui_syncstatusbar * bars,
+                            bool force_redraw)
+{
+    int i;
+    for(i = 0;i < NB_SCREENS;++i) {
+        gui_statusbar_draw( &(bars->statusbars[i]), force_redraw );
+    }
+}
diff --git a/apps/gui/statusbar.h b/apps/gui/statusbar.h
new file mode 100644
index 0000000..434d679
--- /dev/null
+++ b/apps/gui/statusbar.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Kévin FERRARE
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _GUI_STATUSBAR_H_
+#define _GUI_STATUSBAR_H_
+
+#include "config.h"
+#include "status.h"
+
+struct status_info {
+    int battlevel;
+    int volume;
+    int hour;
+    int minute;
+    int playmode;
+    int repeat;
+    bool inserted;
+    bool shuffle;
+    bool keylock;
+    bool battery_safe;
+    bool redraw_volume; /* true if the volume gauge needs updating */
+#if CONFIG_LED == LED_VIRTUAL
+    bool led; /* disk LED simulation in the status bar */
+#endif
+#ifdef HAVE_USB_POWER
+    bool usb_power;
+#endif
+};
+
+struct gui_statusbar
+{
+    /* Volume icon stuffs */
+    long volume_icon_switch_tick;
+    int last_volume;
+
+    long battery_icon_switch_tick;
+
+#ifdef HAVE_CHARGING
+    int battery_charge_step;
+#endif
+
+    struct status_info info;
+    struct status_info lastinfo;
+
+    struct screen * display;
+};
+
+/*
+ * Initializes a status bar
+ *  - bar : the bar to initialize
+ */
+extern void gui_statusbar_init(struct gui_statusbar * bar);
+
+/*
+ * Attach the status bar to a screen
+ * (The previous screen attachement is lost)
+ *  - bar : the statusbar structure
+ *  - display : the screen to attach
+ */
+extern void gui_statusbar_set_screen(struct gui_statusbar * bar, struct screen * display);
+
+/*
+ * Draws the status bar on the attached screen
+ * - bar : the statusbar structure
+ */
+extern void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw);
+
+void gui_statusbar_icon_battery(struct screen * display, int percent);
+bool gui_statusbar_icon_volume(struct gui_statusbar * bar, int percent);
+void gui_statusbar_icon_play_state(struct screen * display, int state);
+void gui_statusbar_icon_play_mode(struct screen * display, int mode);
+void gui_statusbar_icon_shuffle(struct screen * display);
+void gui_statusbar_icon_lock(struct screen * display);
+#if CONFIG_LED == LED_VIRTUAL
+void gui_statusbar_led(struct screen * display);
+#endif
+
+#ifdef HAVE_RTC
+void gui_statusbar_time(struct screen * display, int hour, int minute);
+#endif
+
+
+struct gui_syncstatusbar
+{
+    struct gui_statusbar statusbars[NB_SCREENS];
+};
+
+extern void gui_syncstatusbar_init(struct gui_syncstatusbar * bars);
+extern void gui_syncstatusbar_draw(struct gui_syncstatusbar * bars, bool force_redraw);
+
+#endif /*_GUI_STATUSBAR_H_*/
diff --git a/apps/status.c b/apps/status.c
index ca4b218..9f43c65 100644
--- a/apps/status.c
+++ b/apps/status.c
@@ -43,12 +43,12 @@
 #endif
 #include "usb.h"
 
-static enum playmode ff_mode;
+enum playmode ff_mode;
 
-static long switch_tick;
-static bool battery_state = true;
+long switch_tick;
+bool battery_state = true;
 #ifdef HAVE_CHARGING
-static int  battery_charge_step = 0;
+int battery_charge_step = 0;
 #endif
 
 struct status_info {
@@ -123,10 +123,10 @@
 }
 
 #if defined(HAVE_LCD_CHARCELLS)
-static bool record = false;
-static bool audio = false;
-static bool param = false;
-static bool usb = false;
+bool record = false;
+bool audio = false;
+bool param = false;
+bool usb = false;
 
 void status_set_record(bool b)
 {
diff --git a/apps/status.h b/apps/status.h
index 0d8c80d..29316f9 100644
--- a/apps/status.h
+++ b/apps/status.h
@@ -19,6 +19,21 @@
 #ifndef _STATUS_H
 #define _STATUS_H
 
+extern enum playmode ff_mode;
+
+extern long switch_tick;
+extern bool battery_state;
+#ifdef HAVE_CHARGING
+extern int battery_charge_step;
+#endif
+
+#if defined(HAVE_LCD_CHARCELLS)
+extern bool record;
+extern bool audio;
+extern bool param;
+extern bool usb;
+#endif
+
 enum playmode
 {
     STATUS_PLAY,
@@ -33,10 +48,12 @@
 void status_init(void);
 void status_set_ffmode(enum playmode mode);
 enum playmode status_get_ffmode(void);
+int current_playmode(void);
+
 #ifdef HAVE_LCD_BITMAP
 bool statusbar(bool state);
 #if CONFIG_KEYPAD == RECORDER_PAD
-void buttonbar_set(const char* caption1, const char* caption2, 
+void buttonbar_set(const char* caption1, const char* caption2,
                    const char* caption3);
 void buttonbar_unset(void);
 bool buttonbar_isset(void);
diff --git a/apps/tree.c b/apps/tree.c
index 8d68814..7d4ee7f 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -63,6 +63,12 @@
 #include "rtc.h"
 #include "dircache.h"
 
+/* gui api */
+#include "list.h"
+#include "statusbar.h"
+#include "splash.h"
+#include "buttonbar.h"
+
 #ifdef HAVE_LCD_BITMAP
 #include "widgets.h"
 #endif
@@ -99,6 +105,14 @@
 #endif /* #ifndef SIMULATOR */
 };
 
+struct gui_synclist tree_lists;
+
+/* I put it here because other files doesn't use it yet,
+ * but should be elsewhere since it will be used mostly everywhere */
+struct gui_syncstatusbar statusbars;
+#ifdef HAS_BUTTONBAR
+struct gui_buttonbar tree_buttonbar;
+#endif
 static struct tree_context tc;
 
 bool boot_changed = false;
@@ -112,17 +126,77 @@
 
 static bool start_wps = false;
 static bool dirbrowse(void);
-static int curr_context = false;
+static int curr_context = false;/* id3db or tree*/
+
+/*
+ * removes the extension of filename (if it doesn't start with a .)
+ * puts the result in buffer
+ */
+char * strip_extension(char * filename, char * buffer)
+{
+    int dotpos;
+    char * dot=strrchr(filename, '.');
+    if(dot!=0 && filename[0]!='.')
+    {
+        dotpos = dot-filename;
+        strncpy(buffer, filename, dotpos);
+        buffer[dotpos]='\0';
+        return(buffer);
+    }
+    else
+        return(filename);
+}
+char * tree_get_filename(int selected_item, char *buffer)
+{
+    char *name;
+    int attr=0;
+    bool id3db = *tc.dirfilter == SHOW_ID3DB;
+    if (id3db) {
+        name = ((char**)tc.dircache)[selected_item * tc.dentry_size];
+    }
+    else {
+        struct entry* dc = tc.dircache;
+        struct entry* e = &dc[selected_item];
+        name = e->name;
+        attr = e->attr;
+    }
+    /* if any file filter is on, and if it's not a directory,
+     * strip the extension */
+
+    if ( (*tc.dirfilter != SHOW_ID3DB) && !(attr & ATTR_DIRECTORY)
+        && (*tc.dirfilter != SHOW_ALL) )
+    {
+        return(strip_extension(name, buffer));
+    }
+    return(name);
+}
+
+
+void tree_get_fileicon(int selected_item, ICON * icon)
+{
+    bool id3db = *tc.dirfilter == SHOW_ID3DB;
+    if (id3db) {
+        *icon = db_get_icon(&tc);
+    }
+    else {
+        struct entry* dc = tc.dircache;
+        struct entry* e = &dc[selected_item];
+        *icon = filetype_get_icon(e->attr);
+    }
+}
 
 bool check_rockboxdir(void)
 {
     DIR *dir = opendir(ROCKBOX_DIR);
     if(!dir)
     {
-        lcd_clear_display();
-        splash(HZ*2, true, str(LANG_NO_ROCKBOX_DIR));
-        lcd_clear_display();
-        splash(HZ*2, true, str(LANG_INSTALLATION_INCOMPLETE));
+        int i;
+        for(i = 0;i < NB_SCREENS;++i)
+            screens[i].clear_display();
+        gui_syncsplash(HZ*2, true, str(LANG_NO_ROCKBOX_DIR));
+        for(i = 0;i < NB_SCREENS;++i)
+            screens[i].clear_display();
+        gui_syncsplash(HZ*2, true, str(LANG_INSTALLATION_INCOMPLETE));
         return false;
     }
     closedir(dir);
@@ -131,16 +205,28 @@
 
 void browse_root(void)
 {
+    /* essential to all programs that wants to display things */
+    screen_access_init();
+
     filetype_init();
     check_rockboxdir();
 
     strcpy(tc.currdir, "/");
+
 #ifdef HAVE_LCD_CHARCELLS
-    lcd_double_height(false);
+    int i;
+    for(i = 0;i < NB_SCREENS;++i)
+        screens[i].double_height(false);
 #endif
+#ifdef HAS_BUTTONBAR
+    gui_buttonbar_init(&tree_buttonbar);
+    /* since archos only have one screen, no need to create more than that */
+    gui_buttonbar_set_display(&tree_buttonbar, &(screens[SCREEN_MAIN]) );
+#endif
+    gui_syncstatusbar_init(&statusbars);
+    gui_synclist_init(&tree_lists, &tree_get_fileicon, &tree_get_filename);
 #ifndef SIMULATOR
     dirbrowse();
-
 #else
     if (!dirbrowse()) {
         DEBUGF("No filesystem found. Have you forgotten to create it?\n");
@@ -159,126 +245,35 @@
     return &tc;
 }
 
-#ifdef HAVE_LCD_BITMAP
-
-/* pixel margins */
-#define MARGIN_X (global_settings.scrollbar && \
-                  tc.filesindir > tree_max_on_screen ? SCROLLBAR_WIDTH : 0) + \
-                  CURSOR_WIDTH + (global_settings.show_icons && ICON_WIDTH > 0 ? ICON_WIDTH :0)
-#define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0)
-
-/* position the entry-list starts at */
-#define LINE_X   0
-#define LINE_Y   (global_settings.statusbar ? 1 : 0)
-
-#define CURSOR_X (global_settings.scrollbar && \
-                  tc.filesindir > tree_max_on_screen ? 1 : 0)
-#define CURSOR_Y 0 /* the cursor is not positioned in regard to
-                      the margins, so this is the amount of lines
-                      we add to the cursor Y position to position
-                      it on a line */
-#define CURSOR_WIDTH  (global_settings.invert_cursor ? 0 : 4)
-
-#define ICON_WIDTH    6
-
-#define SCROLLBAR_X      0
-#define SCROLLBAR_Y      lcd_getymargin()
-#define SCROLLBAR_WIDTH  6
-
-#else /* HAVE_LCD_BITMAP */
-
-#define TREE_MAX_ON_SCREEN   2
-#define TREE_MAX_LEN_DISPLAY 11 /* max length that fits on screen */
-#define LINE_X      2 /* X position the entry-list starts at */
-#define LINE_Y      0 /* Y position the entry-list starts at */
-
-#define CURSOR_X    0
-#define CURSOR_Y    0 /* not really used for players */
-
-#endif /* HAVE_LCD_BITMAP */
-
 /* talkbox hovering delay, to avoid immediate disk activity */
 #define HOVER_DELAY (HZ/2)
-
-static void showfileline(int line, char* name, int attr, bool scroll)
+/*
+ * Returns the position of a given file in the current directory
+ * returns -1 if not found
+ */
+int tree_get_file_position(char * filename)
 {
-    int xpos = LINE_X;
-    char* dotpos = NULL;
-
-#ifdef HAVE_LCD_CHARCELLS
-    if (!global_settings.show_icons)
-        xpos--;
-#endif
-
-    /* if any file filter is on, strip the extension */
-    if (*tc.dirfilter != SHOW_ID3DB &&
-        *tc.dirfilter != SHOW_ALL &&
-        !(attr & ATTR_DIRECTORY))
-    {
-        dotpos = strrchr(name, '.');
-        if (dotpos) {
-            *dotpos = 0;
-        }
-    }
-    
-    if(scroll) {
-#ifdef HAVE_LCD_BITMAP
-        lcd_setfont(FONT_UI);
-        if (global_settings.invert_cursor)
-            lcd_puts_scroll_style(xpos, line, name, STYLE_INVERT);
-        else
-#endif
-            lcd_puts_scroll(xpos, line, name);
-    } else
-        lcd_puts(xpos, line, name);
-
-    /* Restore the dot before the extension if it was removed */
-    if (dotpos)
-        *dotpos = '.';
-}
-
-#ifdef HAVE_LCD_BITMAP
-static int recalc_screen_height(void)
-{
-    int fw, fh;
-    int height = LCD_HEIGHT;
-
-    lcd_setfont(FONT_UI);
-    lcd_getstringsize("A", &fw, &fh);
-    if(global_settings.statusbar)
-        height -= STATUSBAR_HEIGHT;
-
-#if CONFIG_KEYPAD == RECORDER_PAD
-    if(global_settings.buttonbar)
-        height -= BUTTONBAR_HEIGHT;
-#endif        
-
-    return height / fh;
-}
-#endif
-
-static int showdir(void)
-{
-    struct entry *dircache = tc.dircache;
     int i;
-    int tree_max_on_screen;
-    int start = tc.dirstart;
-    bool id3db = *tc.dirfilter == SHOW_ID3DB;
-    bool newdir = false;
-#ifdef HAVE_LCD_BITMAP
-    const char* icon;
-    int line_height;
-    int fw, fh;
-    lcd_setfont(FONT_UI);
-    lcd_getstringsize("A", &fw, &fh);
-    tree_max_on_screen = recalc_screen_height();
-    line_height = fh;
-#else
-    int icon;
-    tree_max_on_screen = TREE_MAX_ON_SCREEN;
-#endif
+    /* use lastfile to determine the selected item (default=0) */
+    for (i=0; i < tc.filesindir; i++)
+    {
+        struct entry* dc = tc.dircache;
+        struct entry* e = &dc[i];
+        if (!strcasecmp(e->name, filename))
+            return(i);
+    }
+    return(-1);/* no file can match, returns undefined */
+}
 
-    /* new file dir? load it */
+/*
+ * Called when a new dir is loaded (for example when returning from other apps ...)
+ * also completely redraws the tree
+ */
+static int update_dir(void)
+{
+    bool id3db = *tc.dirfilter == SHOW_ID3DB;
+    bool changed = false;
+    /* Checks for changes */
     if (id3db) {
         if (tc.currtable != lasttable ||
             tc.currextra != lastextra ||
@@ -286,151 +281,73 @@
         {
             if (db_load(&tc) < 0)
                 return -1;
+
             lasttable = tc.currtable;
             lastextra = tc.currextra;
             lastfirstpos = tc.firstpos;
-            newdir = true;
+            changed = true;
         }
     }
     else {
+        /* if the tc.currdir has been changed, reload it ...*/
         if (strncmp(tc.currdir, lastdir, sizeof(lastdir)) || reload_dir) {
-            if (ft_load(&tc, NULL) < 0)     
+
+            if (ft_load(&tc, NULL) < 0)
                 return -1;
             strcpy(lastdir, tc.currdir);
-            newdir = true;
+            changed = true;
         }
     }
-
-    if (newdir && !id3db &&
-        (tc.dirfull || tc.filesindir == global_settings.max_files_in_dir) )
+    /* if selected item is undefined */
+    if (tc.selected_item == -1)
     {
-#ifdef HAVE_LCD_CHARCELLS
-        lcd_double_height(false);
-#endif
-        lcd_clear_display();
-        lcd_puts(0,0,str(LANG_SHOWDIR_ERROR_BUFFER));
-        lcd_puts(0,1,str(LANG_SHOWDIR_ERROR_FULL));
-        lcd_update();
-        sleep(HZ*2);
-        lcd_clear_display();
+        /* use lastfile to determine the selected item */
+        tc.selected_item = tree_get_file_position(lastfile);
+
+        /* If the file doesn't exists, select the first one (default) */
+        if(tc.selected_item < 0)
+            tc.selected_item = 0;
+        changed = true;
     }
-
-    if (start == -1)
+    if (changed)
     {
-        int diff_files;
-
-        /* use lastfile to determine start (default=0) */
-        start = 0;
-
-        for (i=0; i < tc.filesindir; i++)
+        if(!id3db && (tc.dirfull ||
+                      tc.filesindir == global_settings.max_files_in_dir) )
         {
-            struct entry *dircache = tc.dircache;
-
-            if (!strcasecmp(dircache[i].name, lastfile))
+            /* dir full */
+            int i;
+            for(i = 0;i < NB_SCREENS;++i)
             {
-                start = i;
-                break;
-            }
-        }
-
-        diff_files = tc.filesindir - start;
-        if (diff_files < tree_max_on_screen)
-        {
-            int oldstart = start;
-
-            start -= (tree_max_on_screen - diff_files);
-            if (start < 0)
-                start = 0;
-
-            tc.dircursor = oldstart - start;
-        }
-
-        tc.dirstart = start;
-    }
-
-    /* The cursor might point to an invalid line, for example if someone
-       deleted the last file in the dir */
-    if (tc.filesindir)
-    {
-        while (start + tc.dircursor >= tc.filesindir)
-        {
-            if (start)
-                start--;
-            else
-                if (tc.dircursor)
-                    tc.dircursor--;
-        }
-        tc.dirstart = start;
-    }
-
 #ifdef HAVE_LCD_CHARCELLS
-    lcd_stop_scroll();
-    lcd_double_height(false);
+                screens[i].double_height(false);
 #endif
-    lcd_clear_display();
-#ifdef HAVE_LCD_BITMAP
-    lcd_setmargins(MARGIN_X,MARGIN_Y); /* leave room for cursor and icon */
-    lcd_setfont(FONT_UI);
+                screens[i].clear_display();
+                screens[i].puts(0,0,str(LANG_SHOWDIR_ERROR_BUFFER));
+                screens[i].puts(0,1,str(LANG_SHOWDIR_ERROR_FULL));
+#if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR)
+                screens[i].update();
 #endif
-
-
-    for ( i=start; i < start+tree_max_on_screen && i < tc.filesindir; i++ ) {
-        int line = i - start;
-        char* name;
-        int attr = 0;
-
-        if (id3db) {
-            name = ((char**)tc.dircache)[i * tc.dentry_size];
-            icon = db_get_icon(&tc);
+            }
+            sleep(HZ*2);
+            for(i = 0;i < NB_SCREENS;++i)
+                screens[i].clear_display();
         }
-        else { 
-            struct entry* dc = tc.dircache;
-            struct entry* e = &dc[i];
-            name = e->name;
-            attr = e->attr;
-            icon = filetype_get_icon(dircache[i].attr);
-        }
-            
-
-        if (icon && global_settings.show_icons) {
-#ifdef HAVE_LCD_BITMAP
-            int offset=0;
-            if ( line_height > 8 )
-                offset = (line_height - 8) / 2;
-            lcd_mono_bitmap(icon,
-                            CURSOR_X * 6 + CURSOR_WIDTH,
-                            MARGIN_Y+(i-start)*line_height + offset, 6, 8);
-#else
-            if (icon < 0 )
-                icon = Icon_Unknown;
-            lcd_putc(LINE_X-1, i-start, icon);
-#endif
-        }
-
-        showfileline(line, name, attr, false); /* no scroll */
     }
-
-#ifdef HAVE_LCD_BITMAP
-    if (global_settings.scrollbar && (tc.dirlength > tree_max_on_screen))
-        scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1,
-                  tree_max_on_screen * line_height, tc.dirlength,
-                  start + tc.firstpos,
-                  start + tc.firstpos + tree_max_on_screen, VERTICAL);
-
-#if CONFIG_KEYPAD == RECORDER_PAD
+    gui_synclist_set_nb_items(&tree_lists, tc.filesindir);
+    gui_synclist_select_item(&tree_lists, tc.selected_item);
+    gui_synclist_draw(&tree_lists);
+    gui_syncstatusbar_draw(&statusbars, true);
+#ifdef HAS_BUTTONBAR
     if (global_settings.buttonbar) {
         if (*tc.dirfilter < NUM_FILTER_MODES)
-            buttonbar_set(str(LANG_DIRBROWSE_F1),
+            gui_buttonbar_set(&tree_buttonbar, str(LANG_DIRBROWSE_F1),
                           str(LANG_DIRBROWSE_F2),
                           str(LANG_DIRBROWSE_F3));
         else
-            buttonbar_set("<<<", "", "");
-        buttonbar_draw();
+            gui_buttonbar_set(&tree_buttonbar, "<<<", "", "");
+        gui_buttonbar_draw(&tree_buttonbar);
     }
 #endif
-#endif
-    status_draw(true);
-
     return tc.filesindir;
 }
 
@@ -468,7 +385,6 @@
 static void start_resume(bool just_powered_on)
 {
     bool do_resume = false;
-    
     if ( global_settings.resume_index != -1 ) {
         DEBUGF("Resume index %X offset %X\n",
                global_settings.resume_index,
@@ -486,7 +402,7 @@
             do_resume = true;
 
         if (! do_resume) return;
-    
+
         if (playlist_resume() != -1)
         {
             playlist_start(global_settings.resume_index,
@@ -496,23 +412,23 @@
         }
         else return;
     } else if (! just_powered_on) {
-        splash(HZ*2, true, str(LANG_NOTHING_TO_RESUME));
+        gui_syncsplash(HZ*2, true, str(LANG_NOTHING_TO_RESUME));
     }
 }
 
+/* Selects a file and update tree context properly */
 void set_current_file(char *path)
 {
     char *name;
-    unsigned int i;
+    int i;
 
     /* in ID3DB mode it is a bad idea to call this function */
     /* (only happens with `follow playlist') */
     if( *tc.dirfilter == SHOW_ID3DB )
-    {
         return;
-    }
 
     /* separate directory from filename */
+    /* gets the directory's name and put it into tc.currdir */
     name = strrchr(path+1,'/');
     if (name)
     {
@@ -528,24 +444,27 @@
     }
 
     strcpy(lastfile, name);
+    
+    /* undefined item selected */
+    tc.selected_item = -1;
 
-    tc.dircursor    =  0;
-    tc.dirstart     = -1;
-
+    /* If we changed dir we must recalculate the dirlevel
+       and adjust the selected history properly */
     if (strncmp(tc.currdir,lastdir,sizeof(lastdir)))
     {
-        tc.dirlevel            =  0;
-        tc.dirpos[tc.dirlevel]    = -1;
-        tc.cursorpos[tc.dirlevel] =  0;
+        tc.dirlevel =  0;
+        tc.selected_item_history[tc.dirlevel] = -1;
 
         /* use '/' to calculate dirlevel */
-        for (i=1; i<strlen(path)+1; i++)
+        /* FIXME : strlen(path) : crazy oO better to store it at
+           the beginning */
+        int path_len = strlen(path) + 1;
+        for (i = 1; i < path_len; i++)
         {
             if (path[i] == '/')
             {
                 tc.dirlevel++;
-                tc.dirpos[tc.dirlevel]    = -1;
-                tc.cursorpos[tc.dirlevel] =  0;
+                tc.selected_item_history[tc.dirlevel] = -1;
             }
         }
     }
@@ -567,24 +486,20 @@
     }
     return currmode;
 }
-
+/* main loop, handles key events */
 static bool dirbrowse(void)
 {
     int numentries=0;
     char buf[MAX_PATH];
-    int i;
-    int lasti=-1;
+    int lasti = -1;
     unsigned button;
-    int tree_max_on_screen;
     bool reload_root = false;
     int lastfilter = *tc.dirfilter;
     bool lastsortcase = global_settings.sort_case;
-    int lastdircursor=-1;
     bool need_update = true;
     bool exit_func = false;
     long thumbnail_time = -1; /* for delaying a thumbnail */
-    bool update_all = false; /* set this to true when the whole file list
-                                has been refreshed on screen */
+
     unsigned lastbutton = 0;
     char* currdir = tc.currdir; /* just a shortcut */
     bool id3db = *tc.dirfilter == SHOW_ID3DB;
@@ -593,15 +508,10 @@
         curr_context=CONTEXT_ID3DB;
     else
         curr_context=CONTEXT_TREE;
-
 #ifdef HAVE_LCD_BITMAP
-    tree_max_on_screen = recalc_screen_height();
-#else
-    tree_max_on_screen = TREE_MAX_ON_SCREEN;
+    screen_access_update_nb_lines();
 #endif
-
-    tc.dircursor=0;
-    tc.dirstart=0;
+    tc.selected_item = 0;
     tc.dirlevel=0;
     tc.firstpos=0;
     lasttable = -1;
@@ -624,25 +534,21 @@
         start_resume(true);
 
     }
-    
+    /* If we don't need to show the wps, draw the dir */
     if (!start_wps) {
-        numentries = showdir();
+        numentries = update_dir();
         if (numentries == -1)
             return false;  /* currdir is not a directory */
-    
+
         if (*tc.dirfilter > NUM_FILTER_MODES && numentries==0)
         {
-            splash(HZ*2, true, str(LANG_NO_FILES));
+            gui_syncsplash(HZ*2, true, str(LANG_NO_FILES));
             return false;  /* No files found for rockbox_browser() */
         }
-        update_all = true;
-
-        put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
     }
 
     while(1) {
         struct entry *dircache = tc.dircache;
-
         bool restore = false;
 
         button = button_get_w_tmo(HZ/5);
@@ -651,15 +557,18 @@
         if (boot_changed) {
             bool stop = false;
             unsigned int button;
-
-            lcd_clear_display();
-            lcd_puts(0,0,str(LANG_BOOT_CHANGED));
-            lcd_puts(0,1,str(LANG_REBOOT_NOW));
+            int i;
+            for(i = 0;i < NB_SCREENS;++i)
+            {
+                screens[i].clear_display();
+                screens[i].puts(0,0,str(LANG_BOOT_CHANGED));
+                screens[i].puts(0,1,str(LANG_REBOOT_NOW));
 #ifdef HAVE_LCD_BITMAP
-            lcd_puts(0,3,str(LANG_CONFIRM_WITH_PLAY_RECORDER));
-            lcd_puts(0,4,str(LANG_CANCEL_WITH_ANY_RECORDER));
-            lcd_update();
+                screens[i].puts(0,3,str(LANG_CONFIRM_WITH_PLAY_RECORDER));
+                screens[i].puts(0,4,str(LANG_CANCEL_WITH_ANY_RECORDER));
+                screens[i].update();
 #endif
+            }
             while (!stop) {
                 button = button_get(true);
                 switch (button) {
@@ -683,6 +592,7 @@
             boot_changed = false;
         }
 #endif
+        need_update = gui_synclist_do_button(&tree_lists, button);
 
         switch ( button ) {
 #ifdef TREE_ENTER
@@ -702,33 +612,17 @@
                     && (lastbutton != TREE_RUN_PRE)))
                     break;
 #endif
-                if ( !numentries )
+                /* nothing to do if no files to display */
+                if ( numentries == 0 )
                     break;
 
-                if (id3db)
-                    i = db_enter(&tc);
-                else
-                    i = ft_enter(&tc);
-                    
-                switch (i)
+                switch (id3db?db_enter(&tc):ft_enter(&tc))
                 {
                     case 1: reload_dir = true; break;
                     case 2: start_wps = true; break;
                     case 3: exit_func = true; break;
                     default: break;
                 }
-
-#ifdef HAVE_LCD_BITMAP
-                /* maybe we have a new font */
-                tree_max_on_screen = recalc_screen_height();
-#endif
-                /* make sure cursor is on screen */
-                while ( tc.dircursor > tree_max_on_screen )
-                {
-                    tc.dircursor--;
-                    tc.dirstart++;
-                }
-
                 restore = true;
                 break;
 
@@ -741,8 +635,8 @@
                     exit_func = true;
                     break;
                 }
-
-                if (!tc.dirlevel)
+                /* if we are in /, nothing to do */
+                if (tc.dirlevel == 0)
                     break;
 
                 if (id3db)
@@ -783,169 +677,6 @@
                 break;
 #endif
 #endif
-
-            case TREE_PREV:
-            case TREE_PREV | BUTTON_REPEAT:
-#ifdef TREE_RC_PREV
-            case TREE_RC_PREV:
-            case TREE_RC_PREV | BUTTON_REPEAT:
-#endif
-                if (!tc.filesindir)
-                    break;
-
-                /* start scrolling when at 1/3 of the screen */
-                if (tc.dircursor >=
-                        tree_max_on_screen - (2 * tree_max_on_screen) / 3
-                        || (tc.dirstart == 0 && tc.dircursor > 0)) {
-                    put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false);
-                    tc.dircursor--;
-                    put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
-                }
-                else {
-                    if (tc.dirstart || tc.firstpos) {
-                        if (tc.dirstart)
-                            tc.dirstart--;
-                        else {
-                            if (tc.firstpos > max_files/2) {
-                                tc.firstpos -= max_files/2;
-                                tc.dirstart += max_files/2;
-                                tc.dirstart--;
-                            }
-                            else {
-                                tc.dirstart = tc.firstpos - 1;
-                                tc.firstpos = 0;
-                            }
-                        }
-                        restore = true;
-                    }
-                    else {
-                        if (button & BUTTON_REPEAT)
-                            break;
-                        if (numentries < tree_max_on_screen) {
-                            put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor,
-                                         false);
-                            tc.dircursor = numentries - 1;
-                            put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor,
-                                         true);
-                        }
-                        else if (id3db && tc.dirfull) {
-                            /* load last dir segment */
-                            /* use max_files/2 in case names are longer than
-                                AVERAGE_FILE_LENGTH */
-                            tc.firstpos = tc.dirlength - max_files/2;
-                            tc.dirstart = tc.firstpos;
-                            tc.dircursor = tree_max_on_screen - 1;
-                            numentries = showdir();
-                            update_all = true;
-                            put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor,
-                                         true);
-                        }
-                        else {
-                            tc.dirstart = numentries - tree_max_on_screen;
-                            tc.dircursor = tree_max_on_screen - 1;
-                            restore = true;
-                        }
-                    }
-                }
-                need_update = true;
-                break;
-
-            case TREE_NEXT:
-            case TREE_NEXT | BUTTON_REPEAT:
-#ifdef TREE_RC_NEXT
-            case TREE_RC_NEXT:
-            case TREE_RC_NEXT | BUTTON_REPEAT:
-#endif
-                if (!tc.filesindir)
-                    break;
-
-                if (tc.dircursor + tc.dirstart + 1 < numentries ) {
-                    /* start scrolling when at 2/3 of the screen */
-                    if(tc.dircursor < (2 * tree_max_on_screen) / 3 ||
-                            numentries - tc.dirstart <= tree_max_on_screen) {
-                        put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false);
-                        tc.dircursor++;
-                        put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
-                    }
-                    else {
-                        tc.dirstart++;
-                        restore = true;
-                    }
-                }
-                else if (id3db && (tc.firstpos || tc.dirfull)) {
-                    if (tc.dircursor + tc.dirstart + tc.firstpos + 1 >= tc.dirlength) {
-                        /* wrap and load first dir segment */
-                        if (button & BUTTON_REPEAT)
-                            break;
-                        tc.firstpos = tc.dirstart = tc.dircursor = 0;
-                    }
-                    else {
-                        /* load next dir segment */
-                        tc.firstpos += tc.dirstart;
-                        tc.dirstart = 0;
-                    }
-                    restore = true;
-                }
-                else {
-                    if (button & BUTTON_REPEAT)
-                        break;
-                    if(numentries < tree_max_on_screen) {
-                        put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false);
-                        tc.dirstart = tc.dircursor = 0;
-                        put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
-                    }
-                    else {
-                        tc.dirstart = tc.dircursor = 0;
-                        numentries = showdir();
-                        update_all=true;
-                        put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
-                    }
-                }
-                need_update = true;
-                break;
-
-#ifdef TREE_PGUP
-            case TREE_PGUP:
-            case TREE_PGUP | BUTTON_REPEAT:
-                if (tc.dirstart) {
-                    tc.dirstart -= tree_max_on_screen;
-                    if ( tc.dirstart < 0 )
-                        tc.dirstart = 0;
-                }
-                else if (tc.firstpos) {
-                    if (tc.firstpos > max_files/2) {
-                        tc.firstpos -= max_files/2;
-                        tc.dirstart += max_files/2;
-                        tc.dirstart -= tree_max_on_screen;
-                    }
-                    else {
-                        tc.dirstart = tc.firstpos - tree_max_on_screen;
-                        tc.firstpos = 0;
-                    }
-                }
-                else
-                    tc.dircursor = 0;
-                restore = true;
-                break;
-
-            case TREE_PGDN:
-            case TREE_PGDN | BUTTON_REPEAT:
-                if ( tc.dirstart < numentries - tree_max_on_screen ) {
-                    tc.dirstart += tree_max_on_screen;
-                    if ( tc.dirstart > numentries - tree_max_on_screen )
-                        tc.dirstart = numentries - tree_max_on_screen;
-                }
-                else if (id3db && tc.dirfull) {
-                    /* load next dir segment */
-                    tc.firstpos += tc.dirstart;
-                    tc.dirstart = 0;
-                }
-                else
-                    tc.dircursor = numentries - tc.dirstart - 1;
-                restore = true;
-                break;
-#endif
-
             case TREE_MENU:
 #ifdef TREE_RC_MENU
             case TREE_RC_MENU:
@@ -957,7 +688,9 @@
                 /* don't enter menu from plugin browser */
                 if (*tc.dirfilter < NUM_FILTER_MODES)
                 {
-                    lcd_stop_scroll();
+                    int i;
+                    for(i = 0;i < NB_SCREENS;++i)
+                        screens[i].stop_scroll();
                     if (main_menu())
                         reload_dir = true;
                     restore = true;
@@ -1017,7 +750,7 @@
                 {
                     if (quick_screen(curr_context, BUTTON_F3))
                         reload_dir = true;
-                    tree_max_on_screen = recalc_screen_height();
+                    screen_access_update_nb_lines();
                     restore = true;
                 }
                 break;
@@ -1052,20 +785,19 @@
                     }
                     else
                     {
-                        attr = dircache[tc.dircursor+tc.dirstart].attr;
+                        attr = dircache[tc.selected_item].attr;
 
-                        if (currdir[1])
+                        if (currdir[1]) /* Not in / */
                             snprintf(buf, sizeof buf, "%s/%s",
                                      currdir,
-                                     dircache[tc.dircursor+tc.dirstart].name);
-                        else
+                                     dircache[tc.selected_item].name);
+                        else /* In / */
                             snprintf(buf, sizeof buf, "/%s",
-                                     dircache[tc.dircursor+tc.dirstart].name);
+                                     dircache[tc.selected_item].name);
                     }
-                    
                     onplay_result = onplay(buf, attr, curr_context);
                 }
-                
+
                 switch (onplay_result)
                 {
                     case ONPLAY_OK:
@@ -1099,22 +831,22 @@
                         }
                     }
                     else
-                    { 
-                        DEBUGF("Playing file thumbnail: %s/%s%s\n", 
+                    {
+                        DEBUGF("Playing file thumbnail: %s/%s%s\n",
                                currdir, dircache[lasti].name, file_thumbnail_ext);
-                        /* no fallback necessary, we knew in advance 
+                        /* no fallback necessary, we knew in advance
                            that the file exists */
                         ft_play_filename(currdir, dircache[lasti].name);
                     }
                     thumbnail_time = -1; /* job done */
                 }
-                status_draw(false);
+                gui_syncstatusbar_draw(&statusbars, false);
                 break;
 
 #ifdef HAVE_HOTSWAP
             case SYS_FS_CHANGED:
                 if (!id3db)
-                    reload_dir = true; 
+                    reload_dir = true;
                 /* The 'dir no longer valid' situation will be caught later
                  * by checking the showdir() result. */
                 break;
@@ -1139,18 +871,20 @@
             lastbutton = button;
         }
 
-        if (start_wps)
+        if (start_wps && audio_status() )
         {
-            lcd_stop_scroll();
+            int i;
+            for(i = 0;i < NB_SCREENS;++i)
+                screens[i].stop_scroll();
             if (wps_show() == SYS_USB_CONNECTED)
                 reload_dir = true;
 #ifdef HAVE_HOTSWAP
-            else 
+            else
                 if (!id3db) /* Try reload to catch 'no longer valid' case. */
                     reload_dir = true;
 #endif
 #ifdef HAVE_LCD_BITMAP
-            tree_max_on_screen = recalc_screen_height();
+            screen_access_update_nb_lines();
 #endif
             id3db = check_changed_id3mode(id3db);
             restore = true;
@@ -1174,8 +908,9 @@
             }
             if (! reload_dir )
             {
-                tc.dircursor = 0;
-                tc.dirstart = 0;
+                gui_synclist_select_item(&tree_lists, 0);
+                gui_synclist_draw(&tree_lists);
+                tc.selected_item = 0;
                 lastdir[0] = 0;
             }
 
@@ -1190,132 +925,88 @@
 
         if (restore || reload_dir) {
             /* restore display */
-
 #ifdef HAVE_LCD_BITMAP
-            tree_max_on_screen = recalc_screen_height();
+            screen_access_update_nb_lines();
 #endif
-
-            /* We need to adjust if the number of lines on screen have
-               changed because of a status bar change */
-            if(CURSOR_Y+LINE_Y+tc.dircursor>tree_max_on_screen) {
-                tc.dirstart++;
-                tc.dircursor--;
-            }
-#ifdef HAVE_LCD_BITMAP
-            /* the sub-screen might've ruined the margins */
-            lcd_setmargins(MARGIN_X,MARGIN_Y); /* leave room for cursor and
-                                                  icon */
-            lcd_setfont(FONT_UI);
-#endif
-            numentries = showdir();
+            numentries = update_dir();
             if (currdir[1] && (numentries < 0))
             {   /* not in root and reload failed */
                 reload_root = true; /* try root */
                 reload_dir = false;
                 goto check_rescan;
             }
-            update_all = true;
-            put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true);
-
             need_update = true;
             reload_dir = false;
         }
+        if(need_update) {
+            tc.selected_item = gui_synclist_get_selected_item_position(&tree_lists);
+            need_update=false;
+            if ( numentries > 0 ) {
+                /* Voice the file if changed */
+                if(lasti != tc.selected_item || restore) {
+                    lasti = tc.selected_item;
+                    thumbnail_time = -1; /* Cancel whatever we were
+                                            about to say */
 
-        if ( (numentries > 0) && need_update) {
-            i = tc.dirstart+tc.dircursor;
+                    /* Directory? */
+                    if (dircache[tc.selected_item].attr & ATTR_DIRECTORY)
+                    {
+                        /* play directory thumbnail */
+                        switch (global_settings.talk_dir) {
+                            case 1: /* dirs as numbers */
+                                talk_id(VOICE_DIR, false);
+                                talk_number(tc.selected_item+1, true);
+                                break;
 
-            /* if MP3 filter is on, cut off the extension */
-            if(lasti!=i || restore) {
-                char* name;
-                int attr = 0;
+                            case 2: /* dirs spelled */
+                                talk_spell(dircache[tc.selected_item].name,
+                                           false);
+                                break;
 
-                if (id3db)
-                    name = ((char**)tc.dircache)[lasti * tc.dentry_size];
-                else {
-                    struct entry* dc = tc.dircache;
-                    struct entry* e = &dc[lasti];
-                    name = e->name;
-                    attr = e->attr;
-                }
-
-                lcd_stop_scroll();
-
-                /* So if lastdircursor and dircursor differ, and then full
-                   screen was not refreshed, restore the previous line */
-                if ((lastdircursor != tc.dircursor) && !update_all ) {
-                    showfileline(lastdircursor, name, attr, false); /* no scroll */
-                }
-                lasti=i;
-                lastdircursor=tc.dircursor;
-                thumbnail_time = -1; /* cancel whatever we were about to say */
-
-                if (id3db)
-                    name = ((char**)tc.dircache)[lasti * tc.dentry_size];
-                else {
-                    struct entry* dc = tc.dircache;
-                    struct entry* e = &dc[lasti];
-                    name = e->name;
-                    attr = e->attr;
-                }
-                showfileline(tc.dircursor, name, attr, true); /* scroll please */
-                need_update = true;
-
-                if (dircache[i].attr & ATTR_DIRECTORY) /* directory? */
-                {
-                    /* play directory thumbnail */
-                    switch (global_settings.talk_dir) {
-                        case 1: /* dirs as numbers */
-                            talk_id(VOICE_DIR, false);
-                            talk_number(i+1, true);
-                            break;
-
-                        case 2: /* dirs spelled */
-                            talk_spell(dircache[i].name, false);
-                            break;
-
-                        case 3: /* thumbnail clip */
-                            /* "schedule" a thumbnail, to have a little dalay */
-                            thumbnail_time = current_tick + HOVER_DELAY;
-                            break;
-
-                        default:
-                            break;
-                    }
-                }
-                else /* file */
-                {
-                    switch (global_settings.talk_file) {
-                        case 1: /* files as numbers */
-                            ft_play_filenumber(i-tc.dirsindir+1, 
-                                               dircache[i].attr & TREE_ATTR_MASK);
-                            break;
-
-                        case 2: /* files spelled */
-                            talk_spell(dircache[i].name, false);
-                            break;
-
-                        case 3: /* thumbnail clip */
-                            /* "schedule" a thumbnail, to have a little delay */
-                            if (dircache[i].attr & TREE_ATTR_THUMBNAIL)
+                            case 3: /* thumbnail clip */
+                                /* "schedule" a thumbnail, to have a little
+                                   delay */
                                 thumbnail_time = current_tick + HOVER_DELAY;
-                            else
-                                /* spell the number as fallback */
-                                talk_spell(dircache[i].name, false);
-                            break;
+                                break;
 
-                        default:
-                            break;
+                            default:
+                                break;
+                        }
+                    }
+                    else /* file */
+                    {
+                        switch (global_settings.talk_file) {
+                            case 1: /* files as numbers */
+                                ft_play_filenumber(
+                                    tc.selected_item-tc.dirsindir+1,
+                                    dircache[tc.selected_item].attr &
+                                    TREE_ATTR_MASK);
+                                break;
+
+                            case 2: /* files spelled */
+                                talk_spell(dircache[tc.selected_item].name,
+                                           false);
+                                break;
+
+                            case 3: /* thumbnail clip */
+                                /* "schedule" a thumbnail, to have a little
+                                   delay */
+                                if (dircache[tc.selected_item].attr &
+                                    TREE_ATTR_THUMBNAIL)
+                                    thumbnail_time = current_tick + HOVER_DELAY;
+                                else
+                                    /* spell the number as fallback */
+                                    talk_spell(dircache[tc.selected_item].name,
+                                               false);
+                                break;
+
+                            default:
+                                break;
+                        }
                     }
                 }
             }
         }
-
-        if(need_update) {
-            lcd_update();
-
-            need_update = false;
-            update_all = false;
-        }
     }
 
     return true;
@@ -1369,7 +1060,7 @@
             int x = strlen(entry->d_name);
             unsigned int i;
             char *cp = strrchr(entry->d_name,'.');
-            
+
             if (cp) {
                 cp++;
 
@@ -1379,6 +1070,7 @@
                         if (!strcasecmp(cp, filetypes[i].extension))
                         {
                             char buf[8];
+                            int i;
                             write(fd, dirname, strlen(dirname));
                             write(fd, "/", 1);
                             write(fd, entry->d_name, x);
@@ -1387,8 +1079,11 @@
                             plsize++;
                             snprintf(buf, sizeof buf, "%d", plsize);
 #ifdef HAVE_LCD_BITMAP
-                            lcd_puts(0,4,buf);
-                            lcd_update();
+                            for(i = 0;i < NB_SCREENS;++i)
+                            {
+                                screens[i].puts(0,4,buf);
+                                screens[i].update();
+                            }
 #else
                             x = 10;
                             if (plsize > 999)
@@ -1401,7 +1096,8 @@
                                         x=9;
                                 }
                             }
-                            lcd_puts(x,0,buf);
+                            for(i = 0;i < NB_SCREENS;++i)
+                                screens[i].puts(x,0,buf);
 #endif
                             break;
                         }
@@ -1418,16 +1114,20 @@
 bool create_playlist(void)
 {
     int fd;
+    int i;
     char filename[MAX_PATH];
 
     snprintf(filename, sizeof filename, "%s.m3u",
              tc.currdir[1] ? tc.currdir : "/root");
-
-    lcd_clear_display();
-    lcd_puts(0,0,str(LANG_CREATING));
-    lcd_puts_scroll(0,1,filename);
-    lcd_update();
-
+    for(i = 0;i < NB_SCREENS;++i)
+    {
+        screens[i].clear_display();
+        screens[i].puts(0,0,str(LANG_CREATING));
+        screens[i].puts_scroll(0,1,filename);
+#if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR)
+        screens[i].update();
+#endif
+    }
     fd = creat(filename,0);
     if (fd < 0)
         return false;
@@ -1435,7 +1135,7 @@
 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
     cpu_boost(true);
 #endif
-    
+
     snprintf(filename, sizeof(filename), "%s",
              tc.currdir[1] ? tc.currdir : "/");
     plsize = 0;
@@ -1445,7 +1145,7 @@
 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
     cpu_boost(false);
 #endif
-    
+
     sleep(HZ);
 
     return true;
@@ -1460,12 +1160,10 @@
     memcpy(tc.currdir, root, sizeof(tc.currdir));
     start_wps = false;
     tc.dirfilter = &dirfilter;
-    
+
     dirbrowse();
 
     tc = backup;
-    reload_dir = true;
-
     return false;
 }
 
@@ -1474,7 +1172,7 @@
     /* We copy the settings value in case it is changed by the user. We can't
        use it until the next reboot. */
     max_files = global_settings.max_files_in_dir;
-    
+
     /* initialize tree context struct */
     memset(&tc, 0, sizeof(tc));
     tc.dirfilter = &global_settings.dirfilter;
@@ -1498,7 +1196,7 @@
     {
         /* Playlist playback */
         char* slash;
-        // check that the file exists
+        /* check that the file exists */
         int fd = open(resume_file, O_RDONLY);
         if(fd<0)
             return;
@@ -1538,7 +1236,7 @@
             if ((strcmp(strrchr(playlist_peek(index) + 1,'/') + 1,
                         filename)))
             {
-                for ( i=0; i < playlist_amount(); i++ ) 
+                for ( i=0; i < playlist_amount(); i++ )
                 {
                     if ((strcmp(strrchr(playlist_peek(i) + 1,'/') + 1,
                                 filename)) == 0)
@@ -1599,7 +1297,7 @@
     }
 
     close(fd);
-  
+
     DEBUGF("Found: %s\n", dirname_mp3_filename);
 
     talk_file(dirname_mp3_filename, false);
@@ -1639,9 +1337,7 @@
     if (global_settings.dircache)
     {
         if (dircache_is_enabled())
-        {
             global_settings.dircache_size = dircache_get_cache_size();
-        }
         dircache_disable();
     }
     else
@@ -1659,21 +1355,27 @@
 #ifdef HAVE_DIRCACHE
     if (global_settings.dircache)
     {
-        int font_w, font_h;
-        
         /* Print "Scanning disk..." to the display. */
-        lcd_getstringsize("A", &font_w, &font_h);
-        lcd_putsxy((LCD_WIDTH/2) - ((strlen(str(LANG_DIRCACHE_BUILDING))*font_w)/2),
-                    LCD_HEIGHT-font_h*3, str(LANG_DIRCACHE_BUILDING));
-        lcd_update();
-
+        int i;
+        for(i = 0;i < NB_SCREENS;++i)
+        {
+            screens[i].putsxy((LCD_WIDTH/2) -
+                              ((strlen(str(LANG_DIRCACHE_BUILDING)) *
+                                screens[i].char_width)/2),
+                              LCD_HEIGHT-screens[i].char_height*3,
+                              str(LANG_DIRCACHE_BUILDING));
+            screens[i].update();
+        }
         dircache_build(global_settings.dircache_size);
-
         /* Clean the text when we are done. */
-        lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
-        lcd_fillrect(0, LCD_HEIGHT-font_h*3, LCD_WIDTH, font_h);
-        lcd_set_drawmode(DRMODE_SOLID);
-        lcd_update();
+        for(i=0;i<NB_SCREENS;++i)
+        {
+            screens[i].set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+            screens[i].fillrect(0, LCD_HEIGHT-screens[i].char_height*3,
+                                LCD_WIDTH, screens[i].char_height);
+            screens[i].set_drawmode(DRMODE_SOLID);
+            screens[i].update();
+        }
     }
 #endif
 }
diff --git a/apps/tree.h b/apps/tree.h
index a6c41f2..04532c8 100644
--- a/apps/tree.h
+++ b/apps/tree.h
@@ -23,6 +23,8 @@
 #include <applimits.h>
 #include <file.h>
 
+/*FIXME: don't forget to remove PGUP, PGDOW, NEXT, PREV
+ * when everything will be working with gui_list */
 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
     (CONFIG_KEYPAD == IRIVER_H300_PAD)
 #define TREE_NEXT      BUTTON_DOWN
@@ -43,8 +45,11 @@
 #define TREE_POWER_BTN BUTTON_ON
 #define TREE_QUICK     (BUTTON_MODE | BUTTON_REPEAT)
 
+/* Remote keys */
 #define TREE_RC_NEXT   BUTTON_RC_FF
 #define TREE_RC_PREV   BUTTON_RC_REW
+#define TREE_RC_PGUP   BUTTON_RC_SOURCE
+#define TREE_RC_PGDN   BUTTON_RC_BITRATE
 #define TREE_RC_EXIT   BUTTON_RC_STOP
 #define TREE_RC_RUN    (BUTTON_RC_MENU | BUTTON_REL)
 #define TREE_RC_RUN_PRE   BUTTON_RC_MENU
@@ -137,27 +142,36 @@
     int icon;
     int voiceclip;
 };
- 
+
 /* browser context for file or db */
 struct tree_context {
+    /* The directory we are browsing */
+    char currdir[MAX_PATH];
+    /* the number of directories we have crossed from / */
     int dirlevel;
-    int dircursor;
-    int dirstart;
+    /* The currently selected file/id3dbitem index (old dircursor+dirfile) */
+    int selected_item;
+    /* The selected item in each directory crossed
+     * (used when we want to return back to a previouws directory)*/
+    int selected_item_history[MAX_DIR_LEVELS];
+
     int firstpos; /* which dir entry is on first
                      position in dir buffer */
     int pos_history[MAX_DIR_LEVELS];
-    int dirpos[MAX_DIR_LEVELS];
-    int cursorpos[MAX_DIR_LEVELS];
-    char currdir[MAX_PATH]; /* file use */
+    int dirpos[MAX_DIR_LEVELS]; /* the dirstart history */
+    int cursorpos[MAX_DIR_LEVELS]; /* the dircursor history */
+
     int *dirfilter; /* file use */
-    int filesindir;
+    int filesindir; /* The number of files in the dircache */
     int dirsindir; /* file use */
     int dirlength; /* total number of entries in dir, incl. those not loaded */
     int table_history[MAX_DIR_LEVELS]; /* db use */
     int extra_history[MAX_DIR_LEVELS]; /* db use */
     int currtable; /* db use */
     int currextra; /* db use */
-
+    /* A big buffer with plenty of entry structs,
+     * contains all files and dirs in the current
+     * dir (with filters applied) */
     void* dircache;
     int dircache_size;
     char* name_buffer;
@@ -196,4 +210,7 @@
 void tree_flush(void);
 void tree_restore(void);
 
+
+extern struct gui_synclist tree_lists;
+extern struct gui_syncstatusbar statusbars;
 #endif
diff --git a/apps/wps.h b/apps/wps.h
index 6f0d601..e32bd3c 100644
--- a/apps/wps.h
+++ b/apps/wps.h
@@ -19,7 +19,7 @@
 #ifndef _WPS_H
 #define _WPS_H
 #include "id3.h"
-#include "playlist.h" 
+#include "playlist.h"
 
 /* button definitions */
 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
@@ -33,7 +33,7 @@
 #define WPS_INCVOL     BUTTON_UP
 #define WPS_DECVOL     BUTTON_DOWN
 #define WPS_PAUSE      (BUTTON_ON | BUTTON_REL)
-#define WPS_PAUSE_PRE  BUTTON_ON 
+#define WPS_PAUSE_PRE  BUTTON_ON
 #define WPS_MENU       (BUTTON_MODE | BUTTON_REL)
 #define WPS_MENU_PRE   BUTTON_MODE
 #define WPS_BROWSE     (BUTTON_SELECT | BUTTON_REL)
@@ -53,10 +53,10 @@
 #define WPS_RC_INCVOL  BUTTON_RC_VOL_UP
 #define WPS_RC_DECVOL  BUTTON_RC_VOL_DOWN
 #define WPS_RC_EXIT    BUTTON_RC_STOP
-#define WPS_RC_MENU    (BUTTON_RC_MENU | BUTTON_REL)
-#define WPS_RC_MENU_PRE BUTTON_RC_MENU
-#define WPS_RC_BROWSE  (BUTTON_RC_MODE | BUTTON_REL)
-#define WPS_RC_BROWSE_PRE BUTTON_RC_MODE
+#define WPS_RC_MENU    (BUTTON_RC_MODE | BUTTON_REL)
+#define WPS_RC_MENU_PRE BUTTON_RC_MODE
+#define WPS_RC_BROWSE  (BUTTON_RC_MENU | BUTTON_REL)
+#define WPS_RC_BROWSE_PRE BUTTON_RC_MENU
 
 #elif CONFIG_KEYPAD == RECORDER_PAD
 #define WPS_NEXT       (BUTTON_RIGHT | BUTTON_REL)
diff --git a/tools/configure b/tools/configure
index 4a0a4ee..ad66ba8 100755
--- a/tools/configure
+++ b/tools/configure
@@ -412,7 +412,7 @@
     shcc
     tool="$rootdir/tools/scramble"
     output="archos.mod"
-    appextra="player"
+    appextra="player:gui"
     archosrom="$pwd/rombox.ucl"
     flash="$pwd/rockbox.ucl"
     plugins="yes"
@@ -425,7 +425,7 @@
     shcc
     tool="$rootdir/tools/scramble"
     output="ajbrec.ajz"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom="$pwd/rombox.ucl"
     flash="$pwd/rockbox.ucl"
     plugins="yes"
@@ -438,7 +438,7 @@
     shcc
     tool="$rootdir/tools/scramble -fm"
     output="ajbrec.ajz"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom="$pwd/rombox.ucl"
     flash="$pwd/rockbox.ucl"
     plugins="yes"
@@ -451,7 +451,7 @@
     shcc
     tool="$rootdir/tools/scramble -v2"
     output="ajbrec.ajz"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom="$pwd/rombox.ucl"
     flash="$pwd/rockbox.ucl"
     plugins="yes"
@@ -465,7 +465,7 @@
     calmrisccc
     tool="cp" # might work for now!
     output="rockbox.gmini"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom=""
     flash=""
     plugins="" # disabled for now, enable later on
@@ -479,7 +479,7 @@
     calmrisccc
     tool="cp" # might work for now!
     output="rockbox.gmini"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom=""
     flash=""
     plugins="" # disabled for now, enable later on
@@ -492,7 +492,7 @@
     shcc
     tool="$rootdir/tools/scramble -osp"
     output="ajbrec.ajz"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom="$pwd/rombox.ucl"
     flash="$pwd/rockbox.ucl"
     plugins="yes"
@@ -505,7 +505,7 @@
     shcc
     tool="$rootdir/tools/scramble -ofm"
     output="ajbrec.ajz"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom="$pwd/rombox.ucl"
     flash="$pwd/rockbox.ucl"
     plugins="yes"
@@ -519,7 +519,7 @@
     coldfirecc
     tool="$rootdir/tools/scramble -add=h120"
     output="rockbox.iriver"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom=""
     flash=""
     plugins="yes"
@@ -533,7 +533,7 @@
     coldfirecc
     tool="$rootdir/tools/scramble -add=h300"
     output="rockbox.iriver"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom=""
     flash=""
     plugins="yes"
@@ -547,7 +547,7 @@
     coldfirecc
     tool="$rootdir/tools/scramble -add=h100"
     output="rockbox.iriver"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom=""
     flash=""
     plugins="yes"
@@ -561,7 +561,7 @@
     coldfirecc
     tool="$rootdir/tools/scramble -add=x5" # wrong, must be fixed
     output="rockbox.iaudio"
-    appextra="recorder"
+    appextra="recorder:gui"
     archosrom=""
     flash=""
     plugins="yes"