Index: apps/screen_access.c
===================================================================
--- apps/screen_access.c	(revision 16159)
+++ apps/screen_access.c	(working copy)
@@ -230,9 +230,6 @@
     int i;
     FOR_NB_SCREENS(i)
     {
-#ifdef HAVE_LCD_BITMAP
-        ((struct screen*)&screens[i])->setfont(FONT_UI);
-#endif
         gui_textarea_update_nblines(&screens[i]);
     }
 }
Index: apps/playlist.c
===================================================================
--- apps/playlist.c	(revision 16159)
+++ apps/playlist.c	(working copy)
@@ -3634,3 +3634,17 @@
 
     return result;
 }
+
+/*
+ * Check if a folder exists, if not try to create it
+ * return 0 if it exists, <0 otherwise
+ */
+int playlist_check_dir(const char* dirname)
+{
+    DIR* dir = opendir(dirname);
+    if(dir)
+        closedir(dir);
+    else 
+        return mkdir(dirname);
+    return 0;
+}
Index: apps/screens.c
===================================================================
--- apps/screens.c	(revision 16159)
+++ apps/screens.c	(working copy)
@@ -631,7 +631,6 @@
 #if CONFIG_CODEC == SWCODEC
     pcmbuf_set_low_latency(false);
 #endif
-    lcd_setfont(FONT_UI);
     return 0;
 }
 #endif /* HAVE_PITCHSCREEN */
Index: apps/playlist.h
===================================================================
--- apps/playlist.h	(revision 16159)
+++ apps/playlist.h	(working copy)
@@ -30,6 +30,7 @@
 #define PLAYLIST_ATTR_SKIPPED   0x04
 #define PLAYLIST_MAX_CACHE      16
 
+#define DEFAULT_PLAYLIST_DIR "/Playlists"
 #define DEFAULT_DYNAMIC_PLAYLIST_NAME "/dynamic.m3u8"
 
 enum playlist_command {
@@ -127,6 +128,7 @@
 int playlist_update_resume_info(const struct mp3entry* id3);
 int playlist_get_display_index(void);
 int playlist_amount(void);
+int playlist_check_dir(const char*);
 
 /* Exported functions for all playlists.  Pass NULL for playlist_info
    structure to work with current playlist. */
Index: apps/recorder/bmp.c
===================================================================
--- apps/recorder/bmp.c	(revision 16159)
+++ apps/recorder/bmp.c	(working copy)
@@ -51,6 +51,7 @@
 #pragma pack (push, 2)
 #endif
 
+#define FACT_SCALE 1000
 /* BMP header structure */
 struct bmp_header {
     uint16_t type;          /* signature - 'BM' */
@@ -81,6 +82,12 @@
     uint32_t raw;
 };
 
+/* maximum bitmap width which can be read: */
+#define MAX_WIDTH 1280
+/* Buffer for one line */
+//static uint32_t bmpbuf[MAX_WIDTH];
+static union rgb_union bmpbuf[MAX_WIDTH];
+
 /* masks for supported BI_BITFIELDS encodings (16/32 bit), little endian */
 static const unsigned char bitfields[3][12] = {
     { 0x00,0x7c,0x00,0,  0xe0,0x03,0x00,0,  0x1f,0x00,0x00,0 }, /* 15 bit */
@@ -137,59 +144,104 @@
               + (unsigned)color.blue) / 10;
 }
 
-/******************************************************************************
- * read_bmp_file()
- *
- * Reads a BMP file and puts the data in rockbox format in *bitmap.
- *
- *****************************************************************************/
-int read_bmp_file(const char* filename,
-                  struct bitmap *bm,
-                  int maxsize,
-                  int format)
+
+static void set_pixel(int format,
+                      unsigned char *bitmap,
+                      bool dither,
+                      union rgb_union color,
+                      int dst_padded_width,
+                      int dst_x,
+                      int dst_y)
 {
-    int fd, ret;
-    fd = open(filename, O_RDONLY);
+#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
+    bool remote = format & FORMAT_REMOTE;
+    format &= ~FORMAT_REMOTE;
+#endif
 
-    /* Exit if file opening failed */
-    if (fd < 0) {
-        DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename, fd);
-        return fd * 10 - 1;
+#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
+    if (format == FORMAT_NATIVE)
+    {
+# if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
+        if (remote)
+        {
+#  if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
+            int delta = (dither)?dither_matrix[dst_y & 0xf][dst_x & 0xf]:127;
+            unsigned bright = brightness(color);
+            bright = (3 * bright + (bright >> 6) + delta) >> 8;
+            ((fb_remote_data *)bitmap)[dst_padded_width*(dst_y >> 3)+dst_x] |= 
+                remote_pattern[bright] << (dst_y & 7);
+#  endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
+        }
+        else
+# endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
+        {
+            int delta = (dither)?dither_matrix[dst_y & 0xf][dst_x & 0xf]:127;
+# if LCD_DEPTH == 2
+            unsigned bright = brightness(color);
+            bright = (3 * bright + (bright >> 6) + delta) >> 8;
+#  if LCD_PIXELFORMAT == VERTICAL_PACKING
+            /* iriver H1x0 */
+            ((fb_data *)bitmap)[dst_padded_width * (dst_y >> 2)+dst_x] |=
+                (~bright & 3) << (2 * (dst_y & 3));
+#  else /* LCD_PIXELFORMAT == HORIZONTAL_PACKING */
+            /* greyscale iPods */
+            ((fb_data *)bitmap)[dst_padded_width * dst_y + (dst_x >> 2)] |=
+                (~bright & 3) << (6 - 2 * (dst_x & 3));
+#  endif /* LCD_PIXELFORMAT */
+# elif LCD_DEPTH == 16
+            /* iriver h300, colour iPods, X5 */
+            unsigned r = (31 * color.red + (color.red >> 3) + delta) >> 8;
+            unsigned g = (63 * color.green + (color.green >> 2) + delta) >> 8;
+            unsigned b = (31 * color.blue + (color.blue >> 3) + delta) >> 8;
+            ((fb_data *)bitmap)[dst_padded_width * dst_y + dst_x] =
+                LCD_RGBPACK_LCD(r, g, b);
+# endif /* LCD_DEPTH */
+        }
     }
-
-    ret = read_bmp_fd(fd, bm, maxsize, format);
-    close(fd);
-    return ret;
+    else
+#else /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
+    (void) format;
+    (void) dither;
+#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
+    {
+        if (brightness(color) < 128)
+            bitmap[dst_padded_width * (dst_y >> 3)+dst_x] |= 1 << (dst_y & 7);
+    }
 }
 
 /******************************************************************************
- * read_bmp_fd()
+ * read_bmp_file()
  *
- * Reads a BMP file in an open file descriptor and puts the data in rockbox
- * format in *bitmap.
+ * Reads a BMP file and puts the data in rockbox format in *bitmap.
  *
  *****************************************************************************/
-int read_bmp_fd(int fd,
-                struct bitmap *bm,
-                int maxsize,
-                int format)
+int read_bmp_fd(  int fd,
+                  struct bitmap *bm,
+                  int maxsize,
+                  int format,
+                  int dst_maxwidth,
+                  int dst_maxheight,
+                  int flags)
 {
     struct bmp_header bmph;
-    int width, height, padded_width;
-    int dst_height, dst_width;
+    int src_w, src_h, src_padded_width;
+    int dst_w, dst_h, dst_padded_width, dst_padded_height;
+    int row, ret;
+    int fact_w = FACT_SCALE;
+    int fact_h = FACT_SCALE;
+    int top = 0,decrement_y = 0;
+    int left = 0,decrement_x = 0;
     int depth, numcolors, compression, totalsize;
-    int row, col, ret;
     int rowstart, rowstop, rowstep;
 
     unsigned char *bitmap = bm->data;
-    uint32_t bmpbuf[LCD_WIDTH]; /* Buffer for one line */
-    uint32_t palette[256];
+    union rgb_union palette[256];
+    bool dither = false;
 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
     bool transparent = false;
-    bool dither = false;
 #ifdef HAVE_REMOTE_LCD
     bool remote = false;
-    
+
     if (format & FORMAT_REMOTE) {
         remote = true;
 #if LCD_REMOTE_DEPTH == 1
@@ -209,7 +261,7 @@
     }
 #else
 
-    (void)format;
+    format = FORMAT_MONO;
 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
 
     /* read fileheader */
@@ -223,27 +275,131 @@
         return -3;
     }
 
-    width = readlong(&bmph.width);
-    if (width > LCD_WIDTH) {
-        DEBUGF("read_bmp_fd: Bitmap too wide (%d pixels, max is %d)\n",
-                        width, LCD_WIDTH);
+    /* check bitmap file signature */
+    if (readshort(&bmph.type)!=0x4d42) {
+        DEBUGF("read_bmp_fd: wring signature.");
+        return -3;
+    }
+    /* read the source dimensions */
+    src_w = readlong(&bmph.width);
+    src_h = readlong(&bmph.height);
+
+    /* Exit if too wide */
+    if (((flags & BMP_RESIZE_NONE)==0 && (src_w > MAX_WIDTH)) ||
+        ((flags & BMP_RESIZE_NONE) && (src_w > LCD_WIDTH)))
+    {
+        DEBUGF("read_bmp_fd: Bitmap is too wide (%d pixels, max is %d)\n",
+               src_w, MAX_WIDTH);
         return -4;
     }
 
-    height = readlong(&bmph.height);
-    if (height < 0) {     /* Top-down BMP file */
-        height = -height;
-        rowstart = 0;
-        rowstop = height;
-        rowstep = 1;
-    } else {              /* normal BMP */
-        rowstart = height - 1;
-        rowstop = -1;
-        rowstep = -1;
+
+    /* Calculate resize factors and image size */
+    if (dst_maxwidth<=0 || dst_maxheight<=0)
+    {
+        dst_w = src_w;
+        dst_h = src_h;
     }
+    else
+    {
+        dst_w = dst_maxwidth;
+        dst_h = dst_maxheight;
+        if (flags & BMP_RESIZE_FILL)
+        {
+            int aspect_src = src_w*FACT_SCALE/src_h;
+            int aspect_dst = dst_maxwidth*FACT_SCALE/dst_maxheight;
+            if (aspect_dst >= aspect_src) /* adjust height */
+                decrement_y = (dst_maxheight * aspect_dst / aspect_src)
+                                  - dst_maxheight;
+            else /* adjust width */
+                decrement_x = (dst_maxwidth * aspect_src / aspect_dst)
+                                  - dst_maxwidth;
 
+            if ((flags & BMP_RESIZE_INCREASE) == 0 && 
+                (src_w < dst_w || src_h < dst_h))
+                {
+                    if ((decrement_x = (src_w-dst_w)) < 0)
+                        decrement_x = 0;
+                        if ((decrement_y = (src_h-dst_h)) < 0)
+                            decrement_y = 0;
+                }
+                left = decrement_x / 2;
+                top = decrement_y / 2;
+                flags |= BMP_RESIZE_DECREASE;
+        }
+        if (flags & (BMP_RESIZE_DECREASE | BMP_RESIZE_INCREASE))
+        {
+            int fact;
+            if (dst_w > 0)
+            {
+                fact = (src_w * FACT_SCALE) / (dst_w + decrement_x);
+                /* decrease allowed and increase allowed */
+                if ((fact < FACT_SCALE && (flags & BMP_RESIZE_DECREASE)) ||
+                    (fact > FACT_SCALE && (flags & BMP_RESIZE_INCREASE)))
+                    fact_w = fact;
+            }
+
+            if (dst_h > 0)
+            {
+                fact = (src_h * FACT_SCALE) / (dst_h + decrement_y);
+                /* decrease allowed and increase allowed */
+                if ((fact < FACT_SCALE && (flags & BMP_RESIZE_DECREASE)) ||
+                    (fact > FACT_SCALE && (flags & BMP_RESIZE_INCREASE)))
+                    fact_h = fact;
+            }
+
+            if ((flags & BMP_RESIZE_IGNORE_ASPECT)==0)
+            {
+                /* keep aspect ratio of source */
+                if (fact_w < fact_h)
+                    fact_w = fact_h;
+                else
+                    fact_h = fact_w;
+                /* don't resize */
+                if (fact_w <= 0 || fact_h <= 0)
+                    fact_h = fact_w = FACT_SCALE;
+            }
+            while (true)
+            {
+                dst_w = ((src_w * FACT_SCALE) / fact_w) - decrement_x;
+                if (dst_w <= dst_maxwidth)
+                    break;
+                fact_w++;
+            }
+            while (true)
+            {
+                dst_h = ((src_h * FACT_SCALE) / fact_h) - decrement_y;
+                if (dst_h <= dst_maxheight)
+                    break;
+                fact_h++;
+            }
+        }
+    }
+
+    /* returning image size */
+    bm->width  = dst_w;
+    bm->height = dst_h;
+
+    DEBUGF("read_bmp_fd: src=%d/%d, dst=%d/%d max=%d/%d (fact=%d/%d)"
+           " dec=%d/%d\n",
+           src_w, src_h, 
+           dst_w, dst_h, 
+           dst_maxwidth, dst_maxheight, 
+           fact_w, fact_h,
+           decrement_x,decrement_y);
+
+    /* Exit if too big for screen */
+    if ((flags & BMP_RESIZE_NONE)==0 &&
+        (dst_w > LCD_WIDTH || dst_h > LCD_HEIGHT))
+    {
+        DEBUGF("read_bmp_fd: error - Bitmap is too big"
+               " (%d x %d pixels, screen is %d x %d)\n",
+               dst_w, dst_h, LCD_WIDTH, LCD_HEIGHT);
+          return -5;
+    }
+
     depth = readshort(&bmph.bit_count);
-    padded_width = ((width * depth + 31) >> 3) & ~3;  /* 4-byte boundary aligned */
+    src_padded_width = ((src_w * depth + 31) >> 3) & ~3;  /* 4-byte boundary aligned */
 
 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
     if (format == FORMAT_ANY) {
@@ -253,49 +409,44 @@
             format = FORMAT_NATIVE;
     }
     bm->format = format;
-#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
-    /* returning image size */
-    bm->width = width;
-    bm->height = height;
-
-#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
     if (format == FORMAT_NATIVE) {
-#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
+# if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
         if (remote) {
-#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
-            dst_width  = width;
-            dst_height = (height + 7) >> 3;
-#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
-            totalsize = dst_width * dst_height * sizeof(fb_remote_data);
+#  if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
+            dst_padded_width = dst_w;
+            dst_padded_height = (dst_h + 7) >> 3;
+#  endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
+            totalsize = dst_padded_width * dst_padded_height * sizeof(fb_remote_data);
         } else
-#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
+# endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
         {
-#if LCD_DEPTH == 2
-#if LCD_PIXELFORMAT == VERTICAL_PACKING
-            dst_width  = width;
-            dst_height = (height + 3) >> 2;
-#else /* LCD_PIXELFORMAT == HORIZONTAL_PACKING */
-            dst_width  = (width + 3) >> 2;
-            dst_height = height;
-#endif /* LCD_PIXELFORMAT */
-#elif LCD_DEPTH == 16
-            dst_width  = width;
-            dst_height = height;
-#endif /* LCD_DEPTH */
-            totalsize  = dst_width * dst_height * sizeof(fb_data);
+# if LCD_DEPTH == 2
+#  if LCD_PIXELFORMAT == VERTICAL_PACKING
+            dst_padded_width  = dst_w;
+            dst_padded_height = (dst_h + 3) >> 2;
+#  else /* LCD_PIXELFORMAT == HORIZONTAL_PACKING */
+            dst_padded_width  = (dst_w + 3) >> 2;
+            dst_padded_height = dst_h;
+#  endif /* LCD_PIXELFORMAT */
+# elif LCD_DEPTH == 16
+            dst_padded_width  = dst_w;
+            dst_padded_height = dst_h;
+# endif /* LCD_DEPTH */
+            totalsize  = dst_padded_width * dst_padded_height * sizeof(fb_data);
         }
     } else
 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
     {
-        dst_width  = width;
-        dst_height = (height + 7) >> 3;
-        totalsize  = dst_width * dst_height;
+        dst_padded_width  = dst_w;
+        dst_padded_height = (dst_h + 7) >> 3;
+        totalsize  = dst_padded_width * dst_padded_height;
     }
 
     /* Check if this fits the buffer */
     if (totalsize > maxsize) {
-        DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
-               "%d bytes.\n", totalsize);
+        DEBUGF("read_bmp_fd: error - Bitmap is too large to fit the supplied buffer: "
+               "%d bytes.%d:%d\n", (dst_padded_height * dst_padded_width),
+               totalsize, maxsize);
         return -6;
     }
 
@@ -306,7 +457,7 @@
             numcolors = 1 << depth;
     } else
         numcolors = (compression == 3) ? 3 : 0;
