Customizable icons for all bitmap targets. (FS#7013)
http://www.rockbox.org/twiki/bin/view/Main/CustomIcons for info on format and how to load them


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13177 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/FILES b/apps/FILES
index d7207d7..1897f66 100644
--- a/apps/FILES
+++ b/apps/FILES
@@ -47,6 +47,7 @@
 plugins/bitmaps/native/*
 plugins/bitmaps/remote_mono/*
 plugins/bitmaps/remote_native/*
+plugins/bitmaps/viewer_defaults/*
 plugins/chessbox/Makefile
 plugins/chessbox/*.lds
 plugins/chessbox/*.[ch]
diff --git a/apps/SOURCES b/apps/SOURCES
index ca640ab..1dabb12 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -48,7 +48,9 @@
 gui/buttonbar.c
 gui/gwps.c
 gui/gwps-common.c
+#ifdef HAVE_LCD_BITMAP
 gui/icon.c
+#endif
 gui/list.c
 gui/option_select.c
 gui/quickscreen.c
diff --git a/apps/bitmaps/native/SOURCES b/apps/bitmaps/native/SOURCES
index ba642ab..51e92c9 100644
--- a/apps/bitmaps/native/SOURCES
+++ b/apps/bitmaps/native/SOURCES
@@ -40,4 +40,11 @@
 #endif
 #endif
 
+/* List Icons */
+#if LCD_DEPTH == 16
+default_icons.6x8x16.bmp
+#else
+default_icons.6x8x1.bmp
+#endif
+
 #endif /* HAVE_LCD_BITMAP */
diff --git a/apps/bitmaps/native/default_icons.6x8x1.bmp b/apps/bitmaps/native/default_icons.6x8x1.bmp
new file mode 100644
index 0000000..857b1e1
--- /dev/null
+++ b/apps/bitmaps/native/default_icons.6x8x1.bmp
Binary files differ
diff --git a/apps/bitmaps/native/default_icons.6x8x16.bmp b/apps/bitmaps/native/default_icons.6x8x16.bmp
new file mode 100755
index 0000000..601c4f9
--- /dev/null
+++ b/apps/bitmaps/native/default_icons.6x8x16.bmp
Binary files differ
diff --git a/apps/bitmaps/remote_native/SOURCES b/apps/bitmaps/remote_native/SOURCES
index c93dc89..2692179 100644
--- a/apps/bitmaps/remote_native/SOURCES
+++ b/apps/bitmaps/remote_native/SOURCES
@@ -3,9 +3,11 @@
 #if (LCD_REMOTE_DEPTH == 1)
 remote_rockboxlogo.128x42x1.bmp
 remote_usblogo.104x27x1.bmp
+remote_default_icons.6x8x1.bmp
 #elif (LCD_REMOTE_DEPTH == 2)
 remote_rockboxlogo.128x42x2.bmp
 remote_usblogo.104x27x2.bmp
+remote_default_icons.6x8x2.bmp
 #endif
 
 #endif /* HAVE_REMOTE_LCD */
diff --git a/apps/bitmaps/remote_native/remote_default_icons.6x8x1.bmp b/apps/bitmaps/remote_native/remote_default_icons.6x8x1.bmp
new file mode 100644
index 0000000..857b1e1
--- /dev/null
+++ b/apps/bitmaps/remote_native/remote_default_icons.6x8x1.bmp
Binary files differ
diff --git a/apps/bitmaps/remote_native/remote_default_icons.6x8x2.bmp b/apps/bitmaps/remote_native/remote_default_icons.6x8x2.bmp
new file mode 100644
index 0000000..857b1e1
--- /dev/null
+++ b/apps/bitmaps/remote_native/remote_default_icons.6x8x2.bmp
Binary files differ
diff --git a/apps/filetypes.c b/apps/filetypes.c
index ca6578a..f91df19 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include "string.h"
+#include "atoi.h"
 #include <ctype.h>
 
 #include "sprintf.h"
@@ -55,7 +56,7 @@
 #define ROCK_EXTENSION "rock"
 
 struct file_type {
-    ICON_NO_CONST  icon; /* the icon which shall be used for it, NOICON if unknown */
+    int  icon; /* the icon which shall be used for it, NOICON if unknown */
     bool  viewer; /* true if the rock is in viewers, false if in rocks */
     unsigned char  attr; /* FILETYPES_MASK >> 8 */ 
     char* plugin; /* Which plugin to use, NULL if unknown, or builtin */
@@ -73,6 +74,38 @@
 }
 static void read_builtin_types(void);
 static void read_config(char* config_file);
+#ifdef HAVE_LCD_BITMAP
+void read_viewer_theme_file(void)
+{
+    char buffer[MAX_PATH];
+    int fd;
+    char *ext, *icon;
+    int i;
+    snprintf(buffer, MAX_PATH, "%s/%s.icons", ICON_DIR, 
+             global_settings.viewers_icon_file);
+    fd = open(buffer, O_RDONLY);
+    if (fd < 0)
+        return;
+    while (read_line(fd, buffer, MAX_PATH) > 0)
+    {
+        if (!settings_parseline(buffer, &ext, &icon))
+            continue;
+        for (i=0; i<filetype_count; i++)
+        {
+            if (filetypes[i].extension && !strcasecmp(ext, filetypes[i].extension))
+            {
+                if (*icon == '*')
+                    filetypes[i].icon = atoi(icon+1);
+                else if (*icon == '-')
+                    filetypes[i].icon = Icon_NOICON;
+                else filetypes[i].icon = Icon_Last_Themeable + atoi(icon);
+                break;
+            }
+        }
+    }
+    close(fd);
+}
+#endif
 
 void  filetype_init(void)
 {
@@ -80,15 +113,14 @@
     filetypes[0].extension = NULL;
     filetypes[0].plugin = NULL;
     filetypes[0].attr   = 0;
-    filetypes[0].icon   = 
-#ifdef HAVE_LCD_BITMAP
-                            (ICON_NO_CONST)&bitmap_icons_6x8[Icon_Folder];
-#else
-                            (ICON_NO_CONST)Icon_Folder;
-#endif
+    filetypes[0].icon   = Icon_Folder;
+    
     filetype_count = 1;
     read_builtin_types();
     read_config(VIEWERS_CONFIG);
+#ifdef HAVE_LCD_BITMAP
+    read_viewer_theme_file();
+#endif
 }
 
 /* remove all white spaces from string */
@@ -119,12 +151,7 @@
         filetypes[filetype_count].attr   = types[i].tree_attr>>8;
         if (filetypes[filetype_count].attr > heighest_attr)
             heighest_attr = filetypes[filetype_count].attr;
-        filetypes[filetype_count].icon   = 
-#ifdef HAVE_LCD_BITMAP
-                            (ICON_NO_CONST)&bitmap_icons_6x8[types[i].icon];
-#else
-                            (ICON_NO_CONST)types[i].icon;
-#endif
+        filetypes[filetype_count].icon   = types[i].icon;
         filetype_count++;
     }
 }
@@ -133,10 +160,6 @@
 {
     char line[64], *s, *e;
     char extension[8], plugin[32];
-#ifdef HAVE_LCD_BITMAP
-    char icon[ICON_LENGTH];
-    int good_icon;
-#endif
     bool viewer;
     int fd = open(config_file, O_RDONLY);
     if (fd < 0)
@@ -181,44 +204,18 @@
         filetypes[filetype_count].plugin = filetypes_strdup(plugin);
         filetypes[filetype_count].viewer = viewer;
         filetypes[filetype_count].attr = heighest_attr +1;
+        filetypes[filetype_count].icon = Icon_Questionmark;
         heighest_attr++;
         /* get the icon */
 #ifdef  HAVE_LCD_BITMAP
         s = e+1;
-        good_icon = 1;
-        if (strlen(s) == 12)
-        {
-            int i, j;
-            char val[2]; 
-            for (i = 0; good_icon && i < ICON_LENGTH; i++)
-            {
-                for (j=0; good_icon && j<2; j++)
-                {
-                    val[j] = tolower(s[i*2+j]);
-                    if (val[j] >= 'a' && val[j] <= 'f')
-                    {
-                        val[j] = val[j] - 'a' + 10;
-                    }
-                    else if (val[j] >= '0' && val[j] <= '9')
-                    {
-                        val[j] = val[j] - '0';
-                    }
-                    else 
-                        good_icon = 0;
-                }
-                icon[i]=((val[0]<<4) | val[1]);
-            }
-        }
-        if (good_icon)
-        {
-            filetypes[filetype_count].icon = 
-                                (ICON_NO_CONST)buffer_alloc(ICON_LENGTH);
-            memcpy(filetypes[filetype_count].icon, icon, ICON_LENGTH);
-        }
-        else 
-            filetypes[filetype_count].icon = NOICON;
+        if (*s == '*')
+            filetypes[filetype_count].icon = atoi(s+1);
+        else if (*s == '-')
+            filetypes[filetype_count].icon = Icon_NOICON;
+        else filetypes[filetype_count].icon = Icon_Last_Themeable + atoi(s);
 #else
-        filetypes[filetype_count].icon = Icon_Unknown;
+        filetypes[filetype_count].icon = Icon_NOICON;
 #endif
         filetype_count++;
     }