-        
+
     if (numcolors > 0 && numcolors <= 256) {
         if (read(fd, palette, numcolors * sizeof(uint32_t))
             != numcolors * (int)sizeof(uint32_t))
@@ -357,31 +508,64 @@
 
     memset(bitmap, 0, totalsize);
 
+#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
+    if (remote)
+        format |= FORMAT_REMOTE; // set remote flag if it is necessary
+#endif
+
     /* loop to read rows and put them to buffer */
-    for (row = rowstart; row != rowstop; row += rowstep) {
+    for (row = src_h - 1; row >= 0; row--)
+    {
+        /* read one row */
+        int dst_y, num_rows = 0;
+        if (fact_h >= FACT_SCALE)
+        {
+            /*
+             * decrease vertically or just transport the pixels
+             * -> put only every "fact" row to the dest buffer
+             */
+            if ((row % (fact_h / FACT_SCALE)) == 0)
+            {
+                dst_y = (row * FACT_SCALE) / fact_h - top;
+                if (dst_y >= 0 && dst_y < dst_h)
+                    num_rows = 1;
+            }
+        }
+        else
+        {
+            /*
+             * increase
+             * -> duplicate src-pixel for not existing dst_rows/cols
+             */
+            dst_y = MAX(row * FACT_SCALE / fact_h - top,0);
+            num_rows = MIN((row + 1) * FACT_SCALE / fact_h - top, dst_h)-dst_y;
+        }
+        if (num_rows<=0)
+        {
+            /* if we are not going to process data - just skip reading */
+            ret = lseek(fd, src_padded_width, SEEK_CUR );
+            continue;
+        }
+        ret = read(fd, bmpbuf, src_padded_width);
+        if (ret != src_padded_width) {
+            DEBUGF("read_bmp_fd: error reading image, read returned: %d "
+                   "expected: %d\n", ret, src_padded_width);
+            return -9;
+        }
         unsigned data, mask;
         unsigned char *p;
         uint16_t *p2;
         uint32_t *rp;
-        union rgb_union *qp;
-        union rgb_union q0, q1;   
+        union rgb_union q0, q1;
 
-        /* read one row */
-        ret = read(fd, bmpbuf, padded_width);
-        if (ret != padded_width) {
-            DEBUGF("read_bmp_fd: error reading image, read returned: %d "
-                   "expected: %d\n", ret, padded_width);
-            return -9;
-        }
-
         /* convert whole line in-place to XRGB8888 (little endian) */
-        rp = bmpbuf + width;
+        rp = (uint32_t *)(bmpbuf + src_w);
         switch (depth) {
           case 1:
-            q0.raw = palette[0];
-            q1.raw = palette[1];
-            p = (unsigned char*)bmpbuf + ((width + 7) >> 3);
-            mask = 0x80 >> ((width + 7) & 7);
+            q0.raw = palette[0].raw;
+            q1.raw = palette[1].raw;
+            p = (unsigned char*)bmpbuf + ((src_w + 7) >> 3);
+            mask = 0x80 >> ((src_w + 7) & 7);
             while (p > (unsigned char*)bmpbuf) {
                 data = *(--p);
                 for (; mask <= 0x80; mask <<= 1)
@@ -391,25 +575,25 @@
             break;
 
           case 4:
-            if (width & 1)
+            if (src_w & 1)
                 rp++;
-            p = (unsigned char*)bmpbuf + ((width + 1) >> 1);
+            p = (unsigned char*)bmpbuf + ((src_w + 1) >> 1);
             while (p > (unsigned char*)bmpbuf) {
                 data = *(--p);
-                *(--rp) = palette[data & 0x0f];
-                *(--rp) = palette[data >> 4];
+                *(--rp) = palette[data & 0x0f].raw;
+                *(--rp) = palette[data >> 4].raw;
             }
             break;
 
           case 8:
-            p = (unsigned char*)bmpbuf + width;
+            p = (unsigned char*)bmpbuf + src_w;
             while (p > (unsigned char*)bmpbuf)
-                *(--rp) = palette[*(--p)];
+                *(--rp) = palette[*(--p)].raw;
             break;
-            
+
           case 15:
           case 16:
-            p2 = (uint16_t *)bmpbuf + width;
+            p2 = (uint16_t *)bmpbuf + src_w;
             while (p2 > (uint16_t *)bmpbuf) {
                 unsigned component, rgb;
 
@@ -455,7 +639,7 @@
             break;
 
           case 24:
-            p = (unsigned char*)bmpbuf + 3 * width;
+            p = (unsigned char*)bmpbuf + 3 * src_w;
             while (p > (unsigned char*)bmpbuf) {
                 data = *(--p);
                 data = (data << 8) | *(--p);
@@ -467,99 +651,63 @@
           case 32: /* already in desired format */
             break;
         }
-        
+
         /* Convert to destination format */
-        qp = (union rgb_union *)bmpbuf;
-#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
-        if (format == FORMAT_NATIVE) {
-#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
-            if (remote) {
-#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
-                fb_remote_data *dest = (fb_remote_data *)bitmap
-                                     + dst_width * (row >> 3);
-                int shift = row & 7;
-                int delta = 127;
-                unsigned bright;
-                
-                for (col = 0; col < width; col++) {
-                    if (dither)
-                        delta = dither_matrix[row & 0xf][col & 0xf];
-                    bright = brightness(*qp++);
-                    bright = (3 * bright + (bright >> 6) + delta) >> 8;
-                    *dest++ |= remote_pattern[bright] << shift;
+        while (--num_rows>=0) {
+            int src_col, dst_x;
+            if (fact_w >= FACT_SCALE)
+            {
+                /* decrease horizontally or just transport the pixels */
+                for (dst_x = 0; dst_x < dst_w; dst_x++) {
+                    src_col = ((dst_x + left) * fact_w) / FACT_SCALE;
+                    set_pixel(format,bitmap,dither,bmpbuf[src_col],
+                              dst_padded_width,dst_x,dst_y);
                 }
-#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
-            } else
-#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
+            }
+            else /*if (fact_w < FACT_SCALE)*/
             {
-#if LCD_DEPTH == 2
-#if LCD_PIXELFORMAT == VERTICAL_PACKING
-                /* iriver H1x0 */
-                fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 2);
-                int shift = 2 * (row & 3);
-                int delta = 127;
-                unsigned bright;
-
-                for (col = 0; col < width; col++) {
-                    if (dither)
-                        delta = dither_matrix[row & 0xf][col & 0xf];
-                    bright = brightness(*qp++);
-                    bright = (3 * bright + (bright >> 6) + delta) >> 8;
-                    *dest++ |= (~bright & 3) << shift;
-                }
-#else /* LCD_PIXELFORMAT == HORIZONTAL_PACKING */
-                /* greyscale iPods */
-                fb_data *dest = (fb_data *)bitmap + dst_width * row;
-                int shift = 6;
-                int delta = 127;
-                unsigned bright;
-                unsigned data = 0;
-            
-                for (col = 0; col < width; col++) {
-                    if (dither)
-                        delta = dither_matrix[row & 0xf][col & 0xf];
-                    bright = brightness(*qp++);
-                    bright = (3 * bright + (bright >> 6) + delta) >> 8;
-                    data |= (~bright & 3) << shift;
-                    shift -= 2;
-                    if (shift < 0) {
-                        *dest++ = data;
-                        data = 0;
-                        shift = 6;
+                /* increase horizontally */
+                for (src_col = 0; src_col < src_w; src_col++) {
+                    int num_col;
+                    dst_x = MAX(src_col * FACT_SCALE / fact_w - left,0);
+                    num_col = MIN((src_col + 1) * FACT_SCALE / fact_w
+                                  - left,dst_w) - dst_x;
+                    q0 = bmpbuf[src_col];
+                    while (--num_col>=0) {
+                        set_pixel(format,bitmap,dither,q0,dst_padded_width,
+                                  dst_x,dst_y);
+                        dst_x++;
                     }
                 }
-                if (shift < 6)
-                    *dest++ = data;
-#endif /* LCD_PIXELFORMAT */
-#elif LCD_DEPTH == 16
-                /* iriver h300, colour iPods, X5 */
-                fb_data *dest = (fb_data *)bitmap + dst_width * row;
-                int delta = 127;
-                unsigned r, g, b;
-
-                for (col = 0; col < width; col++) {
-                    if (dither)
-                        delta = dither_matrix[row & 0xf][col & 0xf];
-                    q0 = *qp++;
-                    r = (31 * q0.red + (q0.red >> 3) + delta) >> 8;
-                    g = (63 * q0.green + (q0.green >> 2) + delta) >> 8;
-                    b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8;
-                    *dest++ = LCD_RGBPACK_LCD(r, g, b);
-                }
-#endif /* LCD_DEPTH */
             }
-        } else
-#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
-        {
-            p = bitmap + dst_width * (row >> 3);
-            mask = 1 << (row & 7);
-
-            for (col = 0; col < width; col++, p++)
-                if (brightness(*qp++) < 128)
-                    *p |= mask;
+            dst_y++;
         }
     }
 
-    DEBUGF("totalsize: %d\n", totalsize);
+    DEBUGF("read_bmp_fd: totalsize=%d, width=%d, height=%d depth=%d"
+           " compression=%d numcolors=%d\n", 
+           totalsize, dst_w, dst_h, depth, compression, numcolors);
+
     return totalsize; /* return the used buffer size. */
 }
+
+int read_bmp_file(const char* filename,
+                  struct bitmap *bm,
+                  int maxsize,
+                  int format,
+                  int dst_maxwidth,
+                  int dst_maxheight,
+                  int flags)
+{
+    int fd = open(filename, O_RDONLY);
+    int ret;
+    /* Exit if file opening failed */
+    if (fd < 0) {
+        DEBUGF("read_bmp_fd: can't open '%s', rc: %d\n", filename, fd);
+        return fd * 10 - 1;
+    }
+    ret = read_bmp_fd(fd, bm, maxsize, format, dst_maxwidth, dst_maxheight,
+                      flags);
+    close(fd);
+    return ret;
+}
Index: apps/recorder/radio.c
===================================================================
--- apps/recorder/radio.c	(revision 16159)
+++ apps/recorder/radio.c	(working copy)
@@ -466,13 +466,14 @@
     global_settings.statusbar = true;
     FOR_NB_SCREENS(i)
     {
+        screens[i].setfont(FONT_TUNER);
         gui_textarea_clear(&screens[i]);
         screen_set_xmargin(&screens[i],0);
     }
     
     gui_syncstatusbar_draw(&statusbars,true);
 
-    fh = font_get(FONT_UI)->height;
+    fh = font_get(FONT_TUNER)->height;
     
     /* Adjust for font size, trying to center the information vertically */
     if(fh < 10)
@@ -888,7 +889,7 @@
                 int freq;
 
                 FOR_NB_SCREENS(i)
-                    screens[i].setfont(FONT_UI);
+                    screens[i].setfont(FONT_TUNER);
                 
                 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
                          curr_preset + 1, presets[curr_preset].name);
Index: apps/recorder/keyboard.c
===================================================================
--- apps/recorder/keyboard.c	(revision 16159)
+++ apps/recorder/keyboard.c	(working copy)
@@ -372,7 +372,7 @@
         }
         else
         {
-            pm->curfont = FONT_UI;
+            pm->curfont = FONT_MENU;
         }
     }
 
@@ -398,14 +398,14 @@
         /* find max width of keyboard glyphs */
         for (i = 0; i < pm->nchars; i++)
         {
-            w = font_get_width(pm->font, pm->kbd_buf[i]);
+            w = font_get_width(pm->font, pm->kbd_buf[i], param[l].curfont);
             if ( w > pm->font_w )
                 pm->font_w = w;
         }
 
         /* Since we're going to be adding spaces, make sure that we check
          * their width too */
-        w = font_get_width( pm->font, ' ' );
+        w = font_get_width( pm->font, ' ', param[l].curfont );
         if ( w > pm->font_w )
             pm->font_w = w;
     }
@@ -473,7 +473,7 @@
 
         while (*utf8)
         {
-            int w = font_get_width(pm->font, ch);
+            int w = font_get_width(pm->font, ch, param[l].curfont);
             utf8 = (unsigned char*)utf8decode(utf8, &ch);
 
             if (w > text_w)
@@ -765,8 +765,6 @@
         switch ( button )
         {
             case ACTION_KBD_ABORT:
-                FOR_NB_SCREENS(l)
-                    screens[l].setfont(FONT_UI);
 
 #ifdef HAS_BUTTONBAR
                 global_settings.buttonbar=buttonbar_config;
Index: apps/recorder/bmp.h
===================================================================
--- apps/recorder/bmp.h	(revision 16159)
+++ apps/recorder/bmp.h	(working copy)
@@ -22,21 +22,34 @@
 #include "config.h"
 #include "lcd.h"
 
+#define BMP_RESIZE_NONE           1
+#define BMP_RESIZE_INCREASE       2
+#define BMP_RESIZE_DECREASE       4
+#define BMP_RESIZE_IGNORE_ASPECT  8
+#define BMP_RESIZE_FILL           16
+
 /*********************************************************************
  * read_bmp_file()
  *
  * Reads a 8bit BMP file and puts the data in a 1-pixel-per-byte
- * array.
+ * array. 
  * Returns < 0 for error, or number of bytes used from the bitmap buffer
  *
  **********************************************/
+int read_bmp_fd  (int fd,
+                  struct bitmap *bm,
+                  int maxsize,
+                  int format,
+                  int dst_maxwidth, /* = 0 */
+                  int dst_maxheight,/* = 0 */
+                  int flags);       /* BMP_RESIZE_NONE */
+
 int read_bmp_file(const char* filename,
                   struct bitmap *bm,
                   int maxsize,
-                  int format);
+                  int format,
+                  int dst_maxwidth, /* = 0 */
+                  int dst_maxheight,/* = 0 */
+                  int flags);       /* BMP_RESIZE_NONE */
 
-int read_bmp_fd(int fd,
-                struct bitmap *bm,
-                int maxsize,
-                int format);
 #endif
Index: apps/recorder/recording.c
===================================================================
--- apps/recorder/recording.c	(revision 16159)
+++ apps/recorder/recording.c	(working copy)
@@ -949,7 +949,7 @@
 
     FOR_NB_SCREENS(i)
     {
-        screens[i].setfont(FONT_SYSFIXED);
+        screens[i].setfont(FONT_RECORD);
         screens[i].getstringsize("M", &w, &h);
         screens[i].setmargins(global_settings.cursor_style ? 0 : w, 8);
         filename_offset[i] = ((screens[i].height >= 80) ? 1 : 0);
@@ -1355,7 +1355,7 @@
 
                         FOR_NB_SCREENS(i)
                         {
-                            screens[i].setfont(FONT_SYSFIXED);
+                            screens[i].setfont(FONT_RECORD);
                             screens[i].setmargins(
                                 global_settings.cursor_style ? 0 : w, 8);
                         }
@@ -1435,7 +1435,7 @@
 #endif
 
             FOR_NB_SCREENS(i)
-                screens[i].setfont(FONT_SYSFIXED);
+                screens[i].setfont(FONT_RECORD);
 
         seconds = audio_recorded_time() / HZ;
 
@@ -1942,9 +1942,6 @@
     rec_status &= ~RCSTAT_IN_RECSCREEN;
     sound_settings_apply();
 
-    FOR_NB_SCREENS(i)
-        screens[i].setfont(FONT_UI);
-
     /* if the directory was created or recording happened, make sure the
        browser is updated */
     if (rec_status & (RCSTAT_CREATED_DIRECTORY | RCSTAT_HAVE_RECORDED))
@@ -1981,7 +1978,7 @@
 
     FOR_NB_SCREENS(i)
     {
-        screens[i].setfont(FONT_SYSFIXED);
+        screens[i].setfont(FONT_RECORD);
         screens[i].getstringsize("A",&w,&h);
     }
 
@@ -2094,8 +2091,6 @@
     set_gain();
 
     settings_save();
-    FOR_NB_SCREENS(i)
-        screens[i].setfont(FONT_UI);
 
     return false;
 }
@@ -2116,7 +2111,7 @@
 
     FOR_NB_SCREENS(i)
     {
-        screens[i].setfont(FONT_SYSFIXED);
+        screens[i].setfont(FONT_RECORD);
         screens[i].getstringsize("A",&w,&h);
     }
 
@@ -2191,8 +2186,6 @@
     set_gain();
 
     settings_save();
-    FOR_NB_SCREENS(i)
-        screens[i].setfont(FONT_UI);
 
     return false;
 }
Index: apps/recorder/peakmeter.c
===================================================================
--- apps/recorder/peakmeter.c	(revision 16159)
+++ apps/recorder/peakmeter.c	(working copy)
@@ -919,14 +919,14 @@
 void peak_meter_screen(struct screen *display, int x, int y, int height)
 {
     peak_meter_draw(display, &scales[display->screen_type], x, y,
-                        display->width - x, height);
+                        display->getwidth() - x, height);
 }           
 /**
  * Draws a peak meter in the specified size at the specified position.
  * @param int x - The x coordinate. 
- *                Make sure that 0 <= x and x + width < display->width
+ *                Make sure that 0 <= x and x + width < display->getwidth()
  * @param int y - The y coordinate. 
- *                Make sure that 0 <= y and y + height < display->height
+ *                Make sure that 0 <= y and y + height < display->getheight()
  * @param int width - The width of the peak meter. Note that for display
  *                    of clips a 3 pixel wide area is used ->
  *                    width > 3
@@ -1105,7 +1105,7 @@
         start_trigx = x+peak_meter_scale_value(trig_strt_threshold,meterwidth);
         display->vline(start_trigx, ycenter - 2, ycenter);
         start_trigx ++;
-        if (start_trigx < display->width ) display->drawpixel(start_trigx, ycenter - 1);
+        if (start_trigx < display->getwidth() ) display->drawpixel(start_trigx, ycenter - 1);
 
         stop_trigx = x + peak_meter_scale_value(trig_stp_threshold,meterwidth);
         display->vline(stop_trigx, ycenter - 2, ycenter);
Index: apps/tree.c
===================================================================
--- apps/tree.c	(revision 16159)
+++ apps/tree.c	(working copy)
@@ -311,8 +311,7 @@
     gui_synclist_set_voice_callback(&tree_lists, tree_voice_cb);
     gui_synclist_set_icon_callback(&tree_lists, &tree_get_fileicon);
 #ifdef HAVE_LCD_COLOR
-    gui_list_set_color_callback(&tree_lists,
-                                &tree_get_filecolor);
+    gui_synclist_set_color_callback(&tree_lists, &tree_get_filecolor);
 #endif
 }
 
@@ -994,7 +993,9 @@
     pltick = current_tick;
 
     snprintf(filename, sizeof filename, "%s.m3u8",
-             tc.currdir[1] ? tc.currdir : "/root");
+             tc.currdir[1] ? tc.currdir : 
+              playlist_check_dir(DEFAULT_PLAYLIST_DIR)==0 ? 
+                DEFAULT_PLAYLIST_DIR"/root" : "/root/");
     FOR_NB_SCREENS(i)
     {
         gui_textarea_clear(&screens[i]);
Index: apps/plugins/mp3_encoder.c
===================================================================
--- apps/plugins/mp3_encoder.c	(revision 16159)
+++ apps/plugins/mp3_encoder.c	(working copy)
@@ -2409,7 +2409,7 @@
         rb->sleep(5*HZ);
     }
 
-    rb->lcd_setfont(FONT_UI);
+    rb->lcd_setfont(FONT_PLUGIN);
 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
     rb->cpu_boost(false);
 #endif
Index: apps/plugins/xobox.c
===================================================================
--- apps/plugins/xobox.c	(revision 16159)
+++ apps/plugins/xobox.c	(working copy)
@@ -947,7 +947,7 @@
 
     /* Turn on backlight timeout (revert to settings) */
     backlight_use_settings(rb); /* backlight control in lib/helper.c */
-    rb->lcd_setfont (FONT_UI);
+    rb->lcd_setfont (FONT_PLUGIN);
 
     return ret;
 }
Index: apps/plugins/zxbox/zxbox_keyb.c
===================================================================
--- apps/plugins/zxbox/zxbox_keyb.c	(revision 16159)
+++ apps/plugins/zxbox/zxbox_keyb.c	(working copy)
@@ -198,13 +198,13 @@
         rb->screens[l]->setfont(param[l].curfont);
         /* find max width of keyboard glyphs */
         for (i=0; i<param[l].nchars; i++) {
-            w = rb->font_get_width(param[l].font, param[l].kbd_buf[i]);
+            w = rb->font_get_width(param[l].font, param[l].kbd_buf[i], FONT_PLUGIN);
             if (w > param[l].font_w)
                 param[l].font_w = w;
         }
         /* Since we're going to be adding spaces, make sure that we check
          * their width too */
-        w = rb->font_get_width( param[l].font, ' ' );
+        w = rb->font_get_width( param[l].font, ' ', FONT_PLUGIN );
         if( w > param[l].font_w )
             param[l].font_w = w;
     }
@@ -256,7 +256,7 @@
         text_w = param[l].font_w;
         while (*utf8) {
             utf8 = (unsigned char*)rb->utf8decode(utf8, &ch);
-            w = rb->font_get_width(param[l].font, ch);
+            w = rb->font_get_width(param[l].font, ch, FONT_SYSFIXED);
             if (w > text_w)
                 text_w = w;
         }
@@ -387,7 +387,7 @@
 
             case KBD_ABORT:
                 FOR_NB_SCREENS(l)
-                    rb->screens[l]->setfont(FONT_UI);
+                    rb->screens[l]->setfont(FONT_SYSFIXED);
 
                 return -1;
                 break;
@@ -506,6 +506,6 @@
         }
     }
     FOR_NB_SCREENS(l)
-        rb->screens[l]->setfont(FONT_UI);
+        rb->screens[l]->setfont(FONT_SYSFIXED);
     return 0;
 }
Index: apps/plugins/rockblox.c
===================================================================
--- apps/plugins/rockblox.c	(revision 16159)
+++ apps/plugins/rockblox.c	(working copy)
@@ -1112,7 +1112,7 @@
     ret = rockblox_loop ();
 
 #ifdef HAVE_LCD_BITMAP
-    rb->lcd_setfont (FONT_UI);
+    rb->lcd_setfont (FONT_BROWSER);
 #else
     pgfx_release();
 #endif
Index: apps/plugins/mpegplayer/mpegplayer.c
===================================================================
--- apps/plugins/mpegplayer/mpegplayer.c	(revision 16159)
+++ apps/plugins/mpegplayer/mpegplayer.c	(working copy)
@@ -482,14 +482,14 @@
         const unsigned char *bits;
 
         /* get proportional width and glyph bits */
-        width = rb->font_get_width(pf, ch);
+        width = rb->font_get_width(pf, ch, FONT_PLUGIN);
 
         if (ofs > width) {
             ofs -= width;
             continue;
         }
 
-        bits = rb->font_get_bits(pf, ch);
+        bits = rb->font_get_bits(pf, ch, FONT_PLUGIN);
 
         draw_oriented_mono_bitmap_part(bits, ofs, 0, width, x, y,
                                        width - ofs, pf->height);
Index: apps/plugins/pictureflow.c
===================================================================
--- apps/plugins/pictureflow.c	(revision 16159)
+++ apps/plugins/pictureflow.c	(working copy)
@@ -175,14 +175,20 @@
     {pictureflow_logo, BMPWIDTH_pictureflow_logo, BMPHEIGHT_pictureflow_logo},
 };
 
+enum show_album_name_values { album_name_hide = 0, album_name_bottom , album_name_top };
+
 struct config_data {
     long avg_album_width;
     int spacing_between_slides;
     int extra_spacing_for_center_slide;
     int show_slides;
     int zoom;
+    enum show_album_name_values show_album_name;
 };
 
+const int track_list_offset = ((LCD_HEIGHT > 100) ? 30 : 20); /* make the moving of the tracklist due to the album name moving more usable on small LCDs */
+
+
 /** below we allocate the memory we want to use **/
 
 static fb_data *buffer; /* for now it always points to the lcd framebuffer */
@@ -606,7 +612,7 @@
         input_bmp.data = (char *)input_bmp_buffer;
         ret = rb->read_bmp_file(tmp_path_name, &input_bmp,
                                 sizeof(fb_data)*MAX_IMG_WIDTH*MAX_IMG_HEIGHT,
-                                FORMAT_NATIVE);
+                                FORMAT_NATIVE,PREFERRED_IMG_WIDTH, PREFERRED_IMG_HEIGHT,0);
         if (ret <= 0) {
             rb->splash(HZ, "Could not read bmp");
             continue; /* skip missing/broken files */
@@ -1529,22 +1535,39 @@
     return true;
 }
 
+/**
+    Shows the album name setting menu
+*/
+int album_name_menu(void) {
+    void reset_track_list(void);
+    int selection = config.show_album_name;
 
+    MENUITEM_STRINGLIST(album_name_menu,"Show album title",NULL,
+            "Hide album title", "Show at the bottom", "Show at the top");
+    rb->do_menu(&album_name_menu,&selection);
+    config.show_album_name = selection;
+    reset_track_list();
+    return GO_TO_PREVIOUS;
+}
+
+
 /**
   Shows the settings menu
  */
 int settings_menu(void) {
     int selection = 0;
+    void reset_track_list(void);
 
     MENUITEM_STRINGLIST(settings_menu, "PictureFlow Settings", NULL, "Show FPS",
                         "Spacing", "Center margin", "Number of slides", "Zoom",
-                        "Rebuild cache");
+                        "Show album titles", "Rebuild cache");
 
     do {
         selection=rb->do_menu(&settings_menu,&selection);
         switch(selection) {
             case 0:
                 rb->set_bool("Show FPS", &show_fps);
+                reset_track_list();
                 break;
 
             case 1:
@@ -1571,13 +1594,17 @@
                 break;
 
             case 4:
-                rb->set_int("Number of slides", "", 1, &(config.zoom),
+                rb->set_int("Zoom", "", 1, &(config.zoom),
                             NULL, 1, 10, 300, NULL );
                 recalc_table();
                 reset_slides();
                 break;
-
             case 5:
+                album_name_menu();
+                recalc_table();
+                reset_slides();
+                break;
+            case 6:
                 rb->remove(CACHE_PREFIX "/ready");
                 rb->remove(EMPTY_SLIDE);
                 rb->splash(HZ, "Cache will be rebuilt on next restart");
@@ -1635,6 +1662,7 @@
     config.show_slides = 3;
     config.avg_album_width = 0;
     config.zoom = 100;
+    config.show_album_name = album_name_bottom;
 }
 
 /**
@@ -1743,7 +1771,17 @@
     const char* albumtxt = get_album_name(center_index);
     rb->lcd_getstringsize(albumtxt, &albumtxt_w, &albumtxt_h);
     const int height = LCD_HEIGHT-albumtxt_h-10;
-    track_list_visible_entries = fmin( height/albumtxt_h , track_count );
+    switch (config.show_album_name) {
+        case album_name_hide:
+            track_list_visible_entries = fmin((LCD_HEIGHT-(show_fps ?
+                            track_list_offset : 0))/albumtxt_h, track_count);
+            break;
+        case album_name_bottom:
+        case album_name_top:
+            track_list_visible_entries = fmin((height-(show_fps ?
+                            track_list_offset : 0))/albumtxt_h, track_count);
+            break;
+    }
     start_index_track_list = 0;
     track_scroll_index = 0;
     track_scroll_dir = 1;
@@ -1761,7 +1799,10 @@
         reset_track_list();
     }
     static int titletxt_w, titletxt_h, titletxt_y, titletxt_x, i, color;
-    titletxt_y = 0;
+    /* adjust track list a bit downwards whem album title is set to be shown at the top 
+        OR fps show fps is enabled */
+    titletxt_y = ((config.show_album_name == album_name_top || show_fps) ?
+                            track_list_offset : 0);
     int track_i;
     for (i=0; i < track_list_visible_entries; i++) {
         track_i = i+start_index_track_list;
@@ -1844,8 +1885,8 @@
         albumtxt_dir = -1;
         prev_center_index = center_index;
     }
-    albumtxt_y = LCD_HEIGHT-albumtxt_h-10;
-
+    albumtxt_y = ((config.show_album_name == album_name_bottom) ?
+                            (LCD_HEIGHT-albumtxt_h-10) : 10);
     if (albumtxt_w > LCD_WIDTH ) {
         rb->lcd_putsxy(albumtxt_x, albumtxt_y , albumtxt);
         if ( pf_state == pf_idle || pf_state == pf_show_tracks ) {
@@ -1945,6 +1986,7 @@
     reset_slides();
 
     char fpstxt[10];
+    int fpstxt_w, fpstxt_h;
     int button;
 
 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
@@ -1991,6 +2033,7 @@
                 break;
         }
 
+        rb->lcd_getstringsize(fpstxt, &fpstxt_w, &fpstxt_h);
         /* Calculate FPS */
         if (current_update - last_update > update_interval) {
             fps = frames * HZ / (current_update - last_update);
@@ -2002,10 +2045,14 @@
         if (show_fps) {
             rb->lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
             rb->snprintf(fpstxt, sizeof(fpstxt), "FPS: %d", fps);
-            rb->lcd_putsxy(0, 0, fpstxt);
+            /* move fps text to the bottom, when the album 
+            titles are set to be shown at the top */
+            rb->lcd_putsxy(0, (config.show_album_name == album_name_top ?
+                            (LCD_HEIGHT-fpstxt_h) : 0), fpstxt); 
         }
 
-        draw_album_text();
+        if (config.show_album_name) /* Don't draw when album names are hidden */
+            draw_album_text();
 
 
         /* Copy offscreen buffer to LCD and give time to other threads */
Index: apps/plugins/bounce.c
===================================================================
--- apps/plugins/bounce.c	(revision 16159)
+++ apps/plugins/bounce.c	(working copy)
@@ -538,7 +538,7 @@
     } while(h > 0);
     
     rb->lcd_set_drawmode(DRMODE_SOLID);
-    rb->lcd_setfont(FONT_UI);
+    rb->lcd_setfont(FONT_PLUGIN);
 
     return (h == 0) ? PLUGIN_OK : PLUGIN_USB_CONNECTED;
 }
Index: apps/plugins/lib/bmp.h
===================================================================
--- apps/plugins/lib/bmp.h	(revision 16159)
+++ apps/plugins/lib/bmp.h	(working copy)
@@ -21,6 +21,7 @@
 
 #include "lcd.h"
 #include "plugin.h"
+#include "recorder/bmp.h"
 
 /**
  * Save bitmap to file
Index: apps/plugins/jpeg.c
===================================================================
--- apps/plugins/jpeg.c	(revision 16159)
+++ apps/plugins/jpeg.c	(working copy)
@@ -3041,7 +3041,7 @@
                 rb->lcd_puts(0,3,"Left/Right: Skip File.");
             rb->lcd_puts(0,4,"Off: Quit.");
             rb->lcd_update();
-            rb->lcd_setfont(FONT_UI);
+            rb->lcd_setfont(FONT_PLUGIN);
 
             rb->button_clear_queue();
 
Index: apps/plugins/spacerocks.c
===================================================================
--- apps/plugins/spacerocks.c	(revision 16159)
+++ apps/plugins/spacerocks.c	(working copy)
@@ -1960,7 +1960,7 @@
     iohiscore();
     retval = start_game();  
     iohiscore();
-    rb->lcd_setfont(FONT_UI);
+    rb->lcd_setfont(FONT_PLUGIN);
     /* Turn on backlight timeout (revert to settings) */
     backlight_use_settings(rb); /* backlight control in lib/helper.c */
     return retval;
Index: apps/plugins/brickmania.c
===================================================================
--- apps/plugins/brickmania.c	(revision 16159)
+++ apps/plugins/brickmania.c	(working copy)
@@ -1975,7 +1975,7 @@
     configfile_save(HIGH_SCORE,config,1,0);
 
     /* Restore user's original backlight setting */
-    rb->lcd_setfont(FONT_UI);
+    rb->lcd_setfont(FONT_PLUGIN);
     /* Turn on backlight timeout (revert to settings) */
     backlight_use_settings(rb); /* backlight control in lib/helper.c */
 
Index: apps/plugins/viewer.c
===================================================================
--- apps/plugins/viewer.c	(revision 16159)
+++ apps/plugins/viewer.c	(working copy)
@@ -320,7 +320,7 @@
         ch = ' ';
 
 #ifdef HAVE_LCD_BITMAP
-    return rb->font_get_width(pf, ch);
+    return rb->font_get_width(pf, ch, FONT_BROWSER);
 #else
     return 1;
 #endif
@@ -1029,9 +1029,10 @@
 static bool viewer_init(void)
 {
 #ifdef HAVE_LCD_BITMAP
+    // MWE
+    rb->lcd_setfont(FONT_BROWSER);
+    pf = rb->font_get(FONT_BROWSER);
 
-    pf = rb->font_get(FONT_UI);
-
     display_lines = LCD_HEIGHT / pf->height;
     draw_columns = display_columns = LCD_WIDTH;
 #else
Index: apps/plugins/stopwatch.c
===================================================================
--- apps/plugins/stopwatch.c	(revision 16159)
+++ apps/plugins/stopwatch.c	(working copy)
@@ -195,7 +195,7 @@
 
 #ifdef HAVE_LCD_BITMAP
     int h;
-    rb->lcd_setfont(FONT_UI);
+    rb->lcd_setfont(FONT_PLUGIN);
     rb->lcd_getstringsize("M", NULL, &h);
     lines = (LCD_HEIGHT / h) - (LAP_Y);
 #else
Index: apps/plugins/bubbles.c
===================================================================
--- apps/plugins/bubbles.c	(revision 16159)
+++ apps/plugins/bubbles.c	(working copy)
@@ -2664,7 +2664,7 @@
                 break;
 
             case BB_USB:
-                rb->lcd_setfont(FONT_UI);
+                rb->lcd_setfont(FONT_PLUGIN);
                 return PLUGIN_USB_CONNECTED;
 
             case BB_QUIT:
@@ -2680,7 +2680,7 @@
         }
     }
 
-    rb->lcd_setfont(FONT_UI);
+    rb->lcd_setfont(FONT_PLUGIN);
     return PLUGIN_OK;
 }
 