@@ -254,12 +251,12 @@
     return -1;
 }
 
-ICON filetype_get_icon(int attr)
+int filetype_get_icon(int attr)
 {
     int index = find_attr(attr);
     if (index < 0)
-        return NOICON;
-    return (ICON)filetypes[index].icon;
+        return Icon_NOICON;
+    return filetypes[index].icon;
 }
 
 char* filetype_get_plugin(const struct entry* file)
diff --git a/apps/filetypes.h b/apps/filetypes.h
index d2556c1..182cb0d 100644
--- a/apps/filetypes.h
+++ b/apps/filetypes.h
@@ -25,10 +25,11 @@
 /* init the filetypes structs.
    uses audio buffer for storage, so call early in init... */
 void  filetype_init(void);
+void read_viewer_theme_file(void);
 
 /* Return the attribute (TREE_ATTR_*) of the file */
 int filetype_get_attr(const char* file);
-ICON filetype_get_icon(int attr);
+int filetype_get_icon(int attr);
 /* return the plugin filename associated with the file */
 char* filetype_get_plugin(const struct entry* file);
 
diff --git a/apps/gui/color_picker.c b/apps/gui/color_picker.c
index 2d0dba1..1739f3f 100644
--- a/apps/gui/color_picker.c
+++ b/apps/gui/color_picker.c
@@ -31,7 +31,7 @@
 #include "lang.h"
 #include "splash.h"
 #include "action.h"
-#include "icons.h"
+#include "icon.h"
 
 /* structure for color info */
 struct rgb_pick
@@ -220,13 +220,11 @@
                 /* Draw ">    <" around sliders */
                 int top = text_top + (display->char_height -
                                       SELECTOR_HEIGHT) / 2;
-                display->mono_bitmap(bitmap_icons_6x8[Icon_Cursor],
-                                     MARGIN_LEFT, top,
-                                     SELECTOR_WIDTH, SELECTOR_HEIGHT);
-                display->mono_bitmap(bitmap_icons_6x8[Icon_Reverse_Cursor],
-                                     display->width - MARGIN_RIGHT -
-                                     SELECTOR_WIDTH, top, SELECTOR_WIDTH,
-                                     SELECTOR_HEIGHT);
+                screen_put_iconxy(display, MARGIN_LEFT, top, Icon_Cursor);
+                screen_put_iconxy(display, 
+                                  display->width - MARGIN_RIGHT -
+                                          get_icon_width(display->screen_type), 
+                                          top, Icon_Cursor);
             }
 
             if (display->depth >= 16)
diff --git a/apps/gui/icon.c b/apps/gui/icon.c
index ef6f61f..2cb0035 100644
--- a/apps/gui/icon.c
+++ b/apps/gui/icon.c
@@ -7,7 +7,7 @@
  *                     \/            \/     \/    \/            \/
  * $Id$
  *
- * Copyright (C) Robert E. Hak(2002)
+ * Copyright (C) 2007 Jonathan Gordon
  *
  * 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.
@@ -16,42 +16,265 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
-
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "inttypes.h"
 #include "config.h"
 #include "icon.h"
 #include "screen_access.h"
 #include "icons.h"
+#include "settings.h"
+#include "bmp.h"
+#include "filetypes.h"
 
-/* Count in letter positions, NOT pixels */
-void screen_put_iconxy(struct screen * display, int x, int y, ICON icon)
-{
-#ifdef HAVE_LCD_BITMAP
-    int width, height;
-    int xpos, ypos;
-    display->getstringsize((unsigned char *)"M", &width, &height);
-    xpos = x*CURSOR_WIDTH;
-    ypos = y*height + display->getymargin();
-
-    if ( height > CURSOR_HEIGHT )/* center the cursor */
-        ypos += (height - CURSOR_HEIGHT) / 2;
-    if(icon==0)/* Don't display invalid icons */
-        screen_clear_area(display, xpos, ypos, CURSOR_WIDTH, CURSOR_HEIGHT);
-    else
-        display->mono_bitmap(icon, xpos, ypos, CURSOR_WIDTH, CURSOR_HEIGHT);
-#else
-    if(icon==-1)
-        display->putc(x, y, ' ');
-    else
-        display->putc(x, y, icon);
+/* Quick and Dirty hack untill lcd bitmap drawing is fixed */
+#ifdef HAVE_REMOTE_LCD
+#include "lcd-remote.h"
 #endif
+
+
+#include <default_icons.h>
+#ifdef HAVE_REMOTE_LCD
+#include <remote_default_icons.h>
+#endif
+
+#define DEFAULT_VIEWER_BMP          ICON_DIR "/viewers.bmp"
+#define DEFAULT_REMOTE_VIEWER_BMP   ICON_DIR "/remote_viewers.bmp"
+
+/* These should robably be moved to config-<target>.h */
+#define MAX_ICON_HEIGHT 24
+#define MAX_ICON_WIDTH 24
+
+
+/* We dont actually do anything with these pointers,
+   but they need to be grouped like this to save code
+   so storing them as void* is ok. (stops compile warning) */
+static const void * inbuilt_icons[NB_SCREENS] = {
+        (void*)default_icons
+#ifdef HAVE_REMOTE_LCD
+      , (void*)remote_default_icons
+#endif
+};
+
+static const int default_width[NB_SCREENS] = {
+      BMPWIDTH_default_icons
+#ifdef HAVE_REMOTE_LCD
+    , BMPWIDTH_remote_default_icons
+#endif
+};
+
+/* height of whole file */
+static const int default_height[NB_SCREENS] = {
+      BMPHEIGHT_default_icons
+#ifdef HAVE_REMOTE_LCD
+    , BMPHEIGHT_remote_default_icons
+#endif
+};
+
+#define IMG_BUFSIZE (MAX_ICON_HEIGHT * MAX_ICON_WIDTH * \
+                     Icon_Last_Themeable *LCD_DEPTH/8)
+static unsigned char icon_buffer[IMG_BUFSIZE][NB_SCREENS];
+static bool custom_icons_loaded[NB_SCREENS] = {false};
+static struct bitmap user_iconset[NB_SCREENS];
+
+static unsigned char viewer_icon_buffer[IMG_BUFSIZE][NB_SCREENS];
+static bool viewer_icons_loaded[NB_SCREENS] = {false};
+static struct bitmap viewer_iconset[NB_SCREENS];
+
+
+#define ICON_HEIGHT(screen) (!custom_icons_loaded[screen]?       \
+                             default_height[screen] :   \
+                             user_iconset[screen].height) \
+                            / Icon_Last_Themeable
+                            
+#define ICON_WIDTH(screen)  (!custom_icons_loaded[screen]?       \
+                             default_width[screen] :   \
+                             user_iconset[screen].width)
+                            
+/* x,y in letters, not pixles */
+void screen_put_icon(struct screen * display, 
+                       int x, int y, enum themable_icons icon)
+{
+    screen_put_icon_with_offset(display, x, y, 0, 0, icon);
+}
+
+void screen_put_icon_with_offset(struct screen * display, 
+                       int x, int y, int off_x, int off_y,
+                       enum themable_icons icon)
+{
+    int xpos, ypos;
+    int width, height;
+    int screen = display->screen_type;
+    display->getstringsize((unsigned char *)"M", &width, &height);
+    xpos = x*ICON_WIDTH(screen) + off_x;
+    ypos = y*height + display->getymargin() + off_y;
+
+    if ( height > ICON_HEIGHT(screen) )/* center the cursor */
+        ypos += (height - ICON_HEIGHT(screen)) / 2;
+    screen_put_iconxy(display, xpos, ypos, icon);
+}
+
+/* x,y in pixels */
+typedef void (*lcd_draw_func)(const fb_data *src, int src_x, int src_y,
+                      int stride, int x, int y, int width, int height);
+void screen_put_iconxy(struct screen * display, 
+                       int xpos, int ypos, enum themable_icons icon)
+{
+    fb_data *data;
+    int screen = display->screen_type;
+    lcd_draw_func draw_func = NULL;
+    
+    if (icon == Icon_NOICON)
+    {
+        screen_clear_area(display, xpos, ypos,
+                          ICON_WIDTH(screen), ICON_HEIGHT(screen));
+        return;
+    }
+    else if (icon >= Icon_Last_Themeable)
+    {
+        icon -= Icon_Last_Themeable;
+        if (!viewer_icons_loaded[screen] || 
+           (icon*ICON_HEIGHT(screen) > viewer_iconset[screen].height))
+        {
+            screen_clear_area(display, xpos, ypos,
+                          ICON_WIDTH(screen), ICON_HEIGHT(screen));
+            return;
+        }
+        data = (fb_data *)viewer_iconset[screen].data;
+    }
+    else if (custom_icons_loaded[screen])
+    {
+        data = (fb_data *)user_iconset[screen].data;
+    }
+    else
+    {
+        data = (fb_data *)inbuilt_icons[screen];
+    }
+    /* add some left padding to the icons if they are on the edge */
+    if (xpos == 0)
+        xpos++;
+    
+#ifdef HAVE_REMOTE_LCD
+    if (display->screen_type == SCREEN_REMOTE)
+    {
+        /* Quick and Dirty hack untill lcd bitmap drawing is fixed */
+        draw_func = (lcd_draw_func)lcd_remote_bitmap_part;
+    }
+    else
+#endif
+#if LCD_DEPTH == 16
+        draw_func = display->transparent_bitmap_part;
+#else /* LCD_DEPTH < 16 */
+        draw_func = display->bitmap_part;
+#endif /* LCD_DEPTH == 16 */
+    
+    draw_func(  (const fb_data *)data,
+                0, ICON_HEIGHT(screen)*icon, 
+                ICON_WIDTH(screen), xpos, ypos, 
+                ICON_WIDTH(screen), ICON_HEIGHT(screen));
 }
 
 void screen_put_cursorxy(struct screen * display, int x, int y, bool on)
 {
 #ifdef HAVE_LCD_BITMAP
-    screen_put_iconxy(display, x, y, on?bitmap_icons_6x8[Icon_Cursor]:0);
+    screen_put_icon(display, x, y, on?Icon_Cursor:0);
 #else
-    screen_put_iconxy(display, x, y, on?CURSOR_CHAR:-1);
+    screen_put_icon(display, x, y, on?CURSOR_CHAR:-1);
 #endif
 
 }
+enum Iconset {
+    Iconset_Mainscreen,
+    Iconset_Mainscreen_viewers,
+#ifdef HAVE_REMOTE_LCD
+    Iconset_Remotescreen,
+    Iconset_Remotescreen_viewers,
+#endif
+};
+
+static void load_icons(const char* filename, enum Iconset iconset)
+{
+    int size_read;
+    bool *loaded_ok = NULL;
+    struct bitmap *bmp = NULL;
+    
+    switch (iconset)
+    {
+        case Iconset_Mainscreen:
+            loaded_ok = &custom_icons_loaded[SCREEN_MAIN];
+            bmp = &user_iconset[SCREEN_MAIN];
+            bmp->data = icon_buffer[SCREEN_MAIN];
+            break;
+        case Iconset_Mainscreen_viewers:
+            loaded_ok = &viewer_icons_loaded[SCREEN_MAIN];
+            bmp = &viewer_iconset[SCREEN_MAIN];
+            bmp->data = viewer_icon_buffer[SCREEN_MAIN];
+            break;
+#ifdef HAVE_REMOTE_LCD
+        case Iconset_Remotescreen:
+            loaded_ok = &custom_icons_loaded[SCREEN_MAIN];
+            bmp = &user_iconset[SCREEN_MAIN];
+            bmp->data = icon_buffer[SCREEN_MAIN];
+            break;
+        case Iconset_Remotescreen_viewers:
+            loaded_ok = &viewer_icons_loaded[SCREEN_REMOTE];
+            bmp = &viewer_iconset[SCREEN_REMOTE];
+            bmp->data = viewer_icon_buffer[SCREEN_REMOTE];
+            break;
+#endif
+    }
+    
+    *loaded_ok = false;
+    if (filename != NULL)
+    {
+        size_read = read_bmp_file((char*)filename, bmp, IMG_BUFSIZE,
+                                  FORMAT_NATIVE | FORMAT_DITHER);
+        if (size_read > 0)
+        {
+            *loaded_ok = true;
+        }
+    }
+}
+
+
+void icons_init(void)
+{
+    char path[MAX_PATH];
+    if (global_settings.icon_file[0])
+    {
+        snprintf(path, MAX_PATH, "%s/%s.bmp",
+                 ICON_DIR, global_settings.icon_file);
+        load_icons(path, Iconset_Mainscreen);
+    }
+    if (global_settings.viewers_icon_file[0])
+    {
+        snprintf(path, MAX_PATH, "%s/%s.bmp",
+                 ICON_DIR, global_settings.viewers_icon_file);
+        load_icons(path, Iconset_Mainscreen_viewers);
+        read_viewer_theme_file();
+    }
+    else
+        load_icons(DEFAULT_VIEWER_BMP, Iconset_Mainscreen_viewers);
+#ifdef HAVE_REMOTE_LCD
+    if (global_settings.remote_icon_file[0])
+    {
+        snprintf(path, MAX_PATH, "%s/%s.bmp",
+                 ICON_DIR, global_settings.remote_icon_file);
+        load_icons(path, Iconset_Remotescreen);
+    }
+    if (global_settings.remote_viewers_icon_file[0])
+    {
+        snprintf(path, MAX_PATH, "%s/%s.bmp",
+                 ICON_DIR, global_settings.remote_viewers_icon_file);
+        load_icons(path, Iconset_Remotescreen_viewers);
+    }
+    else
+        load_icons(DEFAULT_REMOTE_VIEWER_BMP, Iconset_Mainscreen_viewers);
+#endif
+}
+
+int get_icon_width(enum screen_type screen_type)
+{
+    return ICON_WIDTH(screen_type);
+}
diff --git a/apps/gui/icon.h b/apps/gui/icon.h
index c717bbc..fa69190 100644
--- a/apps/gui/icon.h
+++ b/apps/gui/icon.h
@@ -24,19 +24,51 @@
  * char-based displays and bitmap displays */
 #ifdef HAVE_LCD_BITMAP
 typedef const unsigned char * ICON;
-typedef unsigned char * ICON_NO_CONST;
-#define NOICON NULL
+#define NOICON Icon_NOICON
 #else
 typedef long ICON;
-#define ICON_NO_CONST ICON
-#define NOICON -1
+#define NOICON Icon_NOICON
 #endif
 
-#define Icon_NOICON -1
-
-#define CURSOR_CHAR 0xe10c
-#define CURSOR_WIDTH 6
-#define CURSOR_HEIGHT 8
+#define FORCE_INBUILT_ICON 0x80000000
+/* Don't #ifdef icon values, or we wont be able to use the same 
+   cmp for every target. */
+enum themable_icons {
+    Icon_NOICON = -1, /* Dont put this in a .bmp */
+    Icon_Audio,
+    Icon_Folder,
+    Icon_Playlist,
+    Icon_Cursor,
+    Icon_Wps,
+    Icon_Firmware,
+    Icon_Font,
+    Icon_Language,
+    Icon_Config,
+    Icon_Plugin,
+    Icon_Bookmark,
+    Icon_Preset,
+    Icon_Queued,
+    Icon_Moving,
+    Icon_Keyboard,
+    Icon_Reverse_Cursor,
+    Icon_Questionmark,
+    Icon_Menu_setting,
+    Icon_Menu_functioncall,
+    Icon_Submenu,
+    Icon_Submenu_Entered,
+    Icon_Recording,
+    Icon_Voice,
+    Icon_General_settings_menu,
+    Icon_System_menu,
+    Icon_Playback_menu,
+    Icon_Display_menu,
+    Icon_Remote_Display_menu,
+    Icon_Radio_screen,
+    Icon_file_view_menu,
+    Icon_EQ,
+    Icon_Rockbox,
+    Icon_Last_Themeable,
+};
 
 /*
  * Draws a cursor at a given position, if th
@@ -49,12 +81,36 @@
 /*
  * Put an icon on a screen at a given position
  * (the position is given in characters)
- * If the given icon is null (HAVE_LCD_BITMAP) or -1 otherwise, the icon
+ * If the given icon is Icon_blank, the icon
  * at the given position will be erased
  * - screen : the screen where we put our icon
- * - x, y : the position, in character, not in pixel !!
+ * - x, y : the position, pixel value !!
  * - icon : the icon to put
  */