Index: apps/plugins/robotfindskitten.c
===================================================================
--- apps/plugins/robotfindskitten.c	(revision 16159)
+++ apps/plugins/robotfindskitten.c	(working copy)
@@ -629,6 +629,6 @@
 
   play_game();
 
-  rb->lcd_setfont(FONT_UI);
+  rb->lcd_setfont(FONT_PLUGIN);
   return PLUGIN_OK;
 }
Index: apps/plugins/jewels.c
===================================================================
--- apps/plugins/jewels.c	(revision 16159)
+++ apps/plugins/jewels.c	(working copy)
@@ -1832,7 +1832,7 @@
                 break;
 
             case BJ_USB:
-                rb->lcd_setfont(FONT_UI);
+                rb->lcd_setfont(FONT_PLUGIN);
                 return PLUGIN_USB_CONNECTED;
 
             case BJ_QUIT:
@@ -1862,7 +1862,7 @@
         }
     }
 
-    rb->lcd_setfont(FONT_UI);
+    rb->lcd_setfont(FONT_PLUGIN);
     return PLUGIN_OK;
 }
 
Index: apps/plugins/rockpaint.c
===================================================================
--- apps/plugins/rockpaint.c	(revision 16159)
+++ apps/plugins/rockpaint.c	(working copy)
@@ -402,10 +402,13 @@
 {
     unsigned short ch;
     unsigned short *ucs;
+    int curfont=FONT_PLUGIN;
 
-    struct font *pf = rb->font_get( FONT_UI );
-    if( !pf ) pf = rb->font_get( FONT_SYSFIXED );
-
+    struct font *pf = rb->font_get( FONT_PLUGIN );
+    if( !pf ) {
+        pf = rb->font_get( FONT_SYSFIXED );
+        curfont=FONT_SYSFIXED;
+    }
     ucs = rb->bidi_l2v( str, 1 );
 
     while( (ch = *ucs++) != 0 && x < buf_width )
@@ -414,7 +417,7 @@
         const unsigned char *bits;
 
         /* get proportional width and glyph bits */
-        width = rb->font_get_width( pf, ch );
+        width = rb->font_get_width( pf, ch, curfont );
 
         if( ofs > width )
         {
@@ -422,7 +425,7 @@
             continue;
         }
 
-        bits = rb->font_get_bits( pf, ch );
+        bits = rb->font_get_bits( pf, ch, curfont );
 
         buffer_mono_bitmap_part( buf, buf_width, buf_height, bits, ofs, 0, width, x, y, width - ofs, pf->height);
 
@@ -843,7 +846,7 @@
 
     rb->snprintf( old_font, MAX_PATH,
                   FONT_DIR "/%s.fnt",
-                  rb->global_settings->font_file );
+                  rb->global_settings->browserfont );
 
     while( 1 )
     {
@@ -897,8 +900,8 @@
                     continue;
                 rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s",
                               de->d_name );
-                rb->font_load( bbuf );
-                rb->font_getstringsize( de->d_name, &fw, &fh, FONT_UI );
+                rb->font_load( bbuf, FONT_PLUGIN );
+                rb->font_getstringsize( de->d_name, &fw, &fh, FONT_PLUGIN );
                 if( nvih > 0 )
                 {
                     nvih -= fh;
@@ -932,12 +935,12 @@
                 {
                     rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s",
                           de->d_name );
-                    rb->font_load( bbuf );
-                    rb->font_getstringsize( de->d_name, NULL, &fh, FONT_UI );
+                    rb->font_load( bbuf, FONT_PLUGIN );
+                    rb->font_getstringsize( de->d_name, NULL, &fh, FONT_PLUGIN );
                     nvih = fh;
                 }
             }
-            rb->font_load( old_font );
+            rb->font_load( old_font, FONT_PLUGIN );
             rb->closedir( d );
         }
 
@@ -1083,7 +1086,7 @@
         rb->lcd_putsxy( left + 117, top + 60, str );
         rb->snprintf( str, 6, "%d", blue );
         rb->lcd_putsxy( left + 117, top + 70, str );
-        rb->lcd_setfont( FONT_UI );
+        rb->lcd_setfont( FONT_PLUGIN );
 
 #define CURSOR( l ) \
         rb->lcd_bitmap_transparent_part( rockpaint_hsvrgb, 1, 1, 16, left+l+1, top+20, 6, 58 ); \
@@ -1479,7 +1482,7 @@
     buffer.text.text[0] = '\0';
     rb->snprintf( buffer.text.old_font, MAX_PATH,
                   FONT_DIR "/%s.fnt",
-                  rb->global_settings->font_file );
+                  rb->global_settings->browserfont );
     while( 1 )
     {
         int m = TEXT_MENU_TEXT;
@@ -1493,7 +1496,7 @@
             case TEXT_MENU_FONT:
                 if( browse_fonts( buffer.text.font, MAX_PATH ) )
                 {
-                    rb->font_load( buffer.text.font );
+                    rb->font_load( buffer.text.font, FONT_PLUGIN );
                 }
                 break;
 
@@ -1545,7 +1548,7 @@
                                   buffer.text.text );
             case TEXT_MENU_CANCEL:
                 restore_screen();
-                rb->font_load( buffer.text.old_font );
+                rb->font_load( buffer.text.old_font, FONT_PLUGIN );
                 return;
         }
     }
@@ -2305,7 +2308,7 @@
 
     rb->lcd_setfont( FONT_SYSFIXED );
     rb->lcd_putsxy( TB_MENU_LEFT, TOP+TB_MENU_TOP, "Menu" );
-    rb->lcd_setfont( FONT_UI );
+    rb->lcd_setfont( FONT_PLUGIN );
 #undef TOP
 
     if( update ) rb->lcd_update();
@@ -2916,7 +2919,9 @@
 
     bm.data = (char*)save_buffer;
     ret = rb->read_bmp_file( file, &bm, ROWS*COLS*sizeof( fb_data ),
-                             FORMAT_NATIVE );
+                             FORMAT_NATIVE,
+                             COLS, ROWS,
+                             BMP_RESIZE_INCREASE | BMP_RESIZE_DECREASE);
 
     if((bm.width > COLS ) || ( bm.height > ROWS ))
         return -1;
Index: apps/plugins/credits.c
===================================================================
--- apps/plugins/credits.c	(revision 16159)
+++ apps/plugins/credits.c	(working copy)
@@ -163,7 +163,7 @@
     /* control if scrolling is automatic (with animation) or manual */
     bool manual_scroll = false;
 
-    rb->lcd_setfont(FONT_UI);
+    rb->lcd_setfont(FONT_PLUGIN);
     rb->lcd_clear_display();
     rb->lcd_update();
 
Index: apps/settings.c
===================================================================
--- apps/settings.c	(revision 16159)
+++ apps/settings.c	(working copy)
@@ -263,6 +263,32 @@
     return false;
 }
 
+/** reset some settings when loading a wps file
+ * to keep backward compatibility **/
+void theme_settings_reset(void)
+{
+    /* multifont settings */
+    global_settings.font_file[0] = '\0';
+    global_settings.browserfont[0] = '\0';
+    global_settings.wpsfont[0] = '\0';
+    global_settings.menufont[0] = '\0';
+#ifdef CONFIG_TUNER
+    global_settings.tunerfont[0] = '\0';
+#endif
+#ifdef HAVE_RECORDING
+    global_settings.recordfont[0] = '\0';
+#endif
+    /* reset rpws setting */
+#ifdef HAVE_REMOTE_LCD
+    global_settings.rwps_file[0]='\0';
+#endif
+    /* reset color settings */
+#ifdef HAVE_LCD_COLOR
+    global_settings.fg_color=LCD_DEFAULT_FG;
+    global_settings.bg_color=LCD_DEFAULT_BG;
+#endif
+}
+
 bool settings_load_config(const char* file, bool apply)
 {
     int fd;
@@ -274,6 +300,11 @@
     if (fd < 0)
         return false;
 
+    /* if loading a theme reset some settings for backward compatibility */
+    if(strncmp(file, THEME_DIR, strlen(THEME_DIR))==0){
+        theme_settings_reset();
+    }
+
     while (read_line(fd, line, sizeof line) > 0)
     {
         if (!settings_parseline(line, &name, &value))
@@ -732,6 +763,8 @@
 #if CONFIG_CODEC == SWCODEC
     int i;
 #endif
+    /** backward comp **/
+    bool useMultifont=false;
 
     DEBUGF( "settings_apply()\n" );
     sound_settings_apply();
@@ -816,7 +849,7 @@
          global_settings.wps_file[0] != 0xff ) {
         snprintf(buf, sizeof buf, WPS_DIR "/%s.wps",
                  global_settings.wps_file);
-        wps_data_load(gui_wps[0].data, buf, true);
+        wps_data_load(gui_wps[0].data, &screens[0], buf, true);
     }
     else
     {
@@ -853,7 +886,7 @@
     if ( global_settings.rwps_file[0]) {
         snprintf(buf, sizeof buf, WPS_DIR "/%s.rwps",
                  global_settings.rwps_file);
-        wps_data_load(gui_wps[1].data, buf, true);
+        wps_data_load(gui_wps[1].data, &screens[1], buf, true);
     }
     else
     {
@@ -863,14 +896,154 @@
 #endif
 
 #ifdef HAVE_LCD_BITMAP
-    if ( global_settings.font_file[0]) {
+     /* Load all the fonts */
+     if ( global_settings.browserfont[0] &&
+          global_settings.browserfont[0] != 0xff ) {
+         useMultifont=true;
+         snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                  global_settings.browserfont);
+         font_load(buf, FONT_BROWSER);
+     }
+     else
+         font_reset(FONT_BROWSER);
+ 
+     if ( global_settings.wpsfont[0] &&
+          global_settings.wpsfont[0] != 0xff ) {
+          useMultifont=true;
+          snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                  global_settings.wpsfont);
+         font_load(buf, FONT_WPS);
+      }
+      else
+         font_reset(FONT_WPS);
+
+     if ( global_settings.menufont[0] &&
+          global_settings.menufont[0] != 0xff ) {
+         useMultifont=true;
+         snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                  global_settings.menufont);
+         font_load(buf, FONT_MENU);
+     }
+     else
+         font_reset(FONT_MENU);
+ 
+#ifdef CONFIG_TUNER
+     if ( global_settings.tunerfont[0] &&
+          global_settings.tunerfont[0] != 0xff ) {
+         useMultifont=true;
+         snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                  global_settings.tunerfont);
+         font_load(buf, FONT_TUNER);
+     }
+     else
+         font_reset(FONT_TUNER);
+#endif /* CONFIG_TUNER */
+ 
+#ifdef HAVE_RECORDING
+     if ( global_settings.recordfont[0] &&
+          global_settings.recordfont[0] != 0xff ) {
+         useMultifont=true;
+         snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                  global_settings.recordfont);
+         font_load(buf, FONT_RECORD);
+     }
+     else
+         font_reset(FONT_RECORD);
+#endif /* HAVE_RECORDING */
+
+    /** backward comp **/
+    if(!useMultifont){
+        if ( global_settings.font_file[0] &&
+                global_settings.font_file[0] != 0xff ) {
+                snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                        global_settings.font_file);
+               font_load(buf, FONT_BROWSER);
+               font_load(buf, FONT_WPS);
+               font_load(buf, FONT_MENU);
+#ifdef CONFIG_TUNER
+               font_load(buf, FONT_TUNER);
+#endif
+#ifdef HAVE_RECORDING
+               font_load(buf, FONT_RECORD);
+#endif
+           }
+           else {
+               font_reset(FONT_BROWSER);
+               font_reset(FONT_WPS);
+               font_reset(FONT_MENU);
+#ifdef CONFIG_TUNER
+               font_reset(FONT_TUNER);
+#endif
+#ifdef HAVE_RECORDING
+               font_reset(FONT_RECORD);
+#endif
+           }
+    }
+
+    /* Load all user fonts */
+    if ( global_settings.userfont1[0] &&
+         global_settings.userfont1[0] != 0xff ) {
         snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
-                 global_settings.font_file);
-        font_load(buf);
+                 global_settings.userfont1);
+        font_load(buf, FONT_USER1);
     }
     else
-        font_reset();
+        font_reset(FONT_USER1);
 
+    if ( global_settings.userfont2[0] &&
+         global_settings.userfont2[0] != 0xff ) {
+        snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                    global_settings.userfont2);
+        font_load(buf, FONT_USER2);
+    }
+    else
+        font_reset(FONT_USER2);
+
+    if ( global_settings.userfont3[0] &&
+         global_settings.userfont3[0] != 0xff ) {
+         snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                    global_settings.userfont3);
+        font_load(buf, FONT_USER3);
+    }
+    else
+        font_reset(FONT_USER3);
+
+    if ( global_settings.userfont4[0] &&
+         global_settings.userfont4[0] != 0xff ) {
+            snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                       global_settings.userfont4);
+        font_load(buf, FONT_USER4);
+    }
+    else
+        font_reset(FONT_USER4);
+
+    if ( global_settings.userfont5[0] &&
+         global_settings.userfont5[0] != 0xff ) {
+        snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                       global_settings.userfont5);
+        font_load(buf, FONT_USER5);
+    }
+    else
+        font_reset(FONT_USER5);
+
+    if ( global_settings.userfont6[0] &&
+         global_settings.userfont6[0] != 0xff ) {
+        snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                       global_settings.userfont6);
+        font_load(buf, FONT_USER6);
+    }
+    else
+        font_reset(FONT_USER6);
+
+    if ( global_settings.userfont7[0] &&
+         global_settings.userfont7[0] != 0xff ) {
+        snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
+                       global_settings.userfont7);
+        font_load(buf, FONT_USER7);
+     }
+     else
+        font_reset(FONT_USER7);
+
     if ( global_settings.kbd_file[0]) {
         snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.kbd",
                  global_settings.kbd_file);
@@ -945,7 +1118,7 @@
     if (global_settings.colors_file)
         read_color_theme_file();
 #endif
-
+    list_init_viewports();
 }
 
 
@@ -983,6 +1156,13 @@
 #if defined (HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
     enc_global_settings_reset();
 #endif
+    global_settings.userfont1[0] = '\0';
+    global_settings.userfont2[0] = '\0';
+    global_settings.userfont3[0] = '\0';
+    global_settings.userfont4[0] = '\0';
+    global_settings.userfont5[0] = '\0';
+    global_settings.userfont6[0] = '\0';
+    global_settings.userfont7[0] = '\0';
 }
 
 /** Changing setting values **/
@@ -1057,14 +1237,15 @@
 
 void set_file(char* filename, char* setting, int maxlen)
 {
-    char* fptr = strrchr(filename,'/');
+    char *fptr = strrchr(filename,'/');
     int len;
     int extlen = 0;
-    char* ptr;
+    char *ptr, *oldptr;
 
     if (!fptr)
         return;
 
+    oldptr = fptr;
     *fptr = 0;
     fptr++;
 
Index: apps/gui/buttonbar.c
===================================================================
--- apps/gui/buttonbar.c	(revision 16159)
+++ apps/gui/buttonbar.c	(working copy)
@@ -116,7 +116,8 @@
         gui_buttonbar_draw_button(buttonbar, i);
     display->update_rect(0, display->height - BUTTONBAR_HEIGHT,
                          display->width, BUTTONBAR_HEIGHT);
-    display->setfont(FONT_UI);
+    // MWE ?
+    display->setfont(FONT_BROWSER);
 }
 
 bool gui_buttonbar_isset(struct gui_buttonbar * buttonbar)