-extern void screen_put_iconxy(struct screen * screen, int x, int y, ICON icon);
+extern void screen_put_iconxy(struct screen * screen,
+                              int x, int y, enum themable_icons icon);
+#ifdef HAVE_LCD_CHARCELLS
+# define screen_put_icon(s, x, y, i) screen_put_iconxy(s, x, y, i)
+# define screen_put_icon_with_offset(s, x, y, w, h, i) screen_put_icon(s, x, y, i)
+#else
+/* For both of these, the icon will be placed in the center of the rectangle */
+/* as above, but x,y are letter position, NOT PIXEL */
+extern void screen_put_icon(struct screen * screen,
+                              int x, int y, enum themable_icons icon);
+/* as above (x,y are letter pos), but with a pxiel offset for both */
+extern void screen_put_icon_with_offset(struct screen * display, 
+                       int x, int y, int off_x, int off_y,
+                       enum themable_icons icon);
+#endif
+
+void icons_init(void);
+
+
+#ifdef HAVE_LCD_CHARCELLS
+# define CURSOR_CHAR 0xe10c
+# define get_icon_width(a) 6
+#else
+int get_icon_width(enum screen_type screen_type);
+#endif
 
 #endif /*_GUI_ICON_H_*/
diff --git a/apps/gui/list.c b/apps/gui/list.c
index e3b0d6a..c93210e 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -92,7 +92,7 @@
     gui_list->selected_size=selected_size;
     gui_list->title = NULL;
     gui_list->title_width = 0;
-    gui_list->title_icon = NOICON;
+    gui_list->title_icon = Icon_NOICON;
 
     gui_list->last_displayed_selected_item = -1 ;
     gui_list->last_displayed_start_item = -1 ;
@@ -230,8 +230,6 @@
 static void gui_list_draw_smart(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;
@@ -288,9 +286,9 @@
     {
         if (gui_list->title_icon != NOICON && draw_icons)
         {
-            screen_put_iconxy(display, 0, 0, gui_list->title_icon);
+            screen_put_icon(display, 0, 0, gui_list->title_icon);
 #ifdef HAVE_LCD_BITMAP
-            text_pos = 8; /* pixels */
+            text_pos = get_icon_width(display->screen_type)+2; /* pixels */
 #else
             text_pos = 1; /* chars */
 #endif
@@ -327,17 +325,13 @@
     if(draw_scrollbar || SHOW_LIST_TITLE) /* indent if there's
                                              a title */
     {
-        cursor_pos++;
-        icon_pos++;
         text_pos += SCROLLBAR_WIDTH;
     }
-    if(!draw_cursor)
-        icon_pos--;
-    else
-        text_pos += CURSOR_WIDTH;
+    if(draw_cursor)
+        text_pos += get_icon_width(display->screen_type) + 2;
 
     if(draw_icons)
-        text_pos += 8;
+        text_pos += get_icon_width(display->screen_type) + 2;
 #else
     draw_cursor = true;
     if(draw_icons)
@@ -413,7 +407,12 @@
 #endif
 
             if (draw_cursor)
-                screen_put_cursorxy(display, cursor_pos, i, true);
+            {
+                screen_put_icon_with_offset(display, 0, i,
+                                           (draw_scrollbar || SHOW_LIST_TITLE)?
+                                                   SCROLLBAR_WIDTH: 0,
+                                           0, Icon_Cursor);
+            }
         }
         else
         {/* normal item */
@@ -437,12 +436,19 @@
         /* Icons display */
         if(draw_icons)
         {
-            ICON icon;
-            gui_list->callback_get_item_icon(current_item,
-                                             gui_list->data,
-                                             &icon);
-            if(icon)
-                screen_put_iconxy(display, icon_pos, i, icon);
+            enum themable_icons icon;
+            icon = gui_list->callback_get_item_icon(current_item, gui_list->data);
+            if(icon > Icon_NOICON)
+            {
+#ifdef HAVE_LCD_BITMAP
+                int x = draw_cursor?1:0;
+                int x_off = (draw_scrollbar || SHOW_LIST_TITLE) ? SCROLLBAR_WIDTH: 0;
+                screen_put_icon_with_offset(display, x, i,
+                                           x_off, 0, icon);
+#else
+                screen_put_icon(display, 1, i, icon);
+#endif
+            }
         }
     }
 
@@ -737,7 +743,8 @@
  * Set the title and title icon of the list. Setting title to NULL disables
  * both the title and icon. Use NOICON if there is no icon.
  */
-static void gui_list_set_title(struct gui_list * gui_list, char * title, ICON icon)
+static void gui_list_set_title(struct gui_list * gui_list, 
+                               char * title, enum themable_icons icon)
 {
     gui_list->title = title;
     gui_list->title_icon = icon;
@@ -870,7 +877,7 @@
 }
 
 void gui_synclist_set_title(struct gui_synclist * lists,
-                            char * title, ICON icon)
+                            char * title, enum themable_icons icon)
 {
     int i;
     FOR_NB_SCREENS(i)
diff --git a/apps/gui/list.h b/apps/gui/list.h
index bd43edf..283676d 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -49,9 +49,7 @@
  *           the icon after the function returns.
  * Note : we use the ICON type because the real type depends of the plateform
  */
-typedef void list_get_icon(int selected_item,
-                           void * data,
-                           ICON * icon);
+typedef enum themable_icons list_get_icon(int selected_item, void * data);
 /*
  * Text callback
  *  - selected_item : an integer that tells the number of the item to display
@@ -101,7 +99,7 @@
     /* The optional title, set to NULL for none */
     char * title;
     /* Optional title icon */
-    ICON title_icon;
+    enum themable_icons title_icon;
 };
 
 /*
@@ -190,7 +188,7 @@
 extern void gui_synclist_limit_scroll(struct gui_synclist * lists, bool scroll);
 extern void gui_synclist_flash(struct gui_synclist * lists);
 extern void gui_synclist_set_title(struct gui_synclist * lists, char * title,
-                                   ICON icon);
+                                   int icon);
 
 /*
  * Do the action implied by the given button,
diff --git a/apps/main.c b/apps/main.c
index 3145f36..7590382 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -70,6 +70,7 @@
 #include "splash.h"
 #include "eeprom_settings.h"
 #include "scrobbler.h"
+#include "icon.h"
 
 #if (CONFIG_CODEC == SWCODEC)
 #include "playback.h"
@@ -267,6 +268,7 @@
     sleep(HZ/2);
     tree_init();
     filetype_init();
+    icons_init();
     playlist_init();
 
 #if CONFIG_CODEC != SWCODEC
@@ -501,6 +503,7 @@
     playlist_init();
     tree_init();
     filetype_init();
+    icons_init();
     scrobbler_init();
     cuesheet_init();
 
diff --git a/apps/menu.c b/apps/menu.c
index 71a066f..e840432 100644
--- a/apps/menu.c
+++ b/apps/menu.c
@@ -136,7 +136,7 @@
     return P2STR(menu->callback_and_desc->desc);
 }
 #ifdef HAVE_LCD_BITMAP
-static void menu_get_icon(int selected_item, void * data, ICON * icon)
+static int menu_get_icon(int selected_item, void * data)
 {
     const struct menu_item_ex *menu = (const struct menu_item_ex *)data;
     int menu_icon = Icon_NOICON;
@@ -144,8 +144,7 @@
     
     if ((menu->flags&MENU_TYPE_MASK) == MT_RETURN_ID)
     {
-        *icon = bitmap_icons_6x8[Icon_Menu_functioncall];
-        return;
+        return Icon_Menu_functioncall;
     }
     menu = menu->submenus[selected_item];
     if (menu->flags&MENU_HAS_DESC)
@@ -153,28 +152,24 @@
     else if (menu->flags&MENU_DYNAMIC_DESC)
         menu_icon = menu->menu_get_name_and_icon->icon_id;
     
-    switch (menu->flags&MENU_TYPE_MASK)
+    if (menu_icon == Icon_NOICON)
     {
-        case MT_SETTING:
-        case MT_SETTING_W_TEXT:
-            *icon = bitmap_icons_6x8[Icon_Menu_setting];
-            break;
-        case MT_MENU:
-            if (menu_icon == Icon_NOICON)
-                *icon = bitmap_icons_6x8[Icon_Submenu];
-            else
-                *icon = bitmap_icons_6x8[menu_icon];
-            break;
-        case MT_FUNCTION_CALL:
-        case MT_RETURN_VALUE:
-            if (menu_icon == Icon_NOICON)
-                *icon = bitmap_icons_6x8[Icon_Menu_functioncall];
-            else 
-                *icon = bitmap_icons_6x8[menu_icon];
-            break;
-        default:
-            *icon = NOICON;
+        switch (menu->flags&MENU_TYPE_MASK)
+        {
+            case MT_SETTING:
+            case MT_SETTING_W_TEXT:
+                menu_icon = Icon_Menu_setting;
+                break;
+            case MT_MENU:
+                    menu_icon = Icon_Submenu;
+                break;
+            case MT_FUNCTION_CALL:
+            case MT_RETURN_VALUE:
+                menu_icon = Icon_Menu_functioncall;
+                break;
+        }
     }
+    return menu_icon;
 }
 #endif
 
@@ -184,7 +179,7 @@
     int i, count = MENU_GET_COUNT(menu->flags);
     int type = (menu->flags&MENU_TYPE_MASK);
     menu_callback_type menu_callback = NULL;
-    ICON icon = NOICON;
+    int icon;
     current_subitems_count = 0;
 
     if (type == MT_OLD_MENU)
@@ -220,9 +215,9 @@
     gui_synclist_init(lists,get_menu_item_name,(void*)menu,false,1);
 #ifdef HAVE_LCD_BITMAP
     if (menu->callback_and_desc->icon_id == Icon_NOICON)
-        icon = bitmap_icons_6x8[Icon_Submenu_Entered];
+        icon = Icon_Submenu_Entered;
     else
-        icon = bitmap_icons_6x8[menu->callback_and_desc->icon_id];
+        icon = menu->callback_and_desc->icon_id;
     gui_synclist_set_title(lists, P2STR(menu->callback_and_desc->desc), icon);  
     gui_synclist_set_icon_callback(lists, menu_get_icon);
 #else
@@ -704,10 +699,10 @@
 }
 
 #ifdef HAVE_LCD_BITMAP
-static void oldmenu_get_icon(int selected_item, void * data, ICON * icon)
+static int oldmenu_get_icon(int selected_item, void * data)
 {
     (void)data; (void)selected_item;
-    *icon = bitmap_icons_6x8[Icon_Menu_functioncall];
+    return Icon_Menu_functioncall;
 }
 #endif
 
@@ -721,7 +716,7 @@
     gui_synclist_limit_scroll(lists, true);
 #ifdef HAVE_LCD_BITMAP
     gui_synclist_set_title(lists, menus[menu->value].title,
-                           bitmap_icons_6x8[Icon_Submenu_Entered]);
+                           Icon_Submenu_Entered);
     gui_synclist_set_icon_callback(lists, oldmenu_get_icon);
 #endif
     gui_synclist_select_item(lists, selected);
diff --git a/apps/player/icons.c b/apps/player/icons.c
index 3f9b7c1..6717eb1 100644
--- a/apps/player/icons.c
+++ b/apps/player/icons.c
@@ -7,7 +7,7 @@
  *                     \/            \/     \/    \/            \/
  * $Id$
  *
- * Copyright (C) 2002 Justin Heiner
+ * Copyright (C) 2007 Jonathan Gordon
  *
  * 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.
@@ -17,8 +17,93 @@
  *
  ****************************************************************************/
 #include "lcd.h"
-#include "icons.h"
+#include "icon.h"
 
 #ifdef HAVE_LCD_CHARCELLS
+/* For the moment, charcell cant load custom maps... */
+
+enum old_values{
+    old_Icon_Queued = 'Q',
+    old_Icon_Moving = 'M',
+    old_Icon_Unknown = 0xe100,
+    old_Icon_Bookmark,
+    old_Icon_Plugin,
+    old_Icon_Folder,
+    old_Icon_Firmware,
+    old_Icon_Language,
+    old_Icon_Audio,
+    old_Icon_Wps,
+    old_Icon_Playlist,
+    old_Icon_Text,
+    old_Icon_Config,
+};
+
+static const long icon_unknown = old_Icon_Unknown;
+static const long icons[Icon_Last_Themeable] = {
+    [0 ... Icon_Last_Themeable-1] = 0,
+    
+    [Icon_Audio] = old_Icon_Audio,
+    [Icon_Folder] = old_Icon_Folder,
+    [Icon_Playlist] = old_Icon_Playlist,
+    [Icon_Cursor] = CURSOR_CHAR,
+    [Icon_Wps] = old_Icon_Wps,
+    [Icon_Firmware] = old_Icon_Firmware,
+    [Icon_Language] = old_Icon_Language,
+    [Icon_Config] = old_Icon_Config,
+    [Icon_Plugin] = old_Icon_Plugin,
+    [Icon_Bookmark] = old_Icon_Bookmark,
+    [Icon_Queued] = 'Q',
+    [Icon_Moving] = 'M',
+    
+    /*
+    [Icon_Keyboard] = ,
+    [Icon_Font] = ,
+    [Icon_Preset] = ,
+    [Icon_Reverse_Cursor] = ,
+    [Icon_Questionmark] = ,
+    [Icon_Menu_setting] = ,
+    [Icon_Menu_functioncall] = ,
+    [Icon_Submenu] = ,
+    [Icon_Submenu_Entered] = ,
+    [Icon_Recording] = ,
+    [Icon_Voice] = ,
+    [Icon_General_settings_menu] = ,
+    [Icon_System_menu] = ,
+    [Icon_Playback_menu] = ,
+    [Icon_Display_menu] = ,
+    [Icon_Remote_Display_menu] = ,
+    [Icon_Radio_screen] = ,
+    [Icon_file_view_menu] = ,
+    [Icon_EQ] = ,
+    [Icon_Rockbox] = ,
+    */
+};
+
+/* as above, but x,y are letter position, NOT PIXEL */
+extern void screen_put_iconxy(struct screen * screen,
+                            int x, int y, enum themable_icons icon)
+{
+    if (icon == -1)
+        screen->putc(x, y, icon_unknown);
+    else if ((icon==Icon_NOICON) && (icons[icon]!=0))
+        screen->putc(x, y, ' ');
+    else
+        screen->putc(x, y, icons[icon]);
+}
+
+void screen_put_cursorxy(struct screen * display, int x, int y, bool on)
+{
+    screen_put_iconxy(display, x, y, on?Icon_Cursor:-1);
+
+}
+
+void icons_init(void)
+{
+}
+
+
+
+
+
 
 #endif
diff --git a/apps/player/icons.h b/apps/player/icons.h
index 5df94b0..48dfdfc 100644
--- a/apps/player/icons.h
+++ b/apps/player/icons.h
@@ -25,50 +25,5 @@
  * Icons of size 5x7 pixels for the Player LCD
  */
 
-#ifdef HAVE_LCD_CHARCELLS
-
-enum {
-    Icon_Queued = 'Q',
-    Icon_Moving = 'M',
-    Icon_Unknown = 0xe100,
-    Icon_Bookmark,
-    Icon_Plugin,
-    Icon_Folder,
-    Icon_Firmware,
-    Icon_Language,
-    Icon_Audio,
-    Icon_Wps,
-    Icon_Playlist,
-    Icon_Text,
-    Icon_Config,
-};
-
-/* put icons from the 6x8 enum here if the player
-   doesnt have an icon for it */
-enum unused_but_needed {
-    Icon_Cursor,
-    Icon_Font,
-    Icon_Preset,
-    Icon_Keyboard,
-    Icon_Reverse_Cursor,
-    Icon_Questionmark,
-    Icon_Menu_setting,
-    Icon_Menu_functioncall,
-    Icon_Submenu,
-    Icon_Submenu_Entered,
-    Icon_Recording,
-    Icon_Voice,
-    Icon_General_settings_menu,
-    Icon_System_menu,
-    Icon_Playback_menu,
-    Icon_Display_menu,
-    Icon_Remote_Display_menu,
-    Icon_Radio_screen,
-    Icon_file_view_menu,
-    Icon_EQ,
-    Icon_Rockbox,
-    Icon6x8Last,
-};
-#endif
 
 #endif /* _ICONS_H_ */
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c
index 7d6bf2d..b5f72cb 100644
--- a/apps/playlist_viewer.c
+++ b/apps/playlist_viewer.c
@@ -570,7 +570,7 @@
 }
 
 
-static void playlist_callback_icons(int selected_item, void *data, ICON * icon)
+static int playlist_callback_icons(int selected_item, void *data)
 {
     struct playlist_viewer * local_viewer=(struct playlist_viewer *)data;
     struct playlist_entry *track=
@@ -578,36 +578,20 @@
     if (track->index == local_viewer->current_playing_track)
     {
         /* Current playing track */
-#ifdef HAVE_LCD_BITMAP
-        *icon=bitmap_icons_6x8[Icon_Audio];
-#else
-        *icon=Icon_Audio;
-#endif
+        return Icon_Audio;
     }
     else if (track->index == local_viewer->move_track)
     {
         /* Track we are moving */
-#ifdef HAVE_LCD_BITMAP
-        *icon=bitmap_icons_6x8[Icon_Moving];
-#else
-        *icon=Icon_Moving;
-#endif
+        return Icon_Moving;
     }
     else if (track->queued)
     {
         /* Queued track */
-#ifdef HAVE_LCD_BITMAP
-        *icon=bitmap_icons_6x8[Icon_Queued];
-#else
-        *icon=Icon_Queued;
-#endif
+        return Icon_Queued;
     }
     else
-#ifdef HAVE_LCD_BITMAP
-        *icon=0;
-#else
-        *icon=-1;
-#endif
+        return Icon_NOICON;
 }
 
 /* Main viewer function.  Filename identifies playlist to be viewed.  If NULL,
@@ -627,13 +611,7 @@
                   &playlist_callback_icons:NULL);
     gui_synclist_set_nb_items(&playlist_lists, viewer.num_tracks);
     gui_synclist_select_item(&playlist_lists, viewer.selected_track);
-    gui_synclist_set_title(&playlist_lists, str(LANG_PLAYLIST_MENU), 
-#ifdef HAVE_LCD_BITMAP
-                            bitmap_icons_6x8[Icon_Playlist]
-#else
-                            NOICON
-#endif
-                          );
+    gui_synclist_set_title(&playlist_lists, str(LANG_PLAYLIST_MENU), Icon_Playlist);
     gui_synclist_draw(&playlist_lists);
     action_signalscreenchange();
     while (!exit)
@@ -800,17 +778,6 @@
     return(buffer);
 }
 
-
-static void playlist_search_callback_icons(int selected_item, void * data, ICON * icon)
-{
-    (void)selected_item;
-    (void)data;
-#ifdef HAVE_LCD_BITMAP
-        *icon=0;
-#else
-        *icon=-1;
-#endif
-}
 bool search_playlist(void)
 {
     char search_str[32] = "";
@@ -851,9 +818,7 @@
     backlight_on();
     gui_synclist_init(&playlist_lists, playlist_search_callback_name,
                                 found_indicies, false, 1);
-    gui_synclist_set_icon_callback(&playlist_lists,
-                  global_settings.playlist_viewer_icons?
-                  &playlist_search_callback_icons:NULL);
+    gui_synclist_set_icon_callback(&playlist_lists, NULL);
     gui_synclist_set_nb_items(&playlist_lists, found_indicies_count);
     gui_synclist_select_item(&playlist_lists, 0);
     gui_synclist_draw(&playlist_lists);
diff --git a/apps/plugin.h b/apps/plugin.h
index 0c2d050..f118260 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -274,7 +274,7 @@
     void (*gui_synclist_flash)(struct gui_synclist * lists);
     unsigned (*gui_synclist_do_button)(struct gui_synclist * lists,
                                          unsigned button,enum list_wrap wrap);
-    void (*gui_synclist_set_title)(struct gui_synclist *lists, char* title, ICON icon);
+    void (*gui_synclist_set_title)(struct gui_synclist *lists, char* title, int icon);
 
     /* button */
     long (*button_get)(bool block);