Index: apps/gui/gwps-common.c
===================================================================
--- apps/gui/gwps-common.c	(revision 16159)
+++ apps/gui/gwps-common.c	(working copy)
@@ -282,6 +282,7 @@
 bool gui_wps_display(void)
 {
     int i;
+
     if (!wps_state.id3 && !(audio_status() & AUDIO_STATUS_PLAY))
     {
         global_status.resume_index = -1;
@@ -295,6 +296,19 @@
     {
         FOR_NB_SCREENS(i)
         {
+            /* Update the values in the first (default) viewport - in case the user
+               has modified the statusbar or colour settings */
+#ifdef HAVE_LCD_BITMAP
+            gui_wps[i].data->viewports[0].vp.ymargin = gui_wps[i].display->getymargin();
+#if LCD_DEPTH > 1
+            if (gui_wps[i].display->depth > 1)
+            {
+                gui_wps[i].data->viewports[0].vp.fg_pattern = gui_wps[i].display->get_foreground();
+                gui_wps[i].data->viewports[0].vp.bg_pattern = gui_wps[i].display->get_background();
+            }
+#endif
+#endif
+
             gui_wps[i].display->clear_display();
             if (!gui_wps[i].data->wps_loaded) {
                 if ( !gui_wps[i].data->num_tokens ) {
@@ -306,6 +320,7 @@
                         unload_wps_backdrop();
 #endif
                         wps_data_load(gui_wps[i].data,
+                                      gui_wps[i].display,
                                       "%s%?it<%?in<%in. |>%it|%fn>\n"
                                       "%s%?ia<%ia|%?d2<%d2|(root)>>\n"
                                       "%s%?id<%id|%?d1<%d1|(root)>> %?iy<(%iy)|>\n"
@@ -316,6 +331,7 @@
                                       "%pm\n", false);
 #else
                         wps_data_load(gui_wps[i].data,
+                                      gui_wps[i].display,
                                       "%s%pp/%pe: %?it<%it|%fn> - %?ia<%ia|%d2> - %?id<%id|%d1>\n"
                                       "%pc%?ps<*|/>%pt\n", false);
 #endif
@@ -328,6 +344,7 @@
                          unload_remote_wps_backdrop();
 #endif
                          wps_data_load(gui_wps[i].data,
+                                       gui_wps[i].display,
                                        "%s%?ia<%ia|%?d2<%d2|(root)>>\n"
                                        "%s%?it<%?in<%in. |>%it|%fn>\n"
                                        "%al%pc/%pt%ar[%pp:%pe]\n"
@@ -448,7 +465,7 @@
     struct wps_data *data = gwps->data;
     struct screen *display = gwps->display;
     struct wps_state *state = gwps->state;
-    int h = font_get(FONT_UI)->height;
+    int h = font_get(FONT_WPS)->height;
 
     int sb_y;
     if (data->progress_top < 0)
@@ -459,7 +476,7 @@
         sb_y = data->progress_top;
 
     if (!data->progress_end)
-        data->progress_end=display->width;
+        data->progress_end=display->getwidth();
 
     if (gwps->data->progressbar.have_bitmap_pb)
         gui_bitmap_scrollbar_draw(display, data->progressbar.bm,
@@ -1449,7 +1466,7 @@
    The return value indicates whether the line needs to be updated.
 */
 static bool get_line(struct gui_wps *gwps,
-                     int line, int subline,
+                     int v, int line, int subline,
                      struct align_pos *align,
                      char *linebuf,
                      int linebuf_size)
@@ -1477,8 +1494,8 @@
 #endif
 
     /* Process all tokens of the desired subline */
-    last_token_idx = wps_last_token_index(data, line, subline);
-    for (i = wps_first_token_index(data, line, subline);
+    last_token_idx = wps_last_token_index(data, v, line, subline);
+    for (i = wps_first_token_index(data, v, line, subline);
          i <= last_token_idx; i++)
     {
         switch(data->tokens[i].type)
@@ -1577,16 +1594,16 @@
     return update;
 }
 
-static void get_subline_timeout(struct gui_wps *gwps, int line, int subline)
+static void get_subline_timeout(struct gui_wps *gwps, int v, int line, int subline)
 {
     struct wps_data *data = gwps->data;
     int i;
-    int subline_idx = wps_subline_index(data, line, subline);
-    int last_token_idx = wps_last_token_index(data, line, subline);
+    int subline_idx = wps_subline_index(data, v, line, subline);
+    int last_token_idx = wps_last_token_index(data, v, line, subline);
 
     data->sublines[subline_idx].time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER;
 
-    for (i = wps_first_token_index(data, line, subline);
+    for (i = wps_first_token_index(data, v, line, subline);
          i <= last_token_idx; i++)
     {
         switch(data->tokens[i].type)
@@ -1614,7 +1631,7 @@
 
 /* Calculates which subline should be displayed for the specified line
    Returns true iff the subline must be refreshed */
-static bool update_curr_subline(struct gui_wps *gwps, int line)
+static bool update_curr_subline(struct gui_wps *gwps, int v, int line)
 {
     struct wps_data *data = gwps->data;
 
@@ -1623,13 +1640,13 @@
     bool new_subline_refresh;
     bool only_one_subline;
 
-    num_sublines = data->lines[line].num_sublines;
-    reset_subline = (data->lines[line].curr_subline == SUBLINE_RESET);
+    num_sublines = data->viewports[v].lines[line].num_sublines;
+    reset_subline = (data->viewports[v].lines[line].curr_subline == SUBLINE_RESET);
     new_subline_refresh = false;
     only_one_subline = false;
 
     /* if time to advance to next sub-line  */
-    if (TIME_AFTER(current_tick, data->lines[line].subline_expire_time - 1) ||
+    if (TIME_AFTER(current_tick, data->viewports[v].lines[line].subline_expire_time - 1) ||
         reset_subline)
     {
         /* search all sublines until the next subline with time > 0
@@ -1637,46 +1654,46 @@
         if (reset_subline)
             search_start = 0;
         else
-            search_start = data->lines[line].curr_subline;
+            search_start = data->viewports[v].lines[line].curr_subline;
 
         for (search = 0; search < num_sublines; search++)
         {
-            data->lines[line].curr_subline++;
+            data->viewports[v].lines[line].curr_subline++;
 
             /* wrap around if beyond last defined subline or WPS_MAX_SUBLINES */
-            if (data->lines[line].curr_subline == num_sublines)
+            if (data->viewports[v].lines[line].curr_subline == num_sublines)
             {
-                if (data->lines[line].curr_subline == 1)
+                if (data->viewports[v].lines[line].curr_subline == 1)
                     only_one_subline = true;
-                data->lines[line].curr_subline = 0;
+                data->viewports[v].lines[line].curr_subline = 0;
             }
 
             /* if back where we started after search or
                 only one subline is defined on the line */
             if (((search > 0) &&
-                 (data->lines[line].curr_subline == search_start)) ||
+                 (data->viewports[v].lines[line].curr_subline == search_start)) ||
                 only_one_subline)
             {
                 /* no other subline with a time > 0 exists */
-                data->lines[line].subline_expire_time = (reset_subline ?
+                data->viewports[v].lines[line].subline_expire_time = (reset_subline ?
                     current_tick :
-                    data->lines[line].subline_expire_time) + 100 * HZ;
+                    data->viewports[v].lines[line].subline_expire_time) + 100 * HZ;
                 break;
             }
             else
             {
                 /* get initial time multiplier for this subline */
-                get_subline_timeout(gwps, line, data->lines[line].curr_subline);
+                get_subline_timeout(gwps, v, line, data->viewports[v].lines[line].curr_subline);
 
-                int subline_idx = wps_subline_index(data, line,
-                                               data->lines[line].curr_subline);
+                int subline_idx = wps_subline_index(data, v, line,
+                                               data->viewports[v].lines[line].curr_subline);
 
                 /* only use this subline if subline time > 0 */
                 if (data->sublines[subline_idx].time_mult > 0)
                 {
                     new_subline_refresh = true;
-                    data->lines[line].subline_expire_time = (reset_subline ?
-                        current_tick : data->lines[line].subline_expire_time) +
+                    data->viewports[v].lines[line].subline_expire_time = (reset_subline ?
+                        current_tick : data->viewports[v].lines[line].subline_expire_time) +
                         BASE_SUBLINE_TIME*data->sublines[subline_idx].time_mult;
                     break;
                 }
@@ -1697,7 +1714,6 @@
                        int line,
                        bool scroll)
 {
-
     int left_width = 0, left_xpos;
     int center_width = 0, center_xpos;
     int right_width = 0,  right_xpos;
@@ -1724,10 +1740,10 @@
     }
 
     left_xpos = display->getxmargin();
-    right_xpos = (display->width - right_width);
-    center_xpos = (display->width + left_xpos - center_width) / 2;
+    right_xpos = (display->getwidth() - right_width);
+    center_xpos = (display->getwidth() + left_xpos - center_width) / 2;
 
-    scroll_width = display->width - left_xpos;
+    scroll_width = display->getwidth() - left_xpos;
 
     /* Checks for overlapping strings.
         If needed the overlapping strings will be merged, separated by a
@@ -1767,7 +1783,7 @@
         format_align->right = format_align->center;
         /* calculate the new width and position of the merged string */
         right_width = center_width + space_width + right_width;
-        right_xpos = (display->width - right_width);
+        right_xpos = (display->getwidth() - right_width);
         /* there is no centered string anymore */
         center_width = 0;
     }
@@ -1778,7 +1794,7 @@
         format_align->right = format_align->center;
         /* calculate the new width and position of the string */
         right_width = center_width;
-        right_xpos = (display->width - right_width);
+        right_xpos = (display->getwidth() - right_width);
         /* there is no centered string anymore */
         center_width = 0;
     }
@@ -1823,7 +1839,7 @@
 #ifdef HAVE_LCD_BITMAP
         /* clear the line first */
         display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
-        display->fillrect(left_xpos, ypos, display->width, string_height);
+        display->fillrect(left_xpos, ypos, display->getwidth(), string_height);
         display->set_drawmode(DRMODE_SOLID);
 #endif
 
@@ -1862,7 +1878,7 @@
     if(!gwps || !data || !state || !display)
         return false;
 
-    int line, i, subline_idx;
+    int v, line, i, subline_idx;
     unsigned char flags;
     char linebuf[MAX_PATH];
 
@@ -1874,6 +1890,7 @@
     bool update_line, new_subline_refresh;
 
 #ifdef HAVE_LCD_BITMAP
+    display->setfont(FONT_WPS);
     gui_wps_statusbar_draw(gwps, true);
 
     /* to find out wether the peak meter is enabled we
@@ -1895,9 +1912,14 @@
     /* reset to first subline if refresh all flag is set */
     if (refresh_mode == WPS_REFRESH_ALL)
     {
-        for (i = 0; i < data->num_lines; i++)
+        display->clear_display();
+
+        for (v = 0; v < data->num_viewports; v++)
         {
-            data->lines[i].curr_subline = SUBLINE_RESET;
+            for (i = 0; i < data->viewports[v].num_lines; i++)
+            {
+                data->viewports[v].lines[i].curr_subline = SUBLINE_RESET;
+            }
         }
     }
 
@@ -1917,83 +1939,91 @@
 
     state->ff_rewind_count = ffwd_offset;
 
-    for (line = 0; line < data->num_lines; line++)
+    for (v = 0; v < data->num_viewports; v++)
     {
-        memset(linebuf, 0, sizeof(linebuf));
-        update_line = false;
+        display->set_viewport(&data->viewports[v].vp);
 
-        /* get current subline for the line */
-        new_subline_refresh = update_curr_subline(gwps, line);
+        for (line = 0; line < data->viewports[v].num_lines; line++)
+        {
+            memset(linebuf, 0, sizeof(linebuf));
+            update_line = false;
 
-        subline_idx = wps_subline_index(data, line,
-                                        data->lines[line].curr_subline);
-        flags = data->sublines[subline_idx].line_type;
+            /* get current subline for the line */
+            new_subline_refresh = update_curr_subline(gwps, v, line);
 
-        if (refresh_mode == WPS_REFRESH_ALL || (flags & refresh_mode)
-            || new_subline_refresh)
-        {
-            /* get_line tells us if we need to update the line */
-            update_line = get_line(gwps, line, data->lines[line].curr_subline,
-                                   &align, linebuf, sizeof(linebuf));
-        }
+            subline_idx = wps_subline_index(data, v, line,
+                                            data->viewports[v].lines[line].curr_subline);
+            flags = data->sublines[subline_idx].line_type;
 
+            if (refresh_mode == WPS_REFRESH_ALL || (flags & refresh_mode)
+                || new_subline_refresh)
+            {
+                /* get_line tells us if we need to update the line */
+                update_line = get_line(gwps, v, line, data->viewports[v].lines[line].curr_subline,
+                                       &align, linebuf, sizeof(linebuf));
+            }
+
 #ifdef HAVE_LCD_BITMAP
-        /* progressbar */
-        if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS)
-        {
-            /* the progressbar should be alone on its line */
-            update_line = false;
-            draw_progressbar(gwps, line);
-        }
+            /* progressbar */
+            if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS)
+            {
+                /* the progressbar should be alone on its line */
+                update_line = false;
+                draw_progressbar(gwps, line);
+            }
 
-        /* peakmeter */
-        if (flags & refresh_mode & WPS_REFRESH_PEAK_METER)
-        {
-            /* the peakmeter should be alone on its line */
-            update_line = false;
+            /* peakmeter */
+            if (flags & refresh_mode & WPS_REFRESH_PEAK_METER)
+            {
+                /* the peakmeter should be alone on its line */
+                update_line = false;
 
-            int h = font_get(FONT_UI)->height;
-            int peak_meter_y = display->getymargin() + line * h;
+                int h = font_get(FONT_WPS)->height;
+                int peak_meter_y = display->getymargin() + line * h;
 
-            /* The user might decide to have the peak meter in the last
-                line so that it is only displayed if no status bar is
-                visible. If so we neither want do draw nor enable the
-                peak meter. */
-            if (peak_meter_y + h <= display->height) {
-                /* found a line with a peak meter -> remember that we must
-                    enable it later */
-                enable_pm = true;
-                peak_meter_screen(gwps->display, 0, peak_meter_y,
-                                  MIN(h, display->height - peak_meter_y));
+                /* The user might decide to have the peak meter in the last
+                    line so that it is only displayed if no status bar is
+                    visible. If so we neither want do draw nor enable the
+                    peak meter. */
+                if (peak_meter_y + h <= display->getheight()) {
+                    /* found a line with a peak meter -> remember that we must
+                        enable it later */
+                    enable_pm = true;
+                    peak_meter_screen(gwps->display, 0, peak_meter_y,
+                                      MIN(h, display->getheight() - peak_meter_y));
+                }
             }
-        }
 
 #else /* HAVE_LCD_CHARCELL */
 
-        /* progressbar */
-        if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS)
-        {
-            if (data->full_line_progressbar)
-                draw_player_fullbar(gwps, linebuf, sizeof(linebuf));
-            else
-                draw_player_progress(gwps);
-        }
+            /* progressbar */
+            if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS)
+            {
+                if (data->full_line_progressbar)
+                    draw_player_fullbar(gwps, linebuf, sizeof(linebuf));
+                else
+                    draw_player_progress(gwps);
+            }
 #endif
 
-        if (update_line)
-        {
-            if (flags & WPS_REFRESH_SCROLL)
+            if (update_line)
             {
-                /* if the line is a scrolling one we don't want to update
-                   too often, so that it has the time to scroll */
-                if ((refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh)
-                    write_line(display, &align, line, true);
+                if (flags & WPS_REFRESH_SCROLL)
+                {
+                    /* if the line is a scrolling one we don't want to update
+                       too often, so that it has the time to scroll */
+                    if ((refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh)
+                        write_line(display, &align, line, true);
+                }
+                else
+                    write_line(display, &align, line, false);
             }
-            else
-                write_line(display, &align, line, false);
         }
     }
 
+    /* Restore the default viewport for the images */
+    display->set_viewport(NULL);
+
 #ifdef HAVE_LCD_BITMAP
     data->peak_meter_enabled = enable_pm;
     wps_display_images(gwps);
Index: apps/gui/statusbar.c
===================================================================
--- apps/gui/statusbar.c	(revision 16159)
+++ apps/gui/statusbar.c	(working copy)
@@ -380,6 +380,7 @@
 #if LCD_DEPTH > 1
     unsigned int prevfg = 0;
 #endif
+    int oldfont;
 
 #if CONFIG_CHARGING
     if (batt_charge_step >= 0)
@@ -405,15 +406,19 @@
     if (global_settings.battery_display && (percent > -1)) {
 #endif
         /* Numeric display */
+        snprintf(buffer, sizeof(buffer), "%3d", percent);
+
+         /* remember to set back if font changed */ 
+        oldfont=display->getfont();
+
         display->setfont(FONT_SYSFIXED);
-        snprintf(buffer, sizeof(buffer), "%3d", percent);
         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);
-
+        /* set back previous font */
+        display->setfont(oldfont);
     }
     else {
         /* draw battery */
@@ -439,10 +444,14 @@
     }
 
     if (percent == -1) {
+         /* remember to set back if font changed */ 
+        oldfont=display->getfont();
+
         display->setfont(FONT_SYSFIXED);
         display->putsxy(STATUSBAR_BATTERY_X_POS + STATUSBAR_BATTERY_WIDTH / 2
                          - 4, STATUSBAR_Y_POS, "?");
-        display->setfont(FONT_UI);
+        /* set back previous font */
+        display->setfont(oldfont);
     }
 }
 
@@ -487,8 +496,11 @@
         /* display volume level numerical? */
         if (type)
         {
+            snprintf(buffer, sizeof(buffer), "%2d", volume);
+            /* remember to set back if font changed */ 
+            int oldFont=display->getfont();
+
             display->setfont(FONT_SYSFIXED);
-            snprintf(buffer, sizeof(buffer), "%2d", volume);
             display->getstringsize(buffer, &width, &height);
             if (height <= STATUSBAR_HEIGHT)
             {
@@ -496,7 +508,7 @@
                                  + STATUSBAR_VOLUME_WIDTH / 2
                                  - width/2, STATUSBAR_Y_POS, buffer);
             }
-            display->setfont(FONT_UI);
+            display->setfont(oldFont);
         } else {
             /* display volume bar */
             vol = (volume - minvol) * 14 / (maxvol - minvol);
@@ -600,13 +612,16 @@
     else {
         strncpy(buffer, "--:--", sizeof buffer);
     }
+    /* remember to set back if font changed */ 
+    int oldfont=display->getfont();
+    
     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);
+    display->setfont(oldfont);
 
 }
 #endif
@@ -709,6 +724,9 @@
 
 static void gui_statusbar_icon_recording_info(struct screen * display)
 {
+    /* remember to set back if font changed */ 
+    int oldfont=display->getfont();
+
 #if CONFIG_CODEC != SWCODEC
     char buffer[3];
     int width, height;
@@ -771,6 +789,7 @@
                              STATUSBAR_RECCHANNELS_X_POS, STATUSBAR_Y_POS,
                              STATUSBAR_RECCHANNELS_WIDTH, STATUSBAR_HEIGHT);
     }
+    display->setfont(oldfont);
 }
 #endif /* HAVE_RECORDING */
 
Index: apps/gui/list.c
===================================================================
--- apps/gui/list.c	(revision 16159)
+++ apps/gui/list.c	(working copy)
@@ -37,6 +37,7 @@
 #include "sound.h"
 #include "misc.h"
 #include "talk.h"
+#include "viewport.h"
 
 #ifdef HAVE_LCD_CHARCELLS
 #define SCROLL_LIMIT 1
@@ -56,12 +57,136 @@
 #endif
 static struct gui_synclist* last_list_displayed;
 
-#define SHOW_LIST_TITLE ((gui_list->title != NULL) && \
-                         (display->nb_lines > 2))
-
 static void gui_list_select_at_offset(struct gui_synclist * gui_list,
                                       int offset);
+void list_draw(struct screen *display, struct viewport *parent, struct gui_synclist *list);
 
+#ifdef HAVE_LCD_BITMAP
+static struct viewport parent[NB_SCREENS] =
+{
+    [SCREEN_MAIN] = {
+        .x        = 0,
+        .y        = 8,
+        .width    = LCD_WIDTH,
+        .height   = (LCD_HEIGHT-8),
+        .font     = FONT_MENU,
+        .drawmode = DRMODE_SOLID,
+        .xmargin  = 0,
+        .ymargin  = 0,
+#if LCD_DEPTH > 1
+        .fg_pattern = LCD_DEFAULT_FG,
+        .bg_pattern = LCD_DEFAULT_BG,
+#ifdef HAVE_LCD_COLOR
+        .lss_pattern = LCD_DEFAULT_BG,
+        .lse_pattern = LCD_DEFAULT_BG,
+        .lst_pattern = LCD_DEFAULT_BG,
+#endif
+#endif
+        },
+#if NB_SCREENS >1
+    [SCREEN_REMOTE] = {
+        .x        = 0,
+        .y        = 8,
+        .width    = LCD_REMOTE_WIDTH,
+        .height   = (LCD_REMOTE_HEIGHT-8),
+        .font     = FONT_MENU,
+        .drawmode = DRMODE_SOLID,
+        .xmargin  = 0,
+        .ymargin  = 0,
+        .fg_pattern = LCD_DEFAULT_FG,
+        .bg_pattern = LCD_DEFAULT_BG,
+    }
+#endif
+};
+void list_init_viewports(void)
+{
+    struct viewport *vp;
+    vp = &parent[SCREEN_MAIN];
+    vp->x = 0;
+    vp->width = LCD_WIDTH;
+    if (!global_settings.statusbar)
+    {
+        vp->y = 0;
+        vp->height = LCD_HEIGHT
+#ifdef HAS_BUTTONBAR
+                     - BUTTONBAR_HEIGHT
+#endif
+        ;
+    }
+    else
+    {
+        vp->y = STATUSBAR_HEIGHT;
+        vp->height = LCD_HEIGHT - STATUSBAR_HEIGHT
+#ifdef HAS_BUTTONBAR
+                     - BUTTONBAR_HEIGHT
+#endif
+        ;
+    }
+    vp->drawmode = STYLE_DEFAULT;
+
+#ifdef HAVE_LCD_COLOR
+    vp->fg_pattern = global_settings.fg_color;
+    vp->bg_pattern = global_settings.bg_color;
+    vp->lss_pattern = global_settings.lss_color;
+    vp->lse_pattern = global_settings.lse_color;
+    vp->lst_pattern = global_settings.lst_color;
+#endif
+    if (global_settings.list_vp_file[0])
+    {
+        char filename[MAX_PATH];
+        snprintf(filename, MAX_PATH, "%s/%s.vp",
+                 THEME_DIR, global_settings.list_vp_file);
+        viewport_load_config(filename, vp);
+    }
+#if NB_SCREENS > 1
+    vp = &parent[SCREEN_REMOTE];
+    vp->x = 0;
+    vp->width = LCD_REMOTE_WIDTH;
+    if (!global_settings.statusbar)
+    {
+        vp->y = 0;
+        vp->height = LCD_REMOTE_HEIGHT;
+    }
+    else
+    {
+        vp->y = STATUSBAR_HEIGHT;
+        vp->height = LCD_REMOTE_HEIGHT - STATUSBAR_HEIGHT;
+    }
+    vp->drawmode = STYLE_DEFAULT;
+    if (global_settings.remote_list_vp_file[0])
+    {
+        char filename[MAX_PATH];
+        snprintf(filename, MAX_PATH, "%s/%s.vp",
+                 THEME_DIR, global_settings.remote_list_vp_file);
+        viewport_load_config(filename, vp);
+    }
+#endif
+}
+#else
+static struct viewport parent[NB_SCREENS] =
+{
+    [SCREEN_MAIN] = 
+    {
+        .x        = 0,
+        .y        = 0,
+        .width    = LCD_WIDTH,
+        .height   = LCD_HEIGHT
+    },
+};
+void list_init_viewports(void)
+{
+}
+#endif
+
+#ifdef HAVE_LCD_BITMAP
+bool list_display_title(struct gui_synclist *list, struct viewport *vp)
+{
+    return list->title != NULL && viewport_get_nb_lines(vp)>2;
+}
+#else
+#define list_display_title(l,v) false
+#endif
+
 /*
  * Initializes a scrolling list
  *  - gui_list : the list structure to initialize
@@ -82,7 +207,7 @@
     gui_list->callback_get_item_icon = NULL;
     gui_list->callback_get_item_name = callback_get_item_name;
     gui_list->callback_speak_item = NULL;
-    gui_list_set_nb_items(gui_list, 0);
+    gui_list->nb_items = 0;
     gui_list->selected_item = 0;
     FOR_NB_SCREENS(i)
     {
@@ -91,6 +216,7 @@
 #ifdef HAVE_LCD_BITMAP
         gui_list->offset_position[i] = 0;
 #endif
+        gui_list->parent[i] = &parent[i];
     }
     gui_list->limit_scroll = false;
     gui_list->data=data;
@@ -118,8 +244,10 @@
 
 
 #ifdef HAVE_LCD_BITMAP
-static int gui_list_get_item_offset(struct gui_synclist * gui_list, int item_width,
-                             int text_pos, struct screen * display)
+int list_title_height(struct gui_synclist *list, struct viewport *vp);
+
+int gui_list_get_item_offset(struct gui_synclist * gui_list, int item_width,
+                             int text_pos, struct screen * display, struct viewport *vp)
 {
     int item_offset;
 
@@ -130,7 +258,7 @@
     else
     {
         /* if text is smaller then view */
-        if (item_width <= display->width - text_pos)
+        if (item_width <= vp->width - text_pos)
         {
             item_offset = 0;
         }
@@ -138,8 +266,8 @@
         {
             /* if text got out of view  */
             if (gui_list->offset_position[display->screen_type] >
-                    item_width - (display->width - text_pos))
-                item_offset = item_width - (display->width - text_pos);
+                    item_width - (vp->width - text_pos))
+                item_offset = item_width - (vp->width - text_pos);
             else
                 item_offset = gui_list->offset_position[display->screen_type];
         }
@@ -148,341 +276,32 @@
     return item_offset;
 }
 #endif
-
 /*
- * Draws the list on the attached screen
- * - gui_list : the list structure
- */
-static void gui_list_draw_smart(struct gui_synclist *gui_list, struct screen * display)
-{
-    int text_pos;
-    bool draw_icons = (gui_list->callback_get_item_icon != NULL && global_settings.show_icons);
-    bool draw_cursor;
-    int i;
-    int lines;
-    static int last_lines[NB_SCREENS] = {0};
-#ifdef HAVE_LCD_BITMAP
-    int item_offset;
-    int old_margin = display->getxmargin();
-#endif
-    int start, end;
-    bool partial_draw = false;
-
-#ifdef HAVE_LCD_BITMAP
-    display->setfont(FONT_UI);
-    gui_textarea_update_nblines(display);
-#endif
-    /* Speed up UI by drawing the changed contents only. */
-    if (gui_list == last_list_displayed
-        && gui_list->last_displayed_start_item[display->screen_type] == gui_list->start_item[display->screen_type]
-        && gui_list->selected_size == 1)
-    {
-        partial_draw = true;
-    }
-
-    lines = display->nb_lines - SHOW_LIST_TITLE;
-    if (last_lines[display->screen_type] != lines)
-    {
-        gui_list_select_at_offset(gui_list, 0);
-        last_lines[display->screen_type] = lines;
-    }
-
-    if (partial_draw)
-    {
-        end = gui_list->last_displayed_selected_item - gui_list->start_item[display->screen_type];
-        i = gui_list->selected_item - gui_list->start_item[display->screen_type];
-        if (i < end )
-        {
-            start = i;
-            end++;
-        }
-        else
-        {
-            start = end;
-            end = i + 1;
-        }
-    }
-    else
-    {
-        gui_textarea_clear(display);
-        start = 0;
-        end = display->nb_lines;
-        gui_list->last_displayed_start_item[display->screen_type] = gui_list->start_item[display->screen_type];
-        last_list_displayed = gui_list;
-    }
-
-    gui_list->last_displayed_selected_item = gui_list->selected_item;
-
-    /* position and draw the list title & icon */
-    if (SHOW_LIST_TITLE && !partial_draw)
-    {
-        if (gui_list->title_icon != NOICON && draw_icons)
-        {
-            screen_put_icon(display, 0, 0, gui_list->title_icon);
-#ifdef HAVE_LCD_BITMAP
-            text_pos = get_icon_width(display->screen_type)+2; /* pixels */
-#else
-            text_pos = 1; /* chars */
-#endif
-        }
-        else
-        {
-            text_pos = 0;
-        }
-
-#ifdef HAVE_LCD_BITMAP
-        int title_style = STYLE_DEFAULT;
-#ifdef HAVE_LCD_COLOR
-        if (gui_list->title_color >= 0)
-        {
-            title_style |= STYLE_COLORED;
-            title_style |= gui_list->title_color;
-        }
-#endif
-        screen_set_xmargin(display, text_pos); /* margin for title */
-        item_offset = gui_list_get_item_offset(gui_list, gui_list->title_width,
-                                               text_pos, display);
-        if (item_offset > gui_list->title_width - (display->width - text_pos))
-            display->puts_style_offset(0, 0, gui_list->title,
-                                       title_style, item_offset);
-        else
-            display->puts_scroll_style_offset(0, 0, gui_list->title,
-                                              title_style, item_offset);
-#else
-        display->puts_scroll(text_pos, 0, gui_list->title);
-#endif
-    }
-
-    /* Adjust the position of icon, cursor, text for the list */
-#ifdef HAVE_LCD_BITMAP
-    gui_textarea_update_nblines(display);
-    bool draw_scrollbar;
-
-    draw_scrollbar = (global_settings.scrollbar &&
-                lines < gui_list->nb_items);
-
-    draw_cursor = !global_settings.cursor_style &&
-                    gui_list->show_selection_marker;
-    text_pos = 0; /* here it's in pixels */
-    if(draw_scrollbar || SHOW_LIST_TITLE) /* indent if there's
-                                             a title */
-    {
-        text_pos += SCROLLBAR_WIDTH;
-    }
-    if(draw_cursor)
-        text_pos += get_icon_width(display->screen_type) + 2;
-
-    if(draw_icons)
-        text_pos += get_icon_width(display->screen_type) + 2;
-#else
-    draw_cursor = true;
-    if(draw_icons)
-        text_pos = 2; /* here it's in chars */
-    else
-        text_pos = 1;
-#endif
-
-#ifdef HAVE_LCD_BITMAP
-    screen_set_xmargin(display, text_pos); /* margin for list */
-#endif
-
-    if (SHOW_LIST_TITLE)
-    {
-        start++;
-        if (end < display->nb_lines)
-            end++;
-    }
-
-#ifdef HAVE_LCD_COLOR
-    unsigned char cur_line = 0;
-#endif
-    for (i = start; i < end; i++)
-    {
-        unsigned char *s;
-        char entry_buffer[MAX_PATH];
-        unsigned char *entry_name;
-        int current_item = gui_list->start_item[display->screen_type] +
-                           (SHOW_LIST_TITLE ? i-1 : 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;
-        s = gui_list->callback_get_item_name(current_item,
-                                             gui_list->data,
-                                             entry_buffer);
-        entry_name = P2STR(s);
-
-#ifdef HAVE_LCD_BITMAP
-        int style = STYLE_DEFAULT;
-        /* position the string at the correct offset place */
-        int item_width,h;
-        display->getstringsize(entry_name, &item_width, &h);
-        item_offset = gui_list_get_item_offset(gui_list, item_width,
-                                               text_pos, display);
-#endif
-
-#ifdef HAVE_LCD_COLOR
-        /* if the list has a color callback */
-        if (gui_list->callback_get_item_color)
-        {
-            int color = gui_list->callback_get_item_color(current_item,
-                                                          gui_list->data);
-            /* if color selected */
-            if (color >= 0)
-            {
-                style |= STYLE_COLORED;
-                style |= color;
-            }
-        }
-#endif
-
-        if(gui_list->show_selection_marker &&
-           current_item >= gui_list->selected_item &&
-           current_item <  gui_list->selected_item + gui_list->selected_size)
-        {/* The selected item must be displayed scrolling */
-#ifdef HAVE_LCD_BITMAP
-            if (global_settings.cursor_style == 1
-#ifdef HAVE_REMOTE_LCD
-                || display->screen_type == SCREEN_REMOTE
-#endif
-               )
-            {
-                /* Display inverted-line-style */
-                style |= STYLE_INVERT;
-            }
-#ifdef HAVE_LCD_COLOR
-            else if (global_settings.cursor_style == 2)
-            {
-                /* Display colour line selector */
-                style |= STYLE_COLORBAR;
-            }
-            else if (global_settings.cursor_style == 3)
-            {
-                /* Display gradient line selector */
-                style = STYLE_GRADIENT;
-
-                /* Make the lcd driver know how many lines the gradient should
-                   cover and current line number */
-                /* number of selected lines */
-                style |= NUMLN_PACK(gui_list->selected_size);
-                /* current line number, zero based */
-                style |= CURLN_PACK(cur_line);
-                cur_line++;
-            }
-#endif
-            else  /*  if (!global_settings.cursor_style) */
-            {
-                if (current_item % gui_list->selected_size != 0)
-                    draw_cursor = false;
-            }
-            /* if the text is smaller than the viewport size */
-            if (item_offset > item_width - (display->width - text_pos))
-            {
-                /* don't scroll */
-                display->puts_style_offset(0, i, entry_name,
-                                           style, item_offset);
-            }
-            else
-            {
-                display->puts_scroll_style_offset(0, i, entry_name,
-                                                  style, item_offset);
-            }
-#else
-            display->puts_scroll(text_pos, i, entry_name);
-#endif
-
-            if (draw_cursor)
-            {
-                screen_put_icon_with_offset(display, 0, i,
-                                           (draw_scrollbar || SHOW_LIST_TITLE)?
-                                                   SCROLLBAR_WIDTH: 0,
-                                           0, Icon_Cursor);
-            }
-        }
-        else
-        {/* normal item */
-            if(gui_list->scroll_all)
-            {
-#ifdef HAVE_LCD_BITMAP
-                display->puts_scroll_style_offset(0, i, entry_name,
-                                                  style, item_offset);
-#else
-                display->puts_scroll(text_pos, i, entry_name);
-#endif
-            }
-            else
-            {
-#ifdef HAVE_LCD_BITMAP
-                display->puts_style_offset(0, i, entry_name,
-                                           style, item_offset);
-#else
-                display->puts(text_pos, i, entry_name);
-#endif
-            }
-        }
-        /* Icons display */
-        if(draw_icons)
-        {
-            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
-            }
-        }
-    }
-
-#ifdef HAVE_LCD_BITMAP
-    /* Draw the scrollbar if needed*/
-    if(draw_scrollbar)
-    {
-        int y_start = gui_textarea_get_ystart(display);
-        if (SHOW_LIST_TITLE)
-            y_start += display->char_height;
-        int scrollbar_y_end = display->char_height *
-                              lines + y_start;
-        gui_scrollbar_draw(display, 0, y_start, SCROLLBAR_WIDTH-1,
-                           scrollbar_y_end - y_start, gui_list->nb_items,
-                           gui_list->start_item[display->screen_type],
-                           gui_list->start_item[display->screen_type] + lines, VERTICAL);
-    }
-
-    screen_set_xmargin(display, old_margin);
-#endif
-
-    gui_textarea_update(display);
-}
-
-/*
  * Force a full screen update.
  */
+ 
 void gui_synclist_draw(struct gui_synclist *gui_list)
 {
     int i;
     FOR_NB_SCREENS(i)
     {
         last_list_displayed = NULL;
-        gui_list_draw_smart(gui_list, &screens[i]);
+        list_draw(&screens[i], gui_list->parent[i], gui_list);
     }
 }
 
-
-
 /* sets up the list so the selection is shown correctly on the screen */
 static void gui_list_put_selection_on_screen(struct gui_synclist * gui_list,
                                              enum screen_type screen)
 {
-    struct screen *display = &screens[screen];
-    int nb_lines = display->nb_lines - SHOW_LIST_TITLE;
+    int nb_lines;
     int difference = gui_list->selected_item - gui_list->start_item[screen];
+    struct viewport vp = *gui_list->parent[screen];
+#ifndef HVE_LCD_CHARCELL
+    if (list_display_title(gui_list, gui_list->parent[screen]))
+        vp.height -= list_title_height(gui_list,gui_list->parent[screen]);
+#endif
+    nb_lines = viewport_get_nb_lines(&vp);
     
     /* edge case,, selected last item */
     if (gui_list->selected_item == gui_list->nb_items -1)
@@ -576,8 +395,12 @@
         int i, nb_lines, screen_top;
         FOR_NB_SCREENS(i)
         {
-            struct screen *display = &screens[i];
-            nb_lines = display->nb_lines - SHOW_LIST_TITLE;
+            struct viewport vp = *gui_list->parent[i];
+#ifndef HVE_LCD_CHARCELL
+            if (list_display_title(gui_list, gui_list->parent[i]))
+                vp.height -= list_title_height(gui_list,gui_list->parent[i]);
+#endif
+            nb_lines = viewport_get_nb_lines(&vp);
             if (offset > 0)
             {
                 screen_top = gui_list->nb_items-nb_lines;
@@ -616,23 +439,12 @@
  */
 void gui_synclist_del_item(struct gui_synclist * gui_list)
 {
-    int i;
     if(gui_list->nb_items > 0)
     {
         if (gui_list->selected_item == gui_list->nb_items-1)
             gui_list->selected_item--;
-        FOR_NB_SCREENS(i)
-        {
-            gui_textarea_update_nblines(&screens[i]);
-            int nb_lines = screens[i].nb_lines;
-            int dist_start_from_end = gui_list->nb_items
-                - gui_list->start_item[i] - 1;
-
-            /* scroll the list if needed */
-            if( (dist_start_from_end < nb_lines) && (gui_list->start_item[i] != 0) )
-                gui_list->start_item[i]--;
-        }
         gui_list->nb_items--;
+        gui_synclist_select_item(gui_list, gui_list->selected_item);
     }
 }
 
@@ -707,6 +519,14 @@
     lists->callback_speak_item = voice_callback;
 }
 
+#ifdef HAVE_LCD_COLOR
+void gui_synclist_set_color_callback(struct gui_synclist * lists,
+                                    list_get_color color_callback)
+{
+    lists->callback_get_item_color = color_callback;
+}
+#endif
+
 static void gui_synclist_select_next_page(struct gui_synclist * lists,
                                    enum screen_type screen)
 {
Index: apps/gui/color_picker.c
===================================================================
--- apps/gui/color_picker.c	(revision 16159)
+++ apps/gui/color_picker.c	(working copy)
@@ -268,6 +268,7 @@
     } /* end for */
 
     /* Draw color value in system font */
+    int oldFont=display->getfont();
     display->setfont(FONT_SYSFIXED);
 
     /* Format RGB: #rrggbb */
@@ -320,7 +321,7 @@
         }
     }
 
-    display->setfont(FONT_UI);
+    display->setfont(oldFont);
 
     display->update();
     /* Be sure screen mode is reset */
Index: apps/gui/quickscreen.c
===================================================================
--- apps/gui/quickscreen.c	(revision 16159)
+++ apps/gui/quickscreen.c	(working copy)
@@ -61,6 +61,8 @@
     if (display->height / display->char_height < 7) /* we need at leats 7 lines */
     {
         display->setfont(FONT_SYSFIXED);
+    } else {
+        display->setfont(FONT_MENU);
     }
     display->getstringsize("A", NULL, &font_h);
 
Index: apps/gui/wps_debug.c
===================================================================
--- apps/gui/wps_debug.c	(revision 16159)
+++ apps/gui/wps_debug.c	(working copy)
@@ -493,40 +493,51 @@
 
 static void print_line_info(struct wps_data *data)
 {
-    int i, j;
+    int i, j, v;
     struct wps_line *line;
     struct wps_subline *subline;
 
     if (wps_verbose_level > 0)
     {
-        DEBUGF("Number of lines   : %d\n", data->num_lines);
-        DEBUGF("Number of sublines: %d\n", data->num_sublines);
-        DEBUGF("Number of tokens  : %d\n", data->num_tokens);
+        DEBUGF("Number of viewports : %d\n", data->num_viewports);
+        for (v = 0; v < data->num_viewports; v++)
+        {
+            DEBUGF("vp %d: Number of lines: %d\n", v, data->viewports[v].num_lines);
+        }
+        DEBUGF("Number of sublines  : %d\n", data->num_sublines);
+        DEBUGF("Number of tokens    : %d\n", data->num_tokens);
         DEBUGF("\n");
     }
 
     if (wps_verbose_level > 1)
     {
-        for (i = 0, line = data->lines; i < data->num_lines; i++,line++)
+        for (v = 0; v < data->num_viewports; v++)
         {
-            DEBUGF("Line %2d (num_sublines=%d, first_subline=%d)\n",
-                   i, line->num_sublines, line->first_subline_idx);
-
-            for (j = 0, subline = data->sublines + line->first_subline_idx;
-                 j < line->num_sublines; j++, subline++)
+            DEBUGF("Viewport %d - +%d+%d (%dx%d)\n",v,data->viewports[v].vp.x, 
+                                                      data->viewports[v].vp.y,
+                                                      data->viewports[v].vp.width,
+                                                      data->viewports[v].vp.height);
+            for (i = 0, line = data->viewports[v].lines; i < data->viewports[v].num_lines; i++,line++)
             {
-                DEBUGF("    Subline %d: first_token=%3d, last_token=%3d",
-                       j, subline->first_token_idx,
-                       wps_last_token_index(data, i, j));
+                DEBUGF("Line %2d (num_sublines=%d, first_subline=%d)\n",
+                       i, line->num_sublines, line->first_subline_idx);
 
-                if (subline->line_type & WPS_REFRESH_SCROLL)
-                    DEBUGF(", scrolled");
-                else if (subline->line_type & WPS_REFRESH_PLAYER_PROGRESS)
-                    DEBUGF(", progressbar");
-                else if (subline->line_type & WPS_REFRESH_PEAK_METER)
-                    DEBUGF(", peakmeter");
+                for (j = 0, subline = data->sublines + line->first_subline_idx;
+                     j < line->num_sublines; j++, subline++)
+                {
+                    DEBUGF("    Subline %d: first_token=%3d, last_token=%3d",
+                           j, subline->first_token_idx,
+                           wps_last_token_index(data, v, i, j));
 
-                DEBUGF("\n");
+                    if (subline->line_type & WPS_REFRESH_SCROLL)
+                        DEBUGF(", scrolled");
+                    else if (subline->line_type & WPS_REFRESH_PLAYER_PROGRESS)
+                        DEBUGF(", progressbar");
+                    else if (subline->line_type & WPS_REFRESH_PEAK_METER)
+                        DEBUGF(", peakmeter");
+
+                    DEBUGF("\n");
+                }
             }
         }
 
Index: apps/gui/list.h
===================================================================
--- apps/gui/list.h	(revision 16159)
+++ apps/gui/list.h	(working copy)
@@ -123,59 +123,10 @@
     int title_color;
     list_get_color *callback_get_item_color;
 #endif
+    struct viewport *parent[NB_SCREENS];
 };
 
-/*
- * Sets the numbers 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
- *  - nb_items : the numbers of items you want
- */
-#define gui_list_set_nb_items(gui_list, nb) \
-    (gui_list)->nb_items = nb
 
-/*
- * Returns the numbers of items currently in the list
- *  - gui_list : the list structure
- */
-#define gui_list_get_nb_items(gui_list) \
-    (gui_list)->nb_items
-
-/*
- * Sets the icon callback function
- *  - gui_list : the list structure
- *  - _callback : the callback function
- */
-#define gui_list_set_icon_callback(gui_list, _callback) \
-    (gui_list)->callback_get_item_icon=_callback
-
-/*
- * Sets the voice callback function
- *  - gui_list : the list structure
- *  - _callback : the callback function
- */
-#define gui_list_set_voice_callback(gui_list, _callback) \
-    (gui_list)->callback_speak_item=_callback
-
-#ifdef HAVE_LCD_COLOR
-/*
- * Sets the color callback function
- *  - gui_list : the list structure
- *  - _callback : the callback function
- */
-#define gui_list_set_color_callback(gui_list, _callback) \
-    (gui_list)->callback_get_item_color=_callback
-#endif
-
-/*
- * Gives the position of the selected item
- *  - gui_list : the list structure
- * Returns the position
- */
-#define gui_list_get_sel_pos(gui_list) \
-    (gui_list)->selected_item
-
-
 #ifdef HAVE_LCD_BITMAP
 /* parse global setting to static int */
 extern void gui_list_screen_scroll_step(int ofs);
@@ -183,17 +134,8 @@
 /* parse global setting to static bool */
 extern void gui_list_screen_scroll_out_of_view(bool enable);
 #endif /* HAVE_LCD_BITMAP */
-/*
- * Tells the list wether it should stop when reaching the top/bottom
- * or should continue (by going to bottom/top)
- * - gui_list : the list structure
- * - scroll :
- *    - true : stops when reaching top/bottom
- *    - false : continues to go to bottom/top when reaching top/bottom
- */
-#define gui_list_limit_scroll(gui_list, scroll) \
-    (gui_list)->limit_scroll=scroll
 
+void list_init_viewports(void);
 
 extern void gui_synclist_init(
     struct gui_synclist * lists,
@@ -205,6 +147,9 @@
 extern void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items);
 extern void gui_synclist_set_icon_callback(struct gui_synclist * lists, list_get_icon icon_callback);
 extern void gui_synclist_set_voice_callback(struct gui_synclist * lists, list_speak_item voice_callback);
+#ifdef HAVE_LCD_COLOR
+extern void gui_synclist_set_color_callback(struct gui_synclist * lists, list_get_color color_callback);
+#endif
 extern void gui_synclist_speak_item(struct gui_synclist * lists);
 extern int gui_synclist_get_nb_items(struct gui_synclist * lists);
 
Index: apps/gui/gwps.c
===================================================================
--- apps/gui/gwps.c	(revision 16159)
+++ apps/gui/gwps.c	(working copy)
@@ -92,6 +92,11 @@
 }
 #endif
 
+static void gui_wps_set_font(struct gui_wps *gwps)
+{
+    gwps->display->setfont(FONT_WPS);
+}
+
 long gui_wps_show(void)
 {
     long button = 0;
@@ -105,6 +110,12 @@
     
     wps_state_init();
 
+    /* Set WPS display font */
+    FOR_NB_SCREENS(i)
+    {
+        gui_wps_set_font(&gui_wps[i]);
+    }
+
 #ifdef HAVE_LCD_CHARCELLS
     status_set_audio(true);
     status_set_param(false);
Index: apps/gui/gwps.h
===================================================================
--- apps/gui/gwps.h	(revision 16159)
+++ apps/gui/gwps.h	(working copy)
@@ -86,6 +86,7 @@
 #define IMG_BUFSIZE ((LCD_HEIGHT*LCD_WIDTH*LCD_DEPTH/8) \
                    + (2*LCD_HEIGHT*LCD_WIDTH/8))
 
+#define WPS_MAX_VIEWPORTS   16
 #define WPS_MAX_LINES       (LCD_HEIGHT/5+1)
 #define WPS_MAX_SUBLINES    (WPS_MAX_LINES*3)
 #define WPS_MAX_TOKENS      1024
@@ -95,6 +96,7 @@
 
 #else
 
+#define WPS_MAX_VIEWPORTS   2
 #define WPS_MAX_LINES       2
 #define WPS_MAX_SUBLINES    12
 #define WPS_MAX_TOKENS      64
@@ -315,7 +317,15 @@
     long subline_expire_time;
 };
 
+struct wps_viewport {
+    struct viewport vp;   /* The LCD viewport struct */
 
+    /* Number of lines in this viewport. During WPS parsing, this is
+       the index of the line being parsed. */
+    int num_lines;
+    struct wps_line lines[WPS_MAX_LINES];
+};
+
 /* wps_data
    this struct holds all necessary data which describes the
    viewable content of a wps */
@@ -360,10 +370,9 @@
     bool remote_wps;
 #endif
 
-    /* Number of lines in the WPS. During WPS parsing, this is
-       the index of the line being parsed. */
-    int num_lines;
-    struct wps_line lines[WPS_MAX_LINES];
+    /* Number of viewports in the WPS */
+    int num_viewports;
+    struct wps_viewport viewports[WPS_MAX_VIEWPORTS];
 
     /* Total number of sublines in the WPS. During WPS parsing, this is
        the index of the subline where the parsed tokens are added to. */
@@ -388,26 +397,30 @@
 /* to setup up the wps-data from a format-buffer (isfile = false)
    from a (wps-)file (isfile = true)*/
 bool wps_data_load(struct wps_data *wps_data,
+                   struct screen *display,
                    const char *buf,
                    bool isfile);
 
 /* Returns the index of the subline in the subline array
+   v - 0-based viewport number
    line - 0-based line number
    subline - 0-based subline number within the line
  */
-int wps_subline_index(struct wps_data *wps_data, int line, int subline);
+int wps_subline_index(struct wps_data *wps_data, int v, int line, int subline);
 
 /* Returns the index of the first subline's token in the token array
+   v - 0-based viewport number
    line - 0-based line number
    subline - 0-based subline number within the line
  */
-int wps_first_token_index(struct wps_data *data, int line, int subline);
+int wps_first_token_index(struct wps_data *data, int v, int line, int subline);
 
 /* Returns the index of the last subline's token in the token array.
+   v - 0-based viewport number
    line - 0-based line number
    subline - 0-based subline number within the line
  */
-int wps_last_token_index(struct wps_data *data, int line, int subline);
+int wps_last_token_index(struct wps_data *data, int v, int line, int subline);
 
 /* wps_data end */
 
Index: apps/gui/backdrop.c
===================================================================
--- apps/gui/backdrop.c	(revision 16159)
+++ apps/gui/backdrop.c	(working copy)
@@ -50,7 +50,9 @@
     /* load the image */
     bm.data=(char*)backdrop_buffer;
     ret = read_bmp_file(filename, &bm, sizeof(main_backdrop),
-                        FORMAT_NATIVE | FORMAT_DITHER);
+                        FORMAT_NATIVE | FORMAT_DITHER,
+                        LCD_WIDTH, LCD_HEIGHT,
+                        BMP_RESIZE_INCREASE | BMP_RESIZE_DECREASE);
 
     if ((ret > 0) && (bm.width == LCD_WIDTH) && (bm.height == LCD_HEIGHT))
     {
@@ -112,7 +114,9 @@
     /* load the image */
     bm.data=(char*)backdrop_buffer;
     ret = read_bmp_file(filename, &bm, sizeof(main_backdrop),
-                        FORMAT_NATIVE | FORMAT_DITHER | FORMAT_REMOTE);
+                        FORMAT_NATIVE | FORMAT_DITHER | FORMAT_REMOTE,
+                        LCD_WIDTH, LCD_HEIGHT,
+                        BMP_RESIZE_INCREASE | BMP_RESIZE_DECREASE);
 
     if ((ret > 0) && (bm.width == LCD_REMOTE_WIDTH) && (bm.height == LCD_REMOTE_HEIGHT))
     {
Index: apps/gui/wps_parser.c
===================================================================
--- apps/gui/wps_parser.c	(revision 16159)
+++ apps/gui/wps_parser.c	(working copy)
@@ -118,6 +118,8 @@
         struct wps_token *token, struct wps_data *wps_data);
 
 #ifdef HAVE_LCD_BITMAP
+static int parse_viewport(const char *wps_bufptr,
+        struct wps_token *token, struct wps_data *wps_data);
 static int parse_leftmargin(const char *wps_bufptr,
         struct wps_token *token, struct wps_data *wps_data);
 static int parse_image_special(const char *wps_bufptr,
@@ -131,7 +133,6 @@
 static int parse_image_load(const char *wps_bufptr,
         struct wps_token *token, struct wps_data *wps_data);
 #endif /*HAVE_LCD_BITMAP */
-
 #ifdef HAVE_ALBUMART
 static int parse_albumart_load(const char *wps_bufptr,
         struct wps_token *token, struct wps_data *wps_data);
@@ -311,6 +312,9 @@
     { WPS_TOKEN_ALBUMART_DISPLAY,         "C",   WPS_REFRESH_STATIC,
                                                 parse_albumart_conditional },
 #endif
+
+    { WPS_NO_TOKEN,                       "V",   0,    parse_viewport      },
+
 #if (LCD_DEPTH > 1) || (defined(HAVE_LCD_REMOTE) && (LCD_REMOTE_DEPTH > 1))
     { WPS_TOKEN_IMAGE_BACKDROP,           "X",   0,    parse_image_special },
 #endif
@@ -334,9 +338,11 @@
 /* Starts a new subline in the current line during parsing */
 static void wps_start_new_subline(struct wps_data *data)
 {
+    struct wps_viewport* vp = &data->viewports[data->num_viewports];
+
     data->num_sublines++;
     data->sublines[data->num_sublines].first_token_idx = data->num_tokens;
-    data->lines[data->num_lines].num_sublines++;
+    vp->lines[vp->num_lines].num_sublines++;
 }
 
 #ifdef HAVE_LCD_BITMAP
@@ -375,7 +381,9 @@
 
     int ret = read_bmp_file(filename, bm,
                             wps_data->img_buf_free,
-                            format);
+                            format,
+                            0,0,
+                            BMP_RESIZE_NONE);
 
     if (ret > 0)
     {
@@ -506,6 +514,150 @@
     return skip_end_of_line(wps_bufptr);
 }
 
+static int parse_viewport(const char *wps_bufptr,
+                          struct wps_token *token,
+                          struct wps_data *wps_data)
+{
+    const char *ptr = wps_bufptr;
+    const char *pos = NULL;
+    const char *newline;
+    struct viewport* vp;
+#if LCD_DEPTH > 2
+    char hexbuf[7];
+#endif
+    int i;
+    int tmp[5];
+    int depth;
+
+    (void)token; /* Kill warnings */
+
+    /* format: %V|x|y|width|height|fg_pattern|bg_pattern| */
+
+    if (wps_data->num_viewports >= WPS_MAX_VIEWPORTS)
+        return WPS_ERROR_INVALID_PARAM;
+
+    wps_data->num_viewports++;
+    vp = &wps_data->viewports[wps_data->num_viewports].vp;
+
+    /* Set the defaults for fields not user-specified */
+    vp->drawmode = DRMODE_SOLID;
+    vp->xmargin  = 0;
+    vp->ymargin  = 0;
+
+    ptr = strchr(ptr, '|') + 1;
+    pos = strchr(ptr, '|');
+    newline = strchr(ptr, '\n');
+
+    if (!pos || pos > newline)
+        return 0;
+
+    /* Parse 5 integers */
+    for (i=0; i< 5 ; i++)
+    {
+        pos = strchr(ptr, '|');
+        if (pos && pos < newline)
+            tmp[i] = atoi(ptr);
+        else
+            return WPS_ERROR_INVALID_PARAM;
+        ptr = pos + 1;
+    }
+
+    vp->x = tmp[0];
+    vp->y = tmp[1];
+    vp->width = tmp[2];
+    vp->height = tmp[3];
+    vp->font = tmp[4];
+
+    switch (vp->font){
+        case 0:
+            vp->font = FONT_SYSFIXED;
+            break;
+        case 1:
+            vp->font = FONT_WPS;
+            break;
+        case 2:
+            vp->font = FONT_USER1;
+            break;
+        case 3:
+            vp->font = FONT_USER2;
+            break;
+        case 4:
+            vp->font = FONT_USER3;
+            break;
+        case 5:
+            vp->font = FONT_USER4;
+            break;
+        case 6:
+            vp->font = FONT_USER5;
+            break;
+        case 7:
+            vp->font = FONT_USER6;
+            break;
+        case 8:
+            vp->font = FONT_USER7;
+            break;
+        default:
+            vp->font = FONT_WPS;
+            break;
+    }
+
+    /* TODO - try and make the following code simpler... */
+
+    /* Work out the depth of this display */
+#ifdef HAVE_REMOTE_LCD
+    if (wps_data->remote_wps)
+      depth = LCD_REMOTE_DEPTH;
+    else
+      depth = LCD_DEPTH;
+#else
+    depth = LCD_DEPTH;
+#endif
+
+#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
+    if (depth > 1)
+    {
+        /* Get 2 colours */
+        for (i = 0; i < 2 ; i++)
+        {
+            /* get fg_pattern */
+            pos = strchr(ptr, '|');
+            if (pos && pos < newline)
+            {
+#if LCD_DEPTH > 2
+                if (depth > 2) 
+                {
+                    snprintf(hexbuf,7,"%s",ptr);
+                    tmp[i] = hex_to_rgb(hexbuf);
+                }
+                else
+#endif
+                    tmp[i] = atoi(ptr);
+            }
+            else
+                return WPS_ERROR_INVALID_PARAM;
+            ptr = pos + 1;
+        }
+
+        vp->fg_pattern = tmp[0];
+        vp->bg_pattern = tmp[1];
+    }
+#endif
+
+    wps_data->viewports[wps_data->num_viewports].num_lines = 0;
+
+    if (wps_data->num_sublines < WPS_MAX_SUBLINES)
+    {
+        wps_data->viewports[wps_data->num_viewports].lines[0].first_subline_idx =
+            wps_data->num_sublines;
+
+        wps_data->sublines[wps_data->num_sublines].first_token_idx =
+            wps_data->num_tokens;
+    }
+
+    /* Skip the rest of the line */
+    return skip_end_of_line(wps_bufptr);
+}
+
 static int parse_image_special(const char *wps_bufptr,
                                struct wps_token *token,
                                struct wps_data *wps_data)
@@ -975,7 +1127,8 @@
     level = -1;
 
     while(*wps_bufptr && !fail && data->num_tokens < WPS_MAX_TOKENS - 1
-          && data->num_lines < WPS_MAX_LINES)
+          && data->num_viewports < WPS_MAX_VIEWPORTS 
+          && data->viewports[data->num_viewports].num_lines < WPS_MAX_LINES)
     {
         switch(*wps_bufptr++)
         {
@@ -1083,12 +1236,12 @@
 
                 line++;
                 wps_start_new_subline(data);
-                data->num_lines++; /* Start a new line */
+                data->viewports[data->num_viewports].num_lines++; /* Start a new line */
 
-                if ((data->num_lines < WPS_MAX_LINES) &&
+                if ((data->viewports[data->num_viewports].num_lines < WPS_MAX_LINES) &&
                     (data->num_sublines < WPS_MAX_SUBLINES))
                 {
-                    data->lines[data->num_lines].first_subline_idx =
+                    data->viewports[data->num_viewports].lines[data->viewports[data->num_viewports].num_lines].first_subline_idx =
                         data->num_sublines;
 
                     data->sublines[data->num_sublines].first_token_idx =
@@ -1165,6 +1318,9 @@
     if (!fail && level >= 0) /* there are unclosed conditionals */
         fail = PARSE_FAIL_UNCLOSED_COND;
 
+    /* We have finished with the last viewport, so increment count */
+    data->num_viewports++;
+
 #ifdef DEBUG
     print_debug_info(data, fail, line);
 #endif
@@ -1308,6 +1464,7 @@
 /* to setup up the wps-data from a format-buffer (isfile = false)
    from a (wps-)file (isfile = true)*/
 bool wps_data_load(struct wps_data *wps_data,
+                   struct screen *display,
                    const char *buf,
                    bool isfile)
 {
@@ -1316,6 +1473,24 @@
 
     wps_reset(wps_data);
 
+    /* Initialise the first (default) viewport */
+    wps_data->viewports[0].vp.x          = 0;
+    wps_data->viewports[0].vp.y          = 0;
+    wps_data->viewports[0].vp.width      = display->width;
+    wps_data->viewports[0].vp.height     = display->height;
+#ifdef HAVE_LCD_BITMAP
+    wps_data->viewports[0].vp.font       = FONT_WPS;
+    wps_data->viewports[0].vp.drawmode   = DRMODE_SOLID;
+#endif
+    wps_data->viewports[0].vp.xmargin    = display->getxmargin();
+    wps_data->viewports[0].vp.ymargin    = display->getymargin();
+#if LCD_DEPTH > 1
+    if (display->depth > 1)
+    {
+        wps_data->viewports[0].vp.fg_pattern = display->get_foreground();
+        wps_data->viewports[0].vp.bg_pattern = display->get_background();
+    }
+#endif
     if (!isfile)
     {
         return wps_parse(wps_data, buf);
@@ -1402,20 +1577,20 @@
     }
 }
 
-int wps_subline_index(struct wps_data *data, int line, int subline)
+int wps_subline_index(struct wps_data *data, int v, int line, int subline)
 {
-    return data->lines[line].first_subline_idx + subline;
+    return data->viewports[v].lines[line].first_subline_idx + subline;
 }
 
-int wps_first_token_index(struct wps_data *data, int line, int subline)
+int wps_first_token_index(struct wps_data *data, int v, int line, int subline)
 {
-    int first_subline_idx = data->lines[line].first_subline_idx;
+    int first_subline_idx = data->viewports[v].lines[line].first_subline_idx;
     return data->sublines[first_subline_idx + subline].first_token_idx;
 }
 
-int wps_last_token_index(struct wps_data *data, int line, int subline)
+int wps_last_token_index(struct wps_data *data, int v, int line, int subline)
 {
-    int first_subline_idx = data->lines[line].first_subline_idx;
+    int first_subline_idx = data->viewports[v].lines[line].first_subline_idx;
     int idx = first_subline_idx + subline;
     if (idx < data->num_sublines - 1)
     {
Index: apps/gui/icon.c
===================================================================
--- apps/gui/icon.c	(revision 16159)
+++ apps/gui/icon.c	(working copy)
@@ -220,7 +220,9 @@
         char path[MAX_PATH];
         
         snprintf(path, sizeof(path), "%s/%s.bmp", ICON_DIR, filename);
-        size_read = read_bmp_file(path, bmp, IMG_BUFSIZE, bmpformat);
+        size_read = read_bmp_file(path, bmp, IMG_BUFSIZE, bmpformat,
+                                  0, 0,
+                                  BMP_RESIZE_NONE);
         if (size_read > 0)
         {
             *loaded_ok = true;
Index: apps/gui/splash.c
===================================================================
--- apps/gui/splash.c	(revision 16159)
+++ apps/gui/splash.c	(working copy)
@@ -25,6 +25,7 @@
 #include "lang.h"
 #include "settings.h"
 #include "talk.h"
+#include "font.h"
 
 #ifndef MAX
 #define MAX(a, b) (((a)>(b))?(a):(b))
@@ -57,10 +58,12 @@
     int space_w, w, h;
 #ifdef HAVE_LCD_BITMAP
     int maxw = 0;
+    int oldFont=screen->getfont();
 #if LCD_DEPTH > 1
     unsigned prevfg = 0;
 #endif
 
+    screen->setfont(FONT_MENU);
     screen->getstringsize(" ", &space_w, &h);
 #else /* HAVE_LCD_CHARCELLS */
 
@@ -75,8 +78,12 @@
     /* break splash string into display lines, doing proper word wrap */
 
     next = strtok_r(splash_buf, " ", &store);
-    if (!next)
+    if (!next){
+#ifdef HAVE_LCD_BITMAP
+        screen->setfont(oldFont);
+#endif
         return;  /* nothing to display */
+    }
 
     lines[0] = next;
     while (true)
@@ -127,6 +134,7 @@
     screen->stop_scroll();
 
 #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! */
     y = (screen->height - y) / 2;  /* height => y start position */
@@ -180,6 +188,7 @@
         screen->set_foreground(prevfg);
         screen->set_drawmode(DRMODE_SOLID);
     }
+    screen->setfont(oldFont);
 #endif
     screen->update();
 }
Index: apps/gui/yesno.c
===================================================================
--- apps/gui/yesno.c	(revision 16159)
+++ apps/gui/yesno.c	(working copy)
@@ -24,6 +24,7 @@
 #include "lang.h"
 #include "action.h"
 #include "talk.h"
+#include "font.h"
 
 /*
  * Initializes the yesno asker
@@ -111,8 +112,13 @@
     bool result_displayed;
     struct gui_yesno yn[NB_SCREENS];
     long talked_tick = 0;
+    int old_font[NB_SCREENS];
     FOR_NB_SCREENS(i)
     {
+#ifdef HAVE_LCD_BITMAP
+        old_font[i]=screens[i].getfont();
+        screens[i].setfont(FONT_MENU);
+#endif
         gui_yesno_init(&(yn[i]), main_message, yes_message, no_message);
         gui_yesno_set_display(&(yn[i]), &(screens[i]));
         gui_yesno_draw(&(yn[i]));
@@ -137,8 +143,15 @@
                 /* ignore some SYS events that can happen */
                 continue;
             default:
-                if(default_event_handler(button) == SYS_USB_CONNECTED)
+                if(default_event_handler(button) == SYS_USB_CONNECTED){
+#ifdef HAVE_LCD_BITMAP
+                    FOR_NB_SCREENS(i)
+                    {
+                        screens[i].setfont(old_font[i]);
+                    }
+#endif
                     return(YESNO_USB);
+                }
                 result = YESNO_NO;
         }
     }
@@ -154,5 +167,13 @@
     }
     if(result_displayed)
         sleep(HZ);
+
+#ifdef HAVE_LCD_BITMAP
+    FOR_NB_SCREENS(i)
+    {
+        screens[i].setfont(old_font[i]);
+    }
+#endif
+
     return(result);
 }
Index: apps/settings.h
===================================================================
--- apps/settings.h	(revision 16159)
+++ apps/settings.h	(working copy)
@@ -416,9 +416,32 @@
 #if CONFIG_TUNER
     unsigned char fmr_file[MAX_FILENAME+1]; /* last fmr preset */
 #endif
-    unsigned char font_file[MAX_FILENAME+1]; /* last font */
+    unsigned char font_file[MAX_FILENAME+1]; /* backward comp */
+
+    unsigned char browserfont[MAX_FILENAME+1]; /* UI fonts */
+    unsigned char wpsfont[MAX_FILENAME+1];
+    unsigned char menufont[MAX_FILENAME+1];
+#ifdef CONFIG_TUNER
+    unsigned char tunerfont[MAX_FILENAME+1];
+#endif
+#ifdef HAVE_RECORDING
+    unsigned char recordfont[MAX_FILENAME+1];
+#endif
+
+    unsigned char userfont1[MAX_FILENAME+1];
+    unsigned char userfont2[MAX_FILENAME+1];
+    unsigned char userfont3[MAX_FILENAME+1];
+    unsigned char userfont4[MAX_FILENAME+1];
+    unsigned char userfont5[MAX_FILENAME+1];
+    unsigned char userfont6[MAX_FILENAME+1];
+    unsigned char userfont7[MAX_FILENAME+1];
+
     unsigned char wps_file[MAX_FILENAME+1];  /* last wps */
     unsigned char lang_file[MAX_FILENAME+1]; /* last language */
+    unsigned char list_vp_file[MAX_FILENAME+1]; /* viewport file for the lists */
+#ifdef HAVE_REMOTE_LCD
+    unsigned char remote_list_vp_file[MAX_FILENAME+1]; /* viewport file for the lists */
+#endif
 
     /* misc options */
 
Index: apps/menus/playlist_menu.c
===================================================================
--- apps/menus/playlist_menu.c	(revision 16159)
+++ apps/menus/playlist_menu.c	(working copy)
@@ -50,7 +50,12 @@
         strcat(temp, "8");
     
     if (len <= 5 || strcasecmp(&temp[len-5], ".m3u8"))
-        strcpy(temp, DEFAULT_DYNAM