diff --git a/apps/plugins/bitmaps/viewer_defaults/remote_viewers.6x8x1.bmp b/apps/plugins/bitmaps/viewer_defaults/remote_viewers.6x8x1.bmp
new file mode 100644
index 0000000..d7d8966
--- /dev/null
+++ b/apps/plugins/bitmaps/viewer_defaults/remote_viewers.6x8x1.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/viewer_defaults/remote_viewers.6x8x2.bmp b/apps/plugins/bitmaps/viewer_defaults/remote_viewers.6x8x2.bmp
new file mode 100644
index 0000000..d7d8966
--- /dev/null
+++ b/apps/plugins/bitmaps/viewer_defaults/remote_viewers.6x8x2.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/viewer_defaults/viewers.6x8x1.bmp b/apps/plugins/bitmaps/viewer_defaults/viewers.6x8x1.bmp
new file mode 100644
index 0000000..d7d8966
--- /dev/null
+++ b/apps/plugins/bitmaps/viewer_defaults/viewers.6x8x1.bmp
Binary files differ
diff --git a/apps/plugins/bitmaps/viewer_defaults/viewers.6x8x16.bmp b/apps/plugins/bitmaps/viewer_defaults/viewers.6x8x16.bmp
new file mode 100644
index 0000000..1760e66
--- /dev/null
+++ b/apps/plugins/bitmaps/viewer_defaults/viewers.6x8x16.bmp
Binary files differ
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config
index 67a39b8..d53fb23 100644
--- a/apps/plugins/viewers.config
+++ b/apps/plugins/viewers.config
@@ -1,32 +1,32 @@
-ch8,viewers/chip8,70 70 7f 7f 70 70
-txt,viewers/viewer,55 55 55 55 55 55
-nfo,viewers/viewer,55 55 55 55 55 55
-txt,rocks/text_editor, 55 55 55 55 55 55
-jpg,viewers/jpeg,18 24 3C 3C 24 18
-jpe,viewers/jpeg,18 24 3C 3C 24 18
-jpeg,viewers/jpeg,18 24 3C 3C 24 18
-ucl,viewers/rockbox_flash,2A 7F 41 41 7F 2A
-rvf,viewers/video,5D 7F 5D 7F 5D 7F
-mp3,viewers/vbrfix,10 08 58 38 04 02
-m3u,viewers/search,00 00 00 00 00 00
-txt,viewers/sort,00 00 00 00 00 00
-gb,viewers/rockboy,0C 2A 59 7A 2E 0C
-gbc,viewers/rockboy,0C 2A 59 7A 2E 0C
-m3u,viewers/iriverify,00 00 00 00 00 00
-mid,viewers/midiplay,20 70 70 3F 00 00 
-rmi,viewers/midiplay,20 70 70 3F 00 00
-rsp,viewers/searchengine,0e 11 11 31 7e 60
-ss,rocks/sudoku,55 55 55 55 55 55
-wav,viewers/wav2wv,00 00 00 00 00 00
-wav,viewers/mp3_encoder,00 00 00 00 00 00
-wav,viewers/wavplay,60 7F 05 35 3F 00
-wav,viewers/wavview,18 7E 3C FF 7E 18
-bmp,rocks/rockpaint,01 10 01 10 01 10
-mpg,viewers/mpegplayer,5D 7F 5D 7F 5D 7F
-mpeg,viewers/mpegplayer,5D 7F 5D 7F 5D 7F
-iriver,viewers/iriver_flash,2A 7F 41 41 7F 2A
-tap,viewers/zxbox,66 52 4A 66 52 4A
-sna,viewers/zxbox,66 52 4A 66 52 4A
-tzx,viewers/zxbox,66 52 4A 66 52 4A
-z80,viewers/zxbox,66 52 4A 66 52 4A
-zzz,viewers/properties,00 00 00 00 00 00
+ch8,viewers/chip8,0
+txt,viewers/viewer,1
+nfo,viewers/viewer,1
+txt,rocks/text_editor,2
+jpg,viewers/jpeg,2
+jpe,viewers/jpeg,2
+jpeg,viewers/jpeg,2
+ucl,viewers/rockbox_flash,3
+rvf,viewers/video,4
+mp3,viewers/vbrfix,5
+m3u,viewers/search,-
+txt,viewers/sort,-
+gb,viewers/rockboy,6
+gbc,viewers/rockboy,6
+m3u,viewers/iriverify,-
+mid,viewers/midiplay,7 
+rmi,viewers/midiplay,7
+rsp,viewers/searchengine,8
+ss,rocks/sudoku,1
+wav,viewers/wav2wv,-
+wav,viewers/mp3_encoder,-
+wav,viewers/wavplay,*0
+wav,viewers/wavview,10
+bmp,rocks/rockpaint,11
+mpg,viewers/mpegplayer,4
+mpeg,viewers/mpegplayer,4
+iriver,viewers/iriver_flash,3
+tap,viewers/zxbox,12
+sna,viewers/zxbox,12
+tzx,viewers/zxbox,12
+z80,viewers/zxbox,12
+zzz,viewers/properties,-
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c
index b33c0a3..352b2f4 100644
--- a/apps/recorder/bmp.c
+++ b/apps/recorder/bmp.c
@@ -215,13 +215,6 @@
     }
 
     height = readlong(&bmph.height);
-    if (height > LCD_HEIGHT) {
-        DEBUGF("read_bmp_file: Bitmap too high (%d pixels, max is %d)\n",
-                        height, LCD_HEIGHT);
-        close(fd);
-        return -5;
-    }
-
     depth = readshort(&bmph.bit_count);
     padded_width = ((width * depth + 31) >> 3) & ~3;  /* 4-byte boundary aligned */
 
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c
index ccb42d5..007cd07 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -44,44 +44,6 @@
 #endif
 };
 
-const unsigned char bitmap_icons_6x8[][6] =
-{
-    { 0x60, 0x7f, 0x03, 0x33, 0x3f, 0x00 }, /* Musical note */
-    { 0x7e, 0x41, 0x41, 0x42, 0x7e, 0x00 }, /* Folder */
-    { 0x55, 0x00, 0x55, 0x55, 0x55, 0x55 }, /* Playlist */
-    { 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00 }, /* Cursor / Marker */
-    { 0x58, 0x5f, 0x42, 0x50, 0x55, 0x55 }, /* WPS file */
-    { 0x63, 0x7f, 0x3a, 0x7f, 0x63, 0x00 }, /* Mod or ajz file */
-    { 0x60, 0x70, 0x38, 0x2c, 0x7e, 0x7e }, /* Font file */
-    { 0x3e, 0x2a, 0x3e, 0x2a, 0x2a, 0x3e }, /* Language file */
-    { 0x4e, 0x51, 0x51, 0x40, 0x55, 0x55 }, /* Config file */
-    { 0x0a, 0x0a, 0x5f, 0x4e, 0x24, 0x18 }, /* Plugin file */
-    { 0x7f, 0x41, 0x4f, 0x4a, 0x4c, 0x78 }, /* Bookmark file */
-    { 0x5f, 0x45, 0x5b, 0x40, 0x55, 0x55 }, /* Preset file */
-    { 0x77, 0x55, 0x55, 0x55, 0x55, 0x77 }, /* Queued Item */
-    { 0x3e, 0x41, 0x3e, 0x1c, 0x1c, 0x08 }, /* Moving Item */
-    { 0x7f, 0x7f, 0x1c, 0x3e, 0x77, 0x63 }, /* Keyboard file */
-    { 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e }, /* Reverse Cursor / Marker */
-    { 0x06, 0x03, 0x5b, 0x5b, 0x0f, 0x06 }, /* question mark */
-    { 0x00, 0x18, 0x24, 0x24, 0x18, 0x00 }, /* Menu Settings */
-    { 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00 }, /* function call from the menu */
-    { 0x18, 0x18, 0x7e, 0x7e, 0x18, 0x18 }, /* sub menu */
-    { 0x01, 0x55, 0x01, 0x55, 0x54, 0x54 }, /* in submenu */
-    { 0x1c, 0x3e, 0x7f, 0x7f, 0x3e, 0x1c }, /* Recording menu */
-    { 0x1c, 0x1c, 0x22, 0x41, 0x7f, 0x00 }, /* voice menu */
-    { 0x06, 0x0f, 0x78, 0x78, 0x0f, 0x06 }, /* general settings menu */
-    { 0x1e, 0x22, 0x49, 0x49, 0x22, 0x1e }, /* system menu */
-    { 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00 }, /* playback menu */
-    { 0x1f, 0x51, 0x71, 0x71, 0x51, 0x1f }, /* display menu */
-    { 0x1e, 0x32, 0x32, 0x32, 0x1e, 0x00 }, /* remote display menu */
-#if CONFIG_TUNER
-    { 0x03, 0x05, 0x7f, 0x05, 0x03, 0x00 }, /* radio */
-#endif
-    { 0x1f, 0x11, 0x7d, 0x46, 0x44, 0x78 }, /* File View Menu */
-    { 0x06, 0x7f, 0x06, 0x18, 0x7f, 0x18 }, /* EQ menu */
-    { 0x20, 0x70, 0x70, 0x3f, 0x0a, 0x0a }, /* "rockbox" musical note */
-};
-
 const unsigned char bitmap_icons_7x8[][7] =
 {
     {0x08,0x1c,0x3e,0x3e,0x3e,0x14,0x14}, /* Power plug */
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h
index 7682d44..8c4cd2b 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -32,10 +32,6 @@
 #include <remote_rockboxlogo.h>
 #endif
 
-/*
- * Icons of size 6x8 pixels
- */
-
 
 /* Symbolic names for icons */
 enum icons_5x8 {
@@ -49,46 +45,6 @@
     Icon5x8Last
 };
 
-/* If any icons are added to this enum, they must be
-   added to the unused_but_needed enum in ../player/icons.h */
-enum icons_6x8 {
-    Icon_Audio,
-    Icon_Folder,
-    Icon_Playlist,
-    Icon_Cursor,
-    Icon_Wps,
-    Icon_Firmware,
-    Icon_Font,
-    Icon_Language,
-    Icon_Config,
-    Icon_Plugin,
-    Icon_Bookmark,
-    Icon_Preset,
-    Icon_Queued,
-    Icon_Moving,
-    Icon_Keyboard,
-    Icon_Reverse_Cursor,
-    Icon_Questionmark,
-    Icon_Menu_setting,
-    Icon_Menu_functioncall,
-    Icon_Submenu,
-    Icon_Submenu_Entered,
-    Icon_Recording,
-    Icon_Voice,
-    Icon_General_settings_menu,
-    Icon_System_menu,
-    Icon_Playback_menu,
-    Icon_Display_menu,
-    Icon_Remote_Display_menu,
-#if CONFIG_TUNER
-    Icon_Radio_screen,
-#endif
-    Icon_file_view_menu,
-    Icon_EQ,
-    Icon_Rockbox,
-    Icon6x8Last,
-};
-
 enum icons_7x8 {
     Icon_Plug,
     Icon_USBPlug,
@@ -144,7 +100,6 @@
 #endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
 
 extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5];
-extern const unsigned char bitmap_icons_6x8[Icon6x8Last][6];
 extern const unsigned char bitmap_icons_7x8[Icon7x8Last][7];
 extern const unsigned char bitmap_icon_disk[];
 
diff --git a/apps/recorder/keyboard.c b/apps/recorder/keyboard.c
index 9856e80..bb8e4e9 100644
--- a/apps/recorder/keyboard.c
+++ b/apps/recorder/keyboard.c
@@ -31,7 +31,7 @@
 #include "logf.h"
 #include "hangul.h"
 #include "action.h"
-#include "icons.h"
+#include "icon.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
@@ -654,10 +654,9 @@
                 /* Draw nicer bitmap arrow if room, else settle for "<". */
                 if (text_w >= 6 && pm->font_h >= 8)
                 {
-                    sc->mono_bitmap(bitmap_icons_6x8[Icon_Reverse_Cursor],
-                                    (text_w - 6) / 2,
-                                    pm->main_y + (pm->font_h - 8) / 2 ,
-                                    6, 8);
+                    screen_put_iconxy(sc, (text_w - 6) / 2,
+                                      pm->main_y + (pm->font_h - 8) / 2 ,
+                                      Icon_Reverse_Cursor);
                 }
                 else
                 {
@@ -672,10 +671,9 @@
                 /* Draw nicer bitmap arrow if room, else settle for ">". */
                 if (text_w >= 6 && pm->font_h >= 8)
                 {
-                    sc->mono_bitmap(bitmap_icons_6x8[Icon_Cursor],
-                                    sc->width - text_w + (text_w - 6) / 2,
-                                    pm->main_y + (pm->font_h - 8) / 2,
-                                    6, 8);
+                    screen_put_iconxy(sc, sc->width - text_w + (text_w - 6) / 2,
+                                      pm->main_y + (pm->font_h - 8) / 2,
+                                      Icon_Cursor);
                 }
                 else
                 {
diff --git a/apps/settings.c b/apps/settings.c
index 23b8117..f3ce2d4 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -853,6 +853,9 @@
 #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
     enc_global_settings_apply();
 #endif
+    /* load the icon set */
+    icons_init();
+    
 }
 
 
@@ -1076,13 +1079,7 @@
     else oldvalue = *(bool*)variable;
 
     gui_synclist_init(&lists,value_setting_get_name_cb,(void*)cb_data,false,1);
-    gui_synclist_set_title(&lists, (char*)string,
-#ifdef HAVE_LCD_BITMAP
-        bitmap_icons_6x8[Icon_Questionmark]
-#else
-        NOICON
-#endif
-    );
+    gui_synclist_set_title(&lists, (char*)string,Icon_Questionmark);
     gui_synclist_set_icon_callback(&lists,NULL);
     gui_synclist_set_nb_items(&lists,nb_items);
     gui_synclist_limit_scroll(&lists,true);
diff --git a/apps/settings.h b/apps/settings.h
index 33dfb85..c27b6e6 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -55,6 +55,7 @@
 #define LANG_DIR    ROCKBOX_DIR "/langs"
 #define WPS_DIR     ROCKBOX_DIR "/wps"
 #define THEME_DIR   ROCKBOX_DIR "/themes"
+#define ICON_DIR    ROCKBOX_DIR "/icons"
 #define PLUGIN_DIR  ROCKBOX_DIR "/rocks"
 #define VIEWERS_DIR  ROCKBOX_DIR "/viewers"
 #define BACKDROP_DIR ROCKBOX_DIR "/backdrops"
@@ -706,7 +707,13 @@
     (defined(HAVE_RECORDING) || CONFIG_TUNER)
     int alarm_wake_up_screen;
 #endif
-
+    /* customizable icons */
+    unsigned char icon_file[MAX_FILENAME+1];
+    unsigned char viewers_icon_file[MAX_FILENAME+1];
+#ifdef HAVE_REMOTE_LCD
+    unsigned char remote_icon_file[MAX_FILENAME+1];
+    unsigned char remote_viewers_icon_file[MAX_FILENAME+1];
+#endif
 };
 
 /** global variables **/
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 3e4e3fb..2ebce0e 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -1160,6 +1160,21 @@
     {F_T_INT, &global_settings.alarm_wake_up_screen, LANG_ALARM_WAKEUP_SCREEN,
         INT(ALARM_START_WPS), "alarm wakeup screen", ALARM_SETTING_TEXT, UNUSED},
 #endif /* HAVE_RTC_ALARM */
+            
+    /* Customizable icons */
+#ifdef HAVE_LCD_BITMAP
+    FILENAME_SETTING(F_THEMESETTING, icon_file, "iconset", "",
+                     ICON_DIR "/", ".bmp", MAX_FILENAME+1),
+    FILENAME_SETTING(F_THEMESETTING, viewers_icon_file, "viewers iconset", "",
+                     ICON_DIR "/", ".bmp", MAX_FILENAME+1),
+#ifdef HAVE_REMOTE_LCD
+    FILENAME_SETTING(F_THEMESETTING, remote_icon_file, "remote iconset", "",
+                     ICON_DIR "/", ".bmp", MAX_FILENAME+1),
+    FILENAME_SETTING(F_THEMESETTING, remote_viewers_icon_file,
+                     "remote viewers iconset", "",
+                     ICON_DIR "/", ".bmp", MAX_FILENAME+1),
+#endif
+#endif /* HAVE_REMOTE_LCD */
 };
 
 const int nb_settings = sizeof(settings)/sizeof(*settings);
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 56e8740..41db17b 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -1686,20 +1686,12 @@
     return attr;
 }
 
-#ifdef HAVE_LCD_BITMAP
-const unsigned char* tagtree_get_icon(struct tree_context* c)
-#else
-int   tagtree_get_icon(struct tree_context* c)
-#endif
+int tagtree_get_icon(struct tree_context* c)
 {
     int icon = Icon_Folder;
 
     if (tagtree_get_attr(c) == TREE_ATTR_MPA)
         icon = Icon_Audio;
 
-#ifdef HAVE_LCD_BITMAP
-    return bitmap_icons_6x8[icon];
-#else
     return icon;
-#endif
 }
diff --git a/apps/tagtree.h b/apps/tagtree.h
index ccb71c4..980dc0d 100644
--- a/apps/tagtree.h
+++ b/apps/tagtree.h
@@ -46,11 +46,7 @@
 bool tagtree_insert_selection_playlist(int position, bool queue);
 char *tagtree_get_title(struct tree_context* c);
 int tagtree_get_attr(struct tree_context* c);
-#ifdef HAVE_LCD_BITMAP
-const unsigned char* tagtree_get_icon(struct tree_context* c);
-#else
-int   tagtree_get_icon(struct tree_context* c);
-#endif
+int tagtree_get_icon(struct tree_context* c);
 int tagtree_get_filename(struct tree_context* c, char *buf, int buflen);
 
 #endif
diff --git a/apps/tree.c b/apps/tree.c
index 4e4d4c7..944f768 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -219,20 +219,20 @@
 }
 
 
-static void tree_get_fileicon(int selected_item, void * data, ICON * icon)
+static int tree_get_fileicon(int selected_item, void * data)
 {
     struct tree_context * local_tc=(struct tree_context *)data;
 #ifdef HAVE_TAGCACHE
     bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB;
     if (id3db) {
-        *icon = (ICON)tagtree_get_icon(&tc);
+        return tagtree_get_icon(&tc);
     }
     else
 #endif
         {
         struct entry* dc = local_tc->dircache;
         struct entry* e = &dc[selected_item];
-        *icon = (ICON)filetype_get_icon(e->attr);
+        return filetype_get_icon(e->attr);
     }
 }
 
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 0ad94e0..9d537ac 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -225,6 +225,20 @@
 #define CONFIG_RTC 0
 #endif
 
+/* define this in the target config.h to use a different size */
+#ifndef CONFIG_DEFAULT_ICON_HEIGHT
+#define CONFIG_DEFAULT_ICON_HEIGHT 8
+#endif
+#ifndef CONFIG_DEFAULT_ICON_WIDTH
+#define CONFIG_DEFAULT_ICON_WIDTH 6
+#endif
+#ifndef CONFIG_REMOTE_DEFAULT_ICON_HEIGHT
+#define CONFIG_REMOTE_DEFAULT_ICON_HEIGHT 8
+#endif
+#ifndef CONFIG_REMOTE_DEFAULT_ICON_WIDTH
+#define CONFIG_REMOTE_DEFAULT_ICON_WIDTH 6
+#endif
+
 /* Enable the directory cache and tagcache in RAM if we have
  * plenty of RAM. Both features can be enabled independently. */
 #if ((defined(MEMORYSIZE) && (MEMORYSIZE > 8)) || MEM > 8) && \
diff --git a/tools/buildzip.pl b/tools/buildzip.pl
index 380c3a4..1dc3397 100755
--- a/tools/buildzip.pl
+++ b/tools/buildzip.pl
@@ -61,6 +61,8 @@
 
 
 my $firmdir="$ROOT/firmware";
+my $appsdir="$ROOT/apps";
+my $viewer_bmpdir="$ROOT/apps/plugins/bitmaps/viewer_defaults";
 
 my $cppdef = $target;
 
@@ -72,8 +74,17 @@
 #ifdef HAVE_LCD_BITMAP
 Bitmap: yes
 Depth: LCD_DEPTH
+Icon Width: CONFIG_DEFAULT_ICON_WIDTH
+Icon Height: CONFIG_DEFAULT_ICON_HEIGHT
 #endif
 Codec: CONFIG_CODEC
+#ifdef HAVE_REMOTE_LCD
+Remote Depth: LCD_REMOTE_DEPTH
+Remote Icon Width: CONFIG_REMOTE_DEFAULT_ICON_WIDTH
+Remote Icon Height: CONFIG_REMOTE_DEFAULT_ICON_WIDTH
+#else
+Remote Depth: 0
+#endif
 STOP
 ;
     close(GCC);
@@ -84,7 +95,9 @@
 
     open(TARGET, "$c|");
 
-    my ($bitmap, $depth, $swcodec);
+    my ($bitmap, $depth, $swcodec, $icon_h, $icon_w);
+    my ($remote_depth, $remote_icon_h, $remote_icon_w);
+    $icon_count = 1;
     while(<TARGET>) {
         # print STDERR "DATA: $_";
         if($_ =~ /^Bitmap: (.*)/) {
@@ -93,15 +106,31 @@
         elsif($_ =~ /^Depth: (\d*)/) {
             $depth = $1;
         }
+        elsif($_ =~ /^Icon Width: (\d*)/) {
+            $icon_w = $1;
+        }
+        elsif($_ =~ /^Icon Height: (\d*)/) {
+            $icon_h = $1;
+        }
         elsif($_ =~ /^Codec: (\d*)/) {
             # SWCODEC is 1, the others are HWCODEC
             $swcodec = ($1 == 1);
         }
+        elsif($_ =~ /^Remote Depth: (\d*)/) {
+            $remote_depth = $1;
+        }
+        elsif($_ =~ /^Remote Icon Width: (\d*)/) {
+            $remote_icon_w = $1;
+        }
+        elsif($_ =~ /^Remote Icon Height: (\d*)/) {
+            $remote_icon_h = $1;
+        }
     }
     close(TARGET);
     unlink("gcctemp");
 
-    return ($bitmap, $depth, $swcodec);
+    return ($bitmap, $depth, $icon_w, $icon_h,
+            $swcodec, $remote_depth, $remote_icon_w, $remote_icon_h);
 }
 
 sub filesize {
@@ -130,7 +159,8 @@
 sub buildzip {
     my ($zip, $image, $fonts)=@_;
 
-    my ($bitmap, $depth, $swcodec) = &gettargetinfo();
+    my ($bitmap, $depth, $icon_w, $icon_h, $swcodec,
+        $remote_depth, $remote_icon_w, $remote_icon_h) = &gettargetinfo();
 
     # print "Bitmap: $bitmap\nDepth: $depth\nSwcodec: $swcodec\n";
 
@@ -261,6 +291,14 @@
     }
     close VIEWERS;
     
+    if ($bitmap) {
+        mkdir ".rockbox/icons", 0777;
+        `cp $viewer_bmpdir/viewers.${icon_w}x${icon_h}x$depth.bmp .rockbox/icons/viewers.bmp`;
+        if ($remote_depth) {
+            `cp $viewer_bmpdir/remote_viewers.${remote_icon_w}x${remote_icon_h}x$remote_depth.bmp .rockbox/icons/remote_viewers.bmp`;
+        }
+    }
+    
     `cp $ROOT/apps/tagnavi.config .rockbox/`;
       
     if($bitmap) {