Remote WPS support (and some WPS bugfixes) by Stephan Wezel


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7934 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/SOURCES b/apps/SOURCES
index 2d32156..67e09ed 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -29,8 +29,6 @@
 dbtree.c
 database.c
 filetree.c
-wps-display.c
-wps.c
 
 screen_access.c
 gui/buttonbar.c
@@ -40,6 +38,8 @@
 gui/select.c
 gui/splash.c
 gui/statusbar.c
+gui/gwps.c
+gui/gwps-common.c
 gui/textarea.c
 
 #ifdef HAVE_LCD_CHARCELLS
diff --git a/apps/bookmark.c b/apps/bookmark.c
index 788aebe..c42f466 100644
--- a/apps/bookmark.c
+++ b/apps/bookmark.c
@@ -27,7 +27,7 @@
 #include "button.h"
 #include "usb.h"
 #include "audio.h"
-#include "wps.h"
+#include "playlist.h"
 #include "settings.h"
 #include "tree.h"
 #include "bookmark.h"
diff --git a/apps/database.c b/apps/database.c
index 6d74ce8..97fb2d7 100644
--- a/apps/database.c
+++ b/apps/database.c
@@ -35,7 +35,6 @@
 #include "mpeg.h"
 #include "misc.h"
 #include "ata.h"
-#include "wps.h"
 #include "filetypes.h"
 #include "applimits.h"
 #include "icons.h"
diff --git a/apps/dbtree.c b/apps/dbtree.c
index 9115c59..b8a4c47 100644
--- a/apps/dbtree.c
+++ b/apps/dbtree.c
@@ -35,7 +35,7 @@
 #include "mpeg.h"
 #include "misc.h"
 #include "ata.h"
-#include "wps.h"
+#include "playlist.h"
 #include "filetypes.h"
 #include "applimits.h"
 #include "dbtree.h"
diff --git a/apps/filetree.c b/apps/filetree.c
index a9670e1..6855d3e 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -31,7 +31,7 @@
 #include "filetypes.h"
 #include "talk.h"
 #include "playlist.h"
-#include "wps-display.h"
+#include "gwps.h"
 #include "lang.h"
 #include "language.h"
 #include "screens.h"
@@ -273,6 +273,9 @@
              (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_M3U) ||
             (*c->dirfilter == SHOW_SUPPORTED && !filetype_supported(dptr->attr)))) ||
             (*c->dirfilter == SHOW_WPS && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_WPS) ||
+#ifdef HAVE_REMOTE_LCD
+            (*c->dirfilter == SHOW_RWPS && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_RWPS) ||
+#endif
             (*c->dirfilter == SHOW_CFG && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_CFG) ||
             (*c->dirfilter == SHOW_LNG && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_LNG) ||
             (*c->dirfilter == SHOW_MOD && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_MOD) ||
@@ -381,11 +384,20 @@
 
                 /* wps config file */
             case TREE_ATTR_WPS:
-                wps_load(buf,true);
+                wps_data_load(gui_syncwps.gui_wps[0].data, buf, true, true);
                 set_file(buf, global_settings.wps_file,
                          MAX_FILENAME);
                 break;
 
+#ifdef HAVE_REMOTE_LCD
+                /* remote-wps config file */
+            case TREE_ATTR_RWPS:
+                wps_data_load(gui_syncwps.gui_wps[1].data, buf, true, true);
+                set_file(buf, global_settings.rwps_file,
+                         MAX_FILENAME);
+                break;
+#endif
+
             case TREE_ATTR_CFG:
                 if (!settings_load_config(buf))
                     break;
diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c
index efc74d5..d279c22 100644
--- a/apps/gui/statusbar.c
+++ b/apps/gui/statusbar.c
@@ -34,7 +34,7 @@
 #include "led.h"
 
 #include "status.h" /* needed for battery_state global var */
-#include "wps.h" /* for keys_locked */
+#include "gwps.h" /* for keys_locked */
 #include "statusbar.h"
 
 
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index d601f71..469e4cb 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3437,3 +3437,15 @@
 voice: 
 new:
 
+id: VOICE_EXT_RWPS
+desc: spoken only, for file extension
+eng: ""
+voice: "remote while-playing-screen"
+new:
+
+id: LANG_REMOTE_WHILE_PLAYING
+desc: in settings_menu()
+eng: "Browse .rwps files"
+voice: "Browse remote while-playing-screen files"
+new:
+
diff --git a/apps/main.c b/apps/main.c
index ab802d5..d84aa25 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -49,7 +49,7 @@
 #include "sprintf.h"
 #include "font.h"
 #include "language.h"
-#include "wps-display.h"
+#include "gwps.h"
 #include "playlist.h"
 #include "buffer.h"
 #include "rolo.h"
@@ -138,6 +138,8 @@
     settings_reset();
     settings_calc_config_sector();
     settings_load(SETTINGS_ALL);
+    gui_sync_data_wps_init();
+    gui_sync_wps_init();
     settings_apply();
     init_dircache();
     sleep(HZ/2);
@@ -295,7 +297,8 @@
     settings_calc_config_sector();
     settings_load(SETTINGS_ALL);
     init_dircache();
-    
+    gui_sync_data_wps_init();
+    gui_sync_wps_init();
     settings_apply();
 
     status_init();
diff --git a/apps/onplay.c b/apps/onplay.c
index 36ea957..704e0c0 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -46,7 +46,6 @@
 #include "filetypes.h"
 #include "plugin.h"
 #include "bookmark.h"
-#include "wps.h"
 #include "action.h"
 #include "splash.h"
 #ifdef HAVE_LCD_BITMAP
diff --git a/apps/playback.c b/apps/playback.c
index b68cb64..6a944c9 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -34,8 +34,6 @@
 #include "sprintf.h"
 #include "settings.h"
 #include "codecs.h"
-#include "wps.h"
-#include "wps-display.h"
 #include "audio.h"
 #include "logf.h"
 #include "mp3_playback.h"
diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c
index 2e4cea0..a93e20a 100644
--- a/apps/recorder/peakmeter.c
+++ b/apps/recorder/peakmeter.c
@@ -24,7 +24,7 @@
 #include "ata.h"
 #include "lcd.h"
 #include "widgets.h"
-#include "wps-display.h"
+#include "gwps.h"
 #include "sprintf.h"
 #include "button.h"
 #include "system.h"
diff --git a/apps/screen_access.c b/apps/screen_access.c
index dfaba4d..b1ae9eb 100644
--- a/apps/screen_access.c
+++ b/apps/screen_access.c
@@ -123,6 +123,8 @@
             screen->height=2;
             screen->double_height=&lcd_double_height;
             screen->putc=&lcd_putc;
+            screen->get_locked_pattern=&lcd_get_locked_pattern;
+            screen->define_pattern=&lcd_define_pattern;
 #ifdef SIMULATOR
             screen->icon=&sim_lcd_icon;
 #else
diff --git a/apps/screen_access.h b/apps/screen_access.h
index 6111de9..95ddcb9 100644
--- a/apps/screen_access.h
+++ b/apps/screen_access.h
@@ -99,6 +99,8 @@
     void (*scroll_delay)(int ms);
     void (*stop_scroll)(void);
     void (*clear_display)(void);
+    unsigned char (*get_locked_pattern)(void);
+    void (*define_pattern)(int pat, const char *pattern);
 #if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR)
     void (*update)(void);
 #endif
diff --git a/apps/screens.c b/apps/screens.c
index 978d2a1..f861bb7 100644
--- a/apps/screens.c
+++ b/apps/screens.c
@@ -46,7 +46,7 @@
 #include "led.h"
 #include "sound.h"
 #include "abrepeat.h"
-#include "wps-display.h"
+#include "gwps-common.h"
 #include "splash.h"
 #if defined(HAVE_LCD_BITMAP)
 #include "widgets.h"
@@ -1226,7 +1226,7 @@
 
         line = draw_id3_item(line, top, LANG_ID3_YEAR, body);
 
-        wps_format_time(buf, sizeof(buf), id3->length);
+        gui_wps_format_time(buf, sizeof(buf), id3->length);
         line = draw_id3_item(line, top, LANG_ID3_LENGHT, buf);
 
         snprintf(buf, sizeof(buf), "%d/%d", playlist_get_display_index(),
diff --git a/apps/settings.c b/apps/settings.c
index 63da47e..2e5014f 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -59,7 +59,7 @@
 #endif
 #include "lang.h"
 #include "language.h"
-#include "wps-display.h"
+#include "gwps.h"
 #include "powermgmt.h"
 #include "bookmark.h"
 #include "sprintf.h"
@@ -85,7 +85,7 @@
 #include "dsp.h"
 #endif
 
-#define CONFIG_BLOCK_VERSION 31
+#define CONFIG_BLOCK_VERSION 32
 #define CONFIG_BLOCK_SIZE 512
 #define RTC_BLOCK_SIZE 44
 
@@ -758,10 +758,16 @@
     strncpy(&config_block[0xb8], global_settings.wps_file, MAX_FILENAME);
     strncpy(&config_block[0xcc], global_settings.lang_file, MAX_FILENAME);
     strncpy(&config_block[0xe0], global_settings.font_file, MAX_FILENAME);
+#ifdef HAVE_REMOTE_LCD
+    strncpy(&config_block[0xf4], global_settings.rwps_file, MAX_FILENAME);
+#endif
 
     if(save_config_buffer())
     {
         lcd_clear_display();
+#ifdef HAVE_REMOTE_LCD
+        lcd_remote_clear_display();
+#endif
 #ifdef HAVE_LCD_CHARCELLS
         lcd_puts(0, 0, str(LANG_SETTINGS_SAVE_PLAYER));
         lcd_puts(0, 1, str(LANG_SETTINGS_BATTERY_PLAYER));
@@ -769,6 +775,11 @@
         lcd_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
         lcd_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
         lcd_update();
+#ifdef HAVE_REMOTE_LCD
+        lcd_remote_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
+        lcd_remote_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
+        lcd_remote_update();
+#endif
 #endif
         sleep(HZ*2);
         return -1;
@@ -879,10 +890,21 @@
          global_settings.wps_file[0] != 0xff ) {
         snprintf(buf, sizeof buf, WPS_DIR "/%s.wps",
                  global_settings.wps_file);
-        wps_load(buf, false);
+        wps_data_load(gui_syncwps.gui_wps[0].data, buf, true, false);
     }
     else
-        wps_reset();
+        wps_data_init(gui_syncwps.gui_wps[0].data);
+
+#ifdef HAVE_REMOTE_LCD
+    if ( global_settings.rwps_file[0] &&
+         global_settings.rwps_file[0] != 0xff ) {
+        snprintf(buf, sizeof buf, WPS_DIR "/%s.rwps",
+                 global_settings.rwps_file);
+        wps_data_load(gui_syncwps.gui_wps[1].data, buf, true, false);
+    }
+    else
+        wps_data_init(gui_syncwps.gui_wps[1].data);
+#endif
 
 #ifdef HAVE_LCD_BITMAP
     if ( global_settings.font_file[0] &&
@@ -1003,6 +1025,9 @@
         strncpy(global_settings.wps_file, &config_block[0xb8], MAX_FILENAME);
         strncpy(global_settings.lang_file, &config_block[0xcc], MAX_FILENAME);
         strncpy(global_settings.font_file, &config_block[0xe0], MAX_FILENAME);
+#ifdef HAVE_REMOTE_LCD
+        strncpy(global_settings.rwps_file, &config_block[0xf4], MAX_FILENAME);
+#endif
     }
 }
 
@@ -1141,9 +1166,15 @@
 
         /* check for the string values */
         if (!strcasecmp(name, "wps")) {
-            if (wps_load(value,false))
+            if (wps_data_load(gui_syncwps.gui_wps[0].data,value,true, false))
                 set_file(value, global_settings.wps_file, MAX_FILENAME);
         }
+#ifdef HAVE_REMOTE_LCD
+        else if (!strcasecmp(name, "rwps")) {
+            if (wps_data_load(gui_syncwps.gui_wps[1].data,value,true, false))
+                set_file(value, global_settings.rwps_file, MAX_FILENAME);
+        }
+#endif
         else if (!strcasecmp(name, "lang")) {
             if (!lang_load(value))
             {
@@ -1283,6 +1314,12 @@
         fdprintf(fd, "wps: %s/%s.wps\r\n", WPS_DIR,
                  global_settings.wps_file);
 
+#ifdef HAVE_REMOTE_LCD
+    if (global_settings.rwps_file[0] != 0)
+        fdprintf(fd, "rwps: %s/%s.rwps\r\n", WPS_DIR,
+                 global_settings.rwps_file);
+#endif
+
     if (global_settings.lang_file[0] != 0)
         fdprintf(fd, "lang: %s/%s.lng\r\n", ROCKBOX_DIR LANG_DIR,
                  global_settings.lang_file);
@@ -1365,6 +1402,9 @@
 #endif
     global_settings.contrast    = lcd_default_contrast();
     global_settings.wps_file[0] = '\0';
+#ifdef HAVE_REMOTE_LCD
+    global_settings.rwps_file[0] = '\0';
+#endif
     global_settings.font_file[0] = '\0';
     global_settings.lang_file[0] = '\0';
 
diff --git a/apps/settings.h b/apps/settings.h
index 50f38ca..20b0408 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -359,6 +359,9 @@
     bool dircache;          /* enable directory cache */
     int dircache_size;      /* directory cache structure last size, 22 bits */
 #endif
+#ifdef HAVE_REMOTE_LCD
+    unsigned char rwps_file[MAX_FILENAME+1];  /* last remote-wps */
+#endif
 };
 
 enum optiontype { INT, BOOL };
@@ -443,7 +446,7 @@
  *       must be added after NUM_FILTER_MODES. */
 enum { SHOW_ALL, SHOW_SUPPORTED, SHOW_MUSIC, SHOW_PLAYLIST, SHOW_ID3DB,
        NUM_FILTER_MODES,
-       SHOW_WPS, SHOW_CFG, SHOW_LNG, SHOW_MOD, SHOW_FONT, SHOW_PLUGINS};
+       SHOW_WPS, SHOW_RWPS, SHOW_CFG, SHOW_LNG, SHOW_MOD, SHOW_FONT, SHOW_PLUGINS};
 
 /* recursive dir insert options */
 enum { RECURSE_OFF, RECURSE_ON, RECURSE_ASK };
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 4aea853..8695177 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -996,6 +996,13 @@
     return rockbox_browse(WPS_DIR, SHOW_WPS);
 }
 
+#ifdef HAVE_REMOTE_LCD
+static bool custom_remote_wps_browse(void)
+{
+    return rockbox_browse(WPS_DIR, SHOW_RWPS);
+}
+#endif
+
 static bool custom_cfg_browse(void)
 {
     return rockbox_browse(ROCKBOX_DIR, SHOW_CFG);
@@ -1602,6 +1609,9 @@
         { ID2P(LANG_CUSTOM_FONT),     font_browse },
 #endif
         { ID2P(LANG_WHILE_PLAYING),   custom_wps_browse },
+#ifdef HAVE_REMOTE_LCD
+        { ID2P(LANG_REMOTE_WHILE_PLAYING),   custom_remote_wps_browse },
+#endif
         { ID2P(LANG_LCD_MENU),        lcd_settings_menu },
 #ifdef HAVE_REMOTE_LCD
         { ID2P(LANG_LCD_REMOTE_MENU), lcd_remote_settings_menu },
diff --git a/apps/status.c b/apps/status.c
index 9f43c65..978341d 100644
--- a/apps/status.c
+++ b/apps/status.c
@@ -26,7 +26,7 @@
 #include "status.h"
 #include "mp3_playback.h"
 #include "audio.h"
-#include "wps.h"
+#include "gwps.h"
 #include "abrepeat.h"
 #ifdef HAVE_RTC
 #include "timefuncs.h"
diff --git a/apps/tree.c b/apps/tree.c
index bfeac6c..39980b1 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -36,8 +36,7 @@
 #include "audio.h"
 #include "playlist.h"
 #include "menu.h"
-#include "wps.h"
-#include "wps-display.h"
+#include "gwps.h"
 #include "settings.h"
 #include "status.h"
 #include "debug.h"
@@ -97,6 +96,9 @@
     { "m3u", TREE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
     { "cfg", TREE_ATTR_CFG, Icon_Config, VOICE_EXT_CFG },
     { "wps", TREE_ATTR_WPS, Icon_Wps, VOICE_EXT_WPS },
+#ifdef HAVE_REMOTE_LCD
+    { "rwps", TREE_ATTR_RWPS, Icon_Wps, VOICE_EXT_RWPS },
+#endif
     { "lng", TREE_ATTR_LNG, Icon_Language, LANG_LANGUAGE },
     { "rock",TREE_ATTR_ROCK,Icon_Plugin, VOICE_EXT_ROCK },
 #ifdef HAVE_LCD_BITMAP
@@ -212,6 +214,7 @@
 {
     /* essential to all programs that wants to display things */
     screen_access_init();
+    gui_sync_wps_screen_init();
 
     filetype_init();
     check_rockboxdir();
@@ -885,7 +888,7 @@
             int i;
             FOR_NB_SCREENS(i)
                 screens[i].stop_scroll();
-            if (wps_show() == SYS_USB_CONNECTED)
+            if (gui_wps_show() == SYS_USB_CONNECTED)
                 reload_dir = true;
 #ifdef HAVE_HOTSWAP
             else
diff --git a/apps/tree.h b/apps/tree.h
index 86e9593..55dfc56 100644
--- a/apps/tree.h
+++ b/apps/tree.h
@@ -213,6 +213,7 @@
 #define TREE_ATTR_LNG   0x0700 /* binary lang file */
 #define TREE_ATTR_ROCK  0x0800 /* binary rockbox plugin */
 #define TREE_ATTR_MOD   0x0900 /* firmware file */
+#define TREE_ATTR_RWPS   0x1000 /* remote-wps config file */
 #define TREE_ATTR_MASK  0xFF00 /* which bits tree.c uses for file types */
 
 void tree_get_filetypes(const struct filetype**, int*);
diff --git a/apps/wps-display.c b/apps/wps-display.c
deleted file mode 100644
index 58a953e..0000000
--- a/apps/wps-display.c
+++ /dev/null
@@ -1,1841 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2002 Björn Stenberg
- *
- * All files in this archive are subject to the GNU General Public License.
- * See the file COPYING in the source tree root for full license agreement.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-
-/* ID3 formatting based on code from the MAD Winamp plugin (in_mad.dll),
- * Copyright (C) 2000-2001 Robert Leslie.
- * See http://www.mars.org/home/rob/proj/mpeg/ for more information.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "lcd.h"
-#include "hwcompat.h"
-#include "font.h"
-#include "audio.h"
-#include "id3.h"
-#include "settings.h"
-#include "playlist.h"
-#include "kernel.h"
-#include "system.h"
-#include "status.h"
-#include "wps-display.h"
-#include "debug.h"
-#include "mas.h"
-#include "lang.h"
-#include "powermgmt.h"
-#include "power.h"
-#include "sprintf.h"
-#include "backlight.h"
-#include "button.h"
-#include "abrepeat.h"
-#include "screens.h"
-#include "splash.h"
-#ifdef HAVE_LCD_BITMAP
-#include <ctype.h>
-#include "icons.h"
-#include "widgets.h"
-#include "peakmeter.h"
-
-/* Image stuff */
-#include "bmp.h"
-#include "atoi.h"
-#define MAX_IMAGES (26*2) /* a-z and A-Z */
-#define IMG_BUFSIZE (LCD_HEIGHT * LCD_WIDTH * MAX_IMAGES / 25 ) / 8
-static unsigned char img_buf[IMG_BUFSIZE]; /* image buffer */
-static unsigned char* img_buf_ptr = img_buf; /* where are in image buffer? */
-
-static int img_buf_free = IMG_BUFSIZE; /* free space in image buffer */
-
-struct {
-    unsigned char* ptr;     /* pointer */
-    int x;                  /* x-pos */
-    int y;                  /* y-pos */
-    int w;                  /* width */
-    int h;                  /* height */
-    bool loaded;            /* load state */
-    bool display;           /* is to be displayed */
-    bool always_display;    /* not using the preload/display mechanism */
-} img[MAX_IMAGES] ;
-
-
-#endif
-
-#define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps"
-
-#ifdef HAVE_LCD_BITMAP
-#define MAX_LINES (LCD_HEIGHT/5+1)
-#define FORMAT_BUFFER_SIZE 3072
-#else
-#define MAX_LINES 2
-#define FORMAT_BUFFER_SIZE 400
-#endif
-#define MAX_SUBLINES 12
-#define DEFAULT_SUBLINE_TIME_MULTIPLIER 20 /* (10ths of sec) */
-#define BASE_SUBLINE_TIME 10 /* base time that multiplier is applied to
-                                (1/HZ sec, or 100ths of sec) */
-#define SUBLINE_RESET -1
-
-#ifdef HAVE_LCD_CHARCELLS
-static unsigned char wps_progress_pat[8]={0,0,0,0,0,0,0,0};
-static bool full_line_progressbar=0;
-static bool draw_player_progress(const struct mp3entry* id3,
-                                 int ff_rewwind_count);
-static void draw_player_fullbar(char* buf, int buf_size,
-                                const struct mp3entry* id3,
-                                int ff_rewwind_count);
-static char map_fullbar_char(char ascii_val);
-#endif
-
-struct align_pos {
-    char* left;
-    char* center;
-    char* right;
-};
-static char format_buffer[FORMAT_BUFFER_SIZE];
-static char* format_lines[MAX_LINES][MAX_SUBLINES];
-static struct align_pos format_align[MAX_LINES][MAX_SUBLINES];
-static unsigned char line_type[MAX_LINES][MAX_SUBLINES];
-static unsigned short time_mult[MAX_LINES][MAX_SUBLINES];
-static long subline_expire_time[MAX_LINES];
-static int curr_subline[MAX_LINES];
-
-static int ff_rewind_count;
-bool wps_time_countup = true;
-static bool wps_loaded = false;
-
-#ifdef HAVE_LCD_BITMAP
-/* Display images */
-static void wps_display_images(void) {
-    int n;
-    for (n = 0; n < MAX_IMAGES; n++) {
-        if (img[n].loaded && img[n].display) {
-            if(img[n].always_display)
-                lcd_set_drawmode(DRMODE_FG);
-            else
-                lcd_set_drawmode(DRMODE_SOLID);
-
-            lcd_mono_bitmap(img[n].ptr, img[n].x, img[n].y, img[n].w, img[n].h);
-            lcd_update_rect(img[n].x, img[n].y, img[n].w, img[n].h);
-        }
-    }
-    lcd_set_drawmode(DRMODE_SOLID);
-}
-#endif
-
-/* Set format string to use for WPS, splitting it into lines */
-static void wps_format(const char* fmt, char *bmpdir, size_t bmpdirlen)
-{
-    char* buf = format_buffer;
-    char* start_of_line = format_buffer;
-    int line = 0;
-    int subline;
-#ifndef HAVE_LCD_BITMAP
-    /* no bitmap lcd == no bitmap loading */
-    (void)bmpdir;
-    (void)bmpdirlen;
-#endif
-
-    strncpy(format_buffer, fmt, sizeof(format_buffer));
-    format_buffer[sizeof(format_buffer) - 1] = 0;
-
-    for (line=0; line<MAX_LINES; line++)
-    {
-        for (subline=0; subline<MAX_SUBLINES; subline++)
-        {
-            format_lines[line][subline] = 0;
-            time_mult[line][subline] = 0;
-        }
-        subline_expire_time[line] = 0;
-        curr_subline[line] = SUBLINE_RESET;
-    }
-
-    line = 0;
-    subline = 0;
-    format_lines[line][subline] = buf;
-
-    while ((*buf) && (line < MAX_LINES))
-    {
-        switch (*buf)
-        {
-            /*
-             * skip % sequences so "%;" doesn't start a new subline
-             * don't skip %x lines (pre-load bitmaps)
-             */
-            case '%':
-                if (*(buf+1) != 'x')
-                    buf++;
-                break;
-
-            case '\r': /* CR */
-                *buf = 0;
-                break;
-
-            case '\n': /* LF */
-                *buf = 0;
-
-                if (*start_of_line != '#') /* A comment? */
-                    line++;
-
-                if (line < MAX_LINES)
-                {
-                    /* the next line starts on the next byte */
-                    subline = 0;
-                    format_lines[line][subline] = buf+1;
-                    start_of_line = format_lines[line][subline];
-                }
-                break;
-
-            case ';': /* start a new subline */
-                *buf = 0;
-                subline++;
-                if (subline < MAX_SUBLINES)
-                {
-                    format_lines[line][subline] = buf+1;
-                }
-                else /* exceeded max sublines, skip rest of line */
-                {
-                    while (*(++buf))
-                    {
-                        if  ((*buf == '\r') || (*buf == '\n'))
-                        {
-                            break;
-                        }
-                    }
-                    buf--;
-                    subline = 0;
-                }
-                break;
-
-            case 'x':
-#ifdef HAVE_LCD_BITMAP
-                /* Preload images so the %xd# tag can display it */
-            {
-                int ret = 0;
-                int n;
-                char *ptr = buf+1;
-                char *pos = NULL;
-                char imgname[MAX_PATH];
-                char qual = *ptr;
-                if (qual == 'l' || qual == '|')  /* format:
-                                                    %x|n|filename.bmp|x|y|
-                                                    or
-                                                    %xl|n|filename.bmp|x|y|
-                                                 */
-                {
-                    ptr = strchr(ptr, '|') + 1;
-                    pos = strchr(ptr, '|');
-                    if (pos)
-                    {
-                        /* get the image ID */
-                        n = *ptr;
-                        if(n >= 'a' && n <= 'z')
-                            n -= 'a';
-                        if(n >= 'A' && n <= 'Z')
-                            n = n - 'A' + 26;
-
-                        if(n < 0 || n >= MAX_IMAGES)
-                        {
-                            /* Skip the rest of the line */
-                            while(*buf != '\n')
-                                buf++;
-                            break;
-                        }
-                        ptr = pos+1;
-
-                        /* check the image number and load state */
-                        if (!img[n].loaded)
-                        {
-                            /* get filename */
-                            pos = strchr(ptr, '|');
-                            if ((pos - ptr) <
-                                (int)sizeof(imgname)-ROCKBOX_DIR_LEN-2)
-                            {
-                                memcpy(imgname, bmpdir, bmpdirlen);
-                                imgname[bmpdirlen] = '/';
-                                memcpy(&imgname[bmpdirlen+1],
-                                       ptr, pos - ptr);
-                                imgname[bmpdirlen+1+pos-ptr] = 0;
-                            }
-                            else
-                                /* filename too long */
-                                imgname[0] = 0;
-
-                            ptr = pos+1;
-
-                            /* get x-position */
-                            pos = strchr(ptr, '|');
-                            if (pos)
-                                img[n].x = atoi(ptr);
-                            else
-                            {
-                                /* weird syntax, bail out */
-                                buf++;
-                                break;
-                            }
-
-                            /* get y-position */
-                            ptr = pos+1;
-                            pos = strchr(ptr, '|');
-                            if (pos)
-                                img[n].y = atoi(ptr);
-                            else
-                            {
-                                /* weird syntax, bail out */
-                                buf++;
-                                break;
-                            }
-
-                            pos++;
-                            
-                            /* reposition buf pointer to next WPS element */
-                            while (*pos && *pos != ';' &&
-                                   *pos != '\r' && *pos != '\n')
-                                pos++;
-
-                            buf = pos;
-
-                            /* load the image */
-                            ret = read_bmp_file(imgname, &img[n].w, &img[n].h,
-                                                img_buf_ptr, img_buf_free);
-                            if (ret > 0)
-                            {
-                                img[n].ptr = img_buf_ptr;
-                                img_buf_ptr += ret;
-                                img_buf_free -= ret;
-                                img[n].loaded = true;
-                                if(qual == '|')
-                                    img[n].always_display = true;
-                            }
-                        }
-                        buf++;
-                    }
-                }
-              }
-#endif
-              break;
-        }
-        buf++;
-    }
-}
-
-/* Clear the WPS image cache */
-static void wps_clear(void)
-{
-#ifdef HAVE_LCD_BITMAP
-   int i;
-
-   /* reset image buffer */
-   img_buf_ptr = img_buf;
-   img_buf_free = IMG_BUFSIZE;
-
-   /* set images to unloaded and not displayed */
-   for (i = 0; i < MAX_IMAGES; i++) {
-      img[i].loaded = false;
-      img[i].display = false;
-      img[i].always_display = false;
-   }
-#endif
-
-}
-
-void wps_reset(void)
-{
-    wps_loaded = false;
-    memset(&format_buffer, 0, sizeof format_buffer);
-    wps_clear();
-}
-
-bool wps_load(const char* file, bool display)
-{
-    int i,s;
-    char buffer[FORMAT_BUFFER_SIZE];
-    int fd;
-    size_t bmpdirlen;
-
-    char *bmpdir = strrchr(file, '.');
-    bmpdirlen = bmpdir - file;
-    
-    /* 
-     * Hardcode loading WPS_DEFAULTCFG to cause a reset ideally this 
-     * wants to be a virtual file.  Feel free to modify dirbrowse()
-     * if you're feeling brave.
-     */
-    if (! strcmp(file, WPS_DEFAULTCFG) ) {
-       wps_reset();
-       return(false);
-    }
-
-    fd = open(file, O_RDONLY);
-
-    if (fd >= 0)
-    {
-        int numread = read(fd, buffer, sizeof(buffer) - 1);
-
-        if (numread > 0)
-        {
-            wps_clear();
-            buffer[numread] = 0;
-            wps_format(buffer, (char *)file, bmpdirlen);
-        }
-
-        close(fd);
-
-        if ( display ) {
-            bool any_defined_line;
-            lcd_clear_display();
-#ifdef HAVE_LCD_BITMAP
-            lcd_setmargins(0,0);
-#endif
-            for (s=0; s<MAX_SUBLINES; s++)
-            {
-                any_defined_line = false;
-                for (i=0; i<MAX_LINES; i++)
-                {
-                    if (format_lines[i][s])
-                    {
-                        if (*format_lines[i][s] == 0)
-                            lcd_puts(0,i," ");
-                        else
-                            lcd_puts(0,i,format_lines[i][s]);
-                        any_defined_line = true;
-                    }
-                    else
-                    {
-                        lcd_puts(0,i," ");
-                    }
-                }
-                if (any_defined_line)
-                {
-#ifdef HAVE_LCD_BITMAP
-                    wps_display_images();
-#endif
-                    lcd_update();
-                    sleep(HZ/2);
-                }
-            }
-        }
-        wps_loaded = true;
-
-        return numread > 0;
-    }
-
-    return false;
-}
-
-/* Format time into buf.
- *
- * buf      - buffer to format to.
- * buf_size - size of buffer.
- * time     - time to format, in milliseconds.
- */
-void wps_format_time(char* buf, int buf_size, long time)
-{
-    if ( time < 3600000 ) {
-      snprintf(buf, buf_size, "%d:%02d",
-               (int) (time % 3600000 / 60000), (int) (time % 60000 / 1000));
-    } else {
-      snprintf(buf, buf_size, "%d:%02d:%02d",
-               (int) (time / 3600000), (int) (time % 3600000 / 60000),
-               (int) (time % 60000 / 1000));
-    }
-}
-
-/* Extract a part from a path.
- *
- * buf      - buffer extract part to.
- * buf_size - size of buffer.
- * path     - path to extract from.
- * level    - what to extract. 0 is file name, 1 is parent of file, 2 is
- *            parent of parent, etc.
- *
- * Returns buf if the desired level was found, NULL otherwise.
- */
-static char* get_dir(char* buf, int buf_size, const char* path, int level)
-{
-    const char* sep;
-    const char* last_sep;
-    int len;
-
-    sep = path + strlen(path);
-    last_sep = sep;
-
-    while (sep > path)
-    {
-        if ('/' == *(--sep))
-        {
-            if (!level)
-            {
-                break;
-            }
-
-            level--;
-            last_sep = sep - 1;
-        }
-    }
-
-    if (level || (last_sep <= sep))
-    {
-        return NULL;
-    }
-
-    len = MIN(last_sep - sep, buf_size - 1);
-    strncpy(buf, sep + 1, len);
-    buf[len] = 0;
-    return buf;
-}
-
-/* Get the tag specified by the two characters at fmt.
- *
- * cid3      - ID3 data to get tag values from.
- * nid3     - next-song ID3 data to get tag values from.
- * tag      - string (of two characters) specifying the tag to get.
- * buf      - buffer to certain tags, such as track number, play time or
- *           directory name.
- * buf_size - size of buffer.
- * flags    - returns the type of the line. See constants i wps-display.h
- *
- * Returns the tag. NULL indicates the tag wasn't available.
- */
-static char* get_tag(struct mp3entry* cid3,
-                     struct mp3entry* nid3,
-                     const char* tag,
-                     char* buf,
-                     int buf_size,
-                     unsigned char* tag_len,
-                     unsigned short* subline_time_mult,
-                     unsigned char* flags,
-                     int *intval)
-{
-    struct mp3entry *id3 = cid3; /* default to current song */
-
-    if ((0 == tag[0]) || (0 == tag[1]))
-    {
-        *tag_len = 0;
-        return NULL;
-    }
-
-    *tag_len = 2;
-
-    *intval = 0;
-    
-    switch (tag[0])
-    {
-        case 'I':  /* ID3 Information */
-            id3 = nid3; /* display next-song data */
-            *flags |= WPS_REFRESH_DYNAMIC;
-            if(!id3)
-                return NULL; /* no such info (yet) */
-            /* fall-through */
-        case 'i':  /* ID3 Information */
-            *flags |= WPS_REFRESH_STATIC;
-            switch (tag[1])
-            {
-                case 't':  /* ID3 Title */
-                    return id3->title;
-
-                case 'a':  /* ID3 Artist */
-                    return id3->artist;
-
-                case 'n':  /* ID3 Track Number */
-                    if (id3->track_string)
-                        return id3->track_string;
-
-                    if (id3->tracknum) {
-                        snprintf(buf, buf_size, "%d", id3->tracknum);
-                        return buf;
-                    }
-                    return NULL;
-
-                case 'd':  /* ID3 Album/Disc */
-                    return id3->album;
-
-                case 'c':  /* ID3 Composer */
-                    return id3->composer;
-
-                case 'y':  /* year */
-                    if( id3->year_string )
-                        return id3->year_string;
-
-                    if (id3->year) {
-                        snprintf(buf, buf_size, "%d", id3->year);
-                        return buf;
-                    }
-                    return NULL;
-
-                case 'g':  /* genre */
-                    return id3_get_genre(id3);
-
-                case 'v': /* id3 version */
-                    switch (id3->id3version) {
-                        case ID3_VER_1_0:
-                            return "1";
-
-                        case ID3_VER_1_1:
-                            return "1.1";
-
-                        case ID3_VER_2_2:
-                            return "2.2";
-
-                        case ID3_VER_2_3:
-                            return "2.3";
-
-                        case ID3_VER_2_4:
-                            return "2.4";
-
-                        default:
-                            return NULL;
-                    }
-            }
-            break;
-
-        case 'F':  /* File Information */
-            id3 = nid3;
-            *flags |= WPS_REFRESH_DYNAMIC;
-            if(!id3)
-                return NULL; /* no such info (yet) */
-            /* fall-through */
-        case 'f':  /* File Information */
-            *flags |= WPS_REFRESH_STATIC;
-            switch(tag[1])
-            {
-                case 'v':  /* VBR file? */
-                    return id3->vbr ? "(avg)" : NULL;
-
-                case 'b':  /* File Bitrate */
-                    if(id3->bitrate)
-                        snprintf(buf, buf_size, "%d", id3->bitrate);
-                    else
-                        snprintf(buf, buf_size, "?");
-                    return buf;
-
-                case 'f':  /* File Frequency */
-                    snprintf(buf, buf_size, "%ld", id3->frequency);
-                    return buf;
-
-                case 'p':  /* File Path */
-                    return id3->path;
-
-                case 'm':  /* File Name - With Extension */
-                    return get_dir(buf, buf_size, id3->path, 0);
-
-                case 'n':  /* File Name */
-                    if (get_dir(buf, buf_size, id3->path, 0))
-                    {
-                        /* Remove extension */
-                        char* sep = strrchr(buf, '.');
-
-                        if (NULL != sep)
-                        {
-                            *sep = 0;
-                        }
-
-                        return buf;
-                    }
-                    else
-                    {
-                        return NULL;
-                    }
-
-                case 's':  /* File Size (in kilobytes) */
-                    snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
-                    return buf;
-
-                case 'c':  /* File Codec */
-                    if(id3->codectype == AFMT_UNKNOWN)
-                        *intval = AFMT_NUM_CODECS;
-                    else
-                        *intval = id3->codectype;
-                    return id3_get_codec(id3);
-            }
-            break;
-
-        case 'p':  /* Playlist/Song Information */
-            switch(tag[1])
-            {
-                case 'b':  /* progress bar */
-                    *flags |= WPS_REFRESH_PLAYER_PROGRESS;
-#ifdef HAVE_LCD_CHARCELLS
-                    snprintf(buf, buf_size, "%c", wps_progress_pat[0]);
-                    full_line_progressbar=0;
-                    return buf;
-#else
-                    return "\x01";
-#endif
-                case 'f':  /* full-line progress bar */
-#ifdef HAVE_LCD_CHARCELLS
-                    if(is_new_player()) {
-                        *flags |= WPS_REFRESH_PLAYER_PROGRESS;
-                        *flags |= WPS_REFRESH_DYNAMIC;
-                        full_line_progressbar=1;
-                        /* we need 11 characters (full line) for
-                           progress-bar */
-                        snprintf(buf, buf_size, "           ");
-                    }
-                    else
-                    {
-                        /* Tell the user if we have an OldPlayer */
-                        snprintf(buf, buf_size, " <Old LCD> ");
-                    }
-                    return buf;
-#endif
-                case 'p':  /* Playlist Position */
-                    *flags |= WPS_REFRESH_STATIC;
-                    snprintf(buf, buf_size, "%d", playlist_get_display_index());
-                    return buf;
-
-                case 'n':  /* Playlist Name (without path) */
-                    *flags |= WPS_REFRESH_STATIC;
-                    return playlist_name(NULL, buf, buf_size);
-
-                case 'e':  /* Playlist Total Entries */
-                    *flags |= WPS_REFRESH_STATIC;
-                    snprintf(buf, buf_size, "%d", playlist_amount());
-                    return buf;
-
-                case 'c':  /* Current Time in Song */
-                    *flags |= WPS_REFRESH_DYNAMIC;
-                    wps_format_time(buf, buf_size,
-                                    id3->elapsed + ff_rewind_count);
-                    return buf;
-
-                case 'r': /* Remaining Time in Song */
-                    *flags |= WPS_REFRESH_DYNAMIC;
-                    wps_format_time(buf, buf_size,
-                                    id3->length - id3->elapsed - ff_rewind_count);
-                    return buf;
-
-                case 't':  /* Total Time */
-                    *flags |= WPS_REFRESH_STATIC;
-                    wps_format_time(buf, buf_size, id3->length);
-                    return buf;
-
-#ifdef HAVE_LCD_BITMAP
-                case 'm': /* Peak Meter */
-                    *flags |= WPS_REFRESH_PEAK_METER;
-                    return "\x01";
-#endif
-                case 's': /* shuffle */
-                    *flags |= WPS_REFRESH_DYNAMIC;
-                    if ( global_settings.playlist_shuffle )
-                        return "s";
-                    else
-                        return NULL;
-                    break;
-
-                case 'v': /* volume */
-                    *flags |= WPS_REFRESH_DYNAMIC;
-                    snprintf(buf, buf_size, "%d%%", global_settings.volume);
-                    *intval = global_settings.volume / 10 + 1;
-                    return buf;
-
-            }
-            break;
-            
-        case 'm':
-            switch (tag[1])
-            {
-                case 'm': /* playback repeat mode */
-                    *flags |= WPS_REFRESH_DYNAMIC;
-                    *intval = global_settings.repeat_mode + 1;
-                    snprintf(buf, buf_size, "%d", *intval);
-                    return buf;
-                    
-                /* playback status */
-                case 'p': /* play */
-                    *flags |= WPS_REFRESH_DYNAMIC;
-                    int status = audio_status();
-                    *intval = 1;
-                    if (status == AUDIO_STATUS_PLAY && \
-                        !(status & AUDIO_STATUS_PAUSE))
-                        *intval = 2;
-                    if (audio_status() & AUDIO_STATUS_PAUSE && \
-                        (! status_get_ffmode()))
-                        *intval = 3;
-                    if (status_get_ffmode() == STATUS_FASTFORWARD)
-                        *intval = 4;
-                    if (status_get_ffmode() == STATUS_FASTBACKWARD)
-                        *intval = 5;
-                    snprintf(buf, buf_size, "%d", *intval);
-                    return buf;
-
-#if CONFIG_KEYPAD == IRIVER_H100_PAD
-                case 'h': /* hold */
-                    *flags |= WPS_REFRESH_DYNAMIC;
-                    if (button_hold())
-                        return "h";
-                    else
-                        return NULL;
-                case 'r': /* remote hold */
-                    *flags |= WPS_REFRESH_DYNAMIC;
-                    if (remote_button_hold())
-                        return "r";
-                    else
-                        return NULL;
-#endif
-            }
-            break;
-
-        case 'b': /* battery info */
-            *flags |= WPS_REFRESH_DYNAMIC;
-            switch (tag[1]) {
-                case 'l': /* battery level */
-                {
-                    int l = battery_level();
-                    if (l > -1)
-                    {
-                        snprintf(buf, buf_size, "%d%%", l);
-                        *intval = l / 20 + 1;
-                    }
-                    else
-                    {
-                        *intval = 6;
-                        return "?%";
-                    }
-                    return buf;
-                }
-
-                case 't': /* estimated battery time */
-                {
-                    int t = battery_time();
-                    if (t >= 0)
-                        snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
-                    else
-                        strncpy(buf, "?h ?m", buf_size);
-                    return buf;
-                }
-                
-		case 'p': /* External power plugged in? */
-		{
-		    if(charger_inserted())
-			return "p";
-		    else
-			return NULL;
-		}
-            }
-            break;
-
-        case 'D': /* Directory path information */
-            id3 = nid3; /* next song please! */
-            *flags |= WPS_REFRESH_DYNAMIC;
-            if(!id3)
-                return NULL; /* no such info (yet) */
-            /* fall-through */
-        case 'd': /* Directory path information */
-            {
-                int level = tag[1] - '0';
-                *flags |= WPS_REFRESH_STATIC;
-                /* d1 through d9 */
-                if ((0 < level) && (9 > level))
-                {
-                    return get_dir(buf, buf_size, id3->path, level);
-                }
-            }
-            break;
-
-        case 't': /* set sub line time multiplier */
-            {
-                int d = 1;
-                int time_mult = 0;
-                bool have_point = false;
-                bool have_tenth = false;
-
-                while (((tag[d] >= '0') &&
-                        (tag[d] <= '9')) ||
-                       (tag[d] == '.'))
-                {
-                    if (tag[d] != '.')
-                    {
-                        time_mult = time_mult * 10;
-                        time_mult = time_mult + tag[d] - '0';
-                        if (have_point)
-                        {
-                            have_tenth = true;
-                            d++;
-                            break;
-                        }
-                    }
-                    else
-                    {
-                        have_point = true;
-                    }
-                    d++;
-                }
-
-                if (have_tenth == false)
-                    time_mult *= 10;
-
-                *subline_time_mult = time_mult;
-                *tag_len = d;
-
-                buf[0] = 0;
-                return buf;
-            }
-            break;
-       case 'r':  /* Runtime database Information */
-            switch(tag[1])
-                {
-                     case 'p':  /* Playcount */
-                         *flags |= WPS_REFRESH_STATIC;
-                         snprintf(buf, buf_size, "%ld", cid3->playcount);
-                         return buf;
-                     case 'r':  /* Rating */
-                         *flags |= WPS_REFRESH_STATIC;
-                         *intval = cid3->rating+1;
-                         snprintf(buf, buf_size, "%d", cid3->rating);
-                         return buf;
-                }
-            break;
-    }
-    return NULL;
-}
-
-/* Skip to the end of the current %? conditional.
- *
- * fmt     - string to skip it. Should point to somewhere after the leading
- *           "<" char (and before or at the last ">").
- * num     - number of |'s to skip, or 0 to skip to the end (the ">").
- *
- * Returns the new position in fmt.
- */
-static const char* skip_conditional(const char* fmt, int num)
-{
-    int level = 1;
-    int count = num;
-    const char *last_alternative = NULL;
-
-    while (*fmt)
-    {
-        switch (*fmt++)
-        {
-            case '%':
-                break;
-
-            case '|':
-                if(1 == level) {
-                    last_alternative = fmt;
-                    if(num) {
-                        count--;
-                        if(count == 0)
-                            return fmt;
-                        continue;
-                    }
-                }
-                continue;
-
-            case '>':
-                if (0 == --level)
-                {
-                    /* We're just skipping to the end */
-                    if(num == 0)
-                        return fmt;
-
-                    /* If we are parsing an enum, we'll return the selected
-                       item. If there weren't enough items in the enum, we'll
-                       return the last one found. */
-                    if(count && last_alternative)
-                    {
-                        return last_alternative;
-                    }
-                    return fmt - 1;
-                }
-                continue;
-
-            default:
-                continue;
-        }
-
-        switch (*fmt++)
-        {
-            case 0:
-            case '%':
-            case '|':
-            case '<':
-            case '>':
-                break;
-
-            case '?':
-                while (*fmt && ('<' != *fmt))
-                    fmt++;
-
-                if ('<' == *fmt)
-                    fmt++;
-
-                level++;
-                break;
-
-            default:
-                break;
-        }
-    }
-
-    return fmt;
-}
-
-/* Generate the display based on id3 information and format string.
- *
- * buf      - char buffer to write the display to.
- * buf_size - the size of buffer.
- * id3      - the ID3 data to format with.
- * nid3     - the ID3 data of the next song (might by NULL)
- * fmt      - format description.
- * flags    - returns the type of the line. See constants i wps-display.h
- */
-static void format_display(char* buf,
-                           int buf_size,
-                           struct mp3entry* id3,
-                           struct mp3entry* nid3, /* next song's id3 */
-                           const char* fmt,
-                           struct align_pos* align,
-                           unsigned short* subline_time_mult,
-                           unsigned char* flags)
-{
-    char temp_buf[128];
-    char* buf_start = buf;
-    char* buf_end = buf + buf_size - 1;   /* Leave room for end null */
-    char* value = NULL;
-    int level = 0;
-    unsigned char tag_length;
-    int intval;
-    int cur_align;
-    char* cur_align_start;
-#ifdef HAVE_LCD_BITMAP
-    int n;
-#endif
-    
-    cur_align_start = buf;
-    cur_align = WPS_ALIGN_LEFT;
-    *subline_time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER;
-
-    align->left = 0;
-    align->center = 0;
-    align->right = 0;
-
-    while (fmt && *fmt && buf < buf_end)
-    {
-        switch (*fmt)
-        {
-            case '%':
-                ++fmt;
-                break;
-
-            case '|':
-            case '>':
-                if (level > 0)
-                {
-                    fmt = skip_conditional(fmt, 0);
-                    level--;
-                    continue;
-                }
-                /* Else fall through */
-
-            default:
-                *buf++ = *fmt++;
-                continue;
-        }
-
-        switch (*fmt)
-        {
-            case 0:
-                *buf++ = '%';
-                break;
-            case 'a':
-                ++fmt;
-                /* remember where the current aligned text started */
-                switch (cur_align)
-                {
-                    case WPS_ALIGN_LEFT:
-                        align->left = cur_align_start;
-                        break;
-
-                    case WPS_ALIGN_CENTER:
-                        align->center = cur_align_start;
-                        break;
-
-                    case WPS_ALIGN_RIGHT:
-                        align->right = cur_align_start;
-                        break;
-                }
-                /* start a new alignment */
-                switch (*fmt)
-                {
-                    case 'l':
-                        cur_align = WPS_ALIGN_LEFT;
-                        break;
-                    case 'c':
-                        cur_align = WPS_ALIGN_CENTER;
-                        break;
-                    case 'r':
-                        cur_align = WPS_ALIGN_RIGHT;
-                        break;
-                } 
-                *buf++=0;
-                cur_align_start = buf;
-                ++fmt;
-                break;
-            case 's':
-                *flags |= WPS_REFRESH_SCROLL;
-                ++fmt;
-                break;
-
-            case 'x': /* image support */
-#ifdef HAVE_LCD_BITMAP
-                /* skip preload or regular image tag */
-                if ('l' == *(fmt+1) || '|' == *(fmt+1))
-                {
-                    while (*fmt && *fmt != '\n')
-                        fmt++;
-                }
-                else if ('d' == *(fmt+1))
-                {
-                    fmt+=2;
-
-                    /* get the image ID */
-                    n = *fmt;
-                    if(n >= 'a' && n <= 'z')
-                        n -= 'a';
-                    if(n >= 'A' && n <= 'Z')
-                        n = n - 'A' + 26;
-                        
-                    if (n >= 0 && n < MAX_IMAGES && img[n].loaded) {
-                        img[n].display = true;
-                    }
-                }
-#endif
-                fmt++;
-                break;
-
-
-            case '%':
-            case '|':
-            case '<':
-            case '>':
-            case ';':
-                *buf++ = *fmt++;
-                break;
-
-            case '?':
-                fmt++;
-                value = get_tag(id3, nid3, fmt, temp_buf, sizeof(temp_buf),
-                                &tag_length, subline_time_mult, flags,
-                                &intval);
-
-                while (*fmt && ('<' != *fmt))
-                    fmt++;
-
-                if ('<' == *fmt)
-                    fmt++;
-
-                /* No value, so skip to else part, using a sufficiently high
-                   value to "hit" the last part of the conditional */
-                if ((!value) || (!strlen(value)))
-                    fmt = skip_conditional(fmt, 1000);
-                else
-                    if(intval > 1) /* enum */
-                        fmt = skip_conditional(fmt, intval - 1);
-
-                level++;
-                break;
-
-            default:
-                value = get_tag(id3, nid3, fmt, temp_buf, sizeof(temp_buf),
-                                &tag_length, subline_time_mult, flags,
-                                &intval);
-                fmt += tag_length;
-
-                if (value)
-                {
-                    while (*value && (buf < buf_end))
-                        *buf++ = *value++;
-                }
-        }
-    }
-
-    /* remember where the current aligned text started */
-    switch (cur_align)
-    {
-        case WPS_ALIGN_LEFT:
-            align->left = cur_align_start;
-            break;
-
-        case WPS_ALIGN_CENTER:
-            align->center = cur_align_start;
-            break;
-
-        case WPS_ALIGN_RIGHT:
-            align->right = cur_align_start;
-            break;
-    }
-
-    *buf = 0;
-
-    /* if resulting line is an empty line, set the subline time to 0 */
-    if (buf - buf_start == 0)
-        *subline_time_mult = 0;
-
-    /* If no flags have been set, the line didn't contain any format codes.
-       We still want to refresh it. */
-    if(*flags == 0)
-        *flags = WPS_REFRESH_STATIC;
-}
-
-bool wps_refresh(struct mp3entry* id3,
-                 struct mp3entry* nid3,
-                 int ffwd_offset,
-                 unsigned char refresh_mode)
-{
-    char buf[MAX_PATH];
-    unsigned char flags;
-    int i;
-    bool update_line;
-    bool only_one_subline;
-    bool new_subline_refresh;
-    int search;
-    int search_start;
-#ifdef HAVE_LCD_BITMAP
-    int h = font_get(FONT_UI)->height;
-    int offset = global_settings.statusbar ? STATUSBAR_HEIGHT : 0;
-    /* to find out wether the peak meter is enabled we
-       assume it wasn't until we find a line that contains
-       the peak meter. We can't use peak_meter_enabled itself
-       because that would mean to turn off the meter thread
-       temporarily. (That shouldn't matter unless yield
-       or sleep is called but who knows...)
-    */
-    bool enable_pm = false;
-
-    /* Set images to not to be displayed */
-    for (i = 0; i < MAX_IMAGES; i++) {
-        img[i].display = false;
-    }
-#endif
-
-    /* reset to first subline if refresh all flag is set */
-    if (refresh_mode == WPS_REFRESH_ALL)
-    {
-        for (i=0; i<MAX_LINES; i++)
-        {
-            curr_subline[i] = SUBLINE_RESET;
-        }
-    }
-
-#ifdef HAVE_LCD_CHARCELLS
-    for (i=0; i<8; i++) {
-       if (wps_progress_pat[i]==0)
-           wps_progress_pat[i]=lcd_get_locked_pattern();
-    }
-#endif
-
-    if (!id3)
-    {
-        lcd_stop_scroll();
-        return false;
-    }
-
-    ff_rewind_count = ffwd_offset;
-
-    for (i = 0; i < MAX_LINES; i++)
-    {
-        new_subline_refresh = false;
-        only_one_subline = false;
-
-        /* if time to advance to next sub-line  */
-        if (TIME_AFTER(current_tick,  subline_expire_time[i] - 1) ||
-           (curr_subline[i] == SUBLINE_RESET))
-        {
-            /* search all sublines until the next subline with time > 0
-               is found or we get back to the subline we started with */
-            if (curr_subline[i] == SUBLINE_RESET)
-                search_start = 0;
-            else
-                search_start = curr_subline[i];
-            for (search=0; search<MAX_SUBLINES; search++)
-            {
-                curr_subline[i]++;
-
-                /* wrap around if beyond last defined subline or MAX_SUBLINES */
-                if ((!format_lines[i][curr_subline[i]]) ||
-                    (curr_subline[i] == MAX_SUBLINES))
-                {
-                    if (curr_subline[i] == 1)
-                        only_one_subline = true;
-                    curr_subline[i] = 0;
-                }
-
-                /* if back where we started after search or
-                   only one subline is defined on the line */
-                if (((search > 0) && (curr_subline[i] == search_start)) ||
-                    only_one_subline)
-                {
-                    /* no other subline with a time > 0 exists */
-                    subline_expire_time[i] = current_tick  + 100 * HZ;
-                    break;
-                }
-                else
-                {
-                    /* get initial time multiplier and
-                       line type flags for this subline */
-                    format_display(buf, sizeof(buf), id3, nid3,
-                                   format_lines[i][curr_subline[i]],
-                                   &format_align[i][curr_subline[i]],
-                                   &time_mult[i][curr_subline[i]],
-                                   &line_type[i][curr_subline[i]]);
-
-                    /* only use this subline if subline time > 0 */
-                    if (time_mult[i][curr_subline[i]] > 0)
-                    {
-                        new_subline_refresh = true;
-                        subline_expire_time[i] = current_tick  +
-                            BASE_SUBLINE_TIME * time_mult[i][curr_subline[i]];
-                        break;
-                    }
-                }
-            }
-
-        }
-
-        update_line = false;
-
-        if ( !format_lines[i][curr_subline[i]] )
-            break;
-
-        if ((line_type[i][curr_subline[i]] & refresh_mode) ||
-            (refresh_mode == WPS_REFRESH_ALL) ||
-            new_subline_refresh)
-        {
-            flags = 0;
-#ifdef HAVE_LCD_BITMAP
-            int left_width,   left_xpos;
-            int center_width, center_xpos;
-            int right_width,  right_xpos;
-            int space_width;
-            int string_height;
-            int ypos;
-#endif
-
-            format_display(buf, sizeof(buf), id3, nid3,
-                           format_lines[i][curr_subline[i]],
-                           &format_align[i][curr_subline[i]],
-                           &time_mult[i][curr_subline[i]],
-                           &flags);
-            line_type[i][curr_subline[i]] = flags;
-
-#ifdef HAVE_LCD_BITMAP
-            /* progress */
-            if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) 
-            {
-#define PROGRESS_BAR_HEIGHT 6 /* this should probably be defined elsewhere; config-*.h perhaps? */
-                int sby = i*h + offset + (h > 7 ? (h - 6) / 2 : 1);
-                scrollbar(0, sby, LCD_WIDTH, PROGRESS_BAR_HEIGHT,
-                    id3->length?id3->length:1, 0,
-                    id3->length?id3->elapsed + ff_rewind_count:0,
-                    HORIZONTAL);
-#ifdef AB_REPEAT_ENABLE
-                if ( ab_repeat_mode_enabled() )
-                    ab_draw_markers(id3->length, 0, sby, LCD_WIDTH, PROGRESS_BAR_HEIGHT);
-#endif
-                update_line = true;
-            }
-            if (flags & refresh_mode & WPS_REFRESH_PEAK_METER) {
-                /* peak meter */
-                int peak_meter_y;
-
-                update_line = true;
-                peak_meter_y = i * h + offset;
-
-                /* 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 <= LCD_HEIGHT) {
-                    /* found a line with a peak meter -> remember that we must
-                       enable it later */
-                    enable_pm = true;
-                    peak_meter_draw(0, peak_meter_y, LCD_WIDTH,
-                                    MIN(h, LCD_HEIGHT - peak_meter_y));
-                }
-            }
-#else
-            /* progress */
-            if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) {
-                if (full_line_progressbar)
-                    draw_player_fullbar(buf, sizeof(buf),
-                                        id3, ff_rewind_count);
-                else
-                    draw_player_progress(id3, ff_rewind_count);
-            }
-#endif
-#ifdef HAVE_LCD_BITMAP
-            /* calculate different string sizes and positions */
-            lcd_getstringsize(" ", &space_width, &string_height);
-            if (format_align[i][curr_subline[i]].left != 0) {
-                lcd_getstringsize(format_align[i][curr_subline[i]].left,
-                                  &left_width, &string_height);
-            }
-            else {
-                left_width = 0;
-            }
-            left_xpos = 0;
-
-            if (format_align[i][curr_subline[i]].center != 0) {
-                lcd_getstringsize(format_align[i][curr_subline[i]].center,
-                                  &center_width, &string_height);
-            }
-            else {
-                center_width = 0;
-            }
-            center_xpos=(LCD_WIDTH - center_width) / 2;
-
-            if (format_align[i][curr_subline[i]].right != 0) {
-                lcd_getstringsize(format_align[i][curr_subline[i]].right,
-                                  &right_width, &string_height);
-            }
-            else {
-                right_width = 0;
-            }
-            right_xpos = (LCD_WIDTH - right_width);
-
-            /* Checks for overlapping strings.
-               If needed the overlapping strings will be merged, separated by a
-               space */
-
-            /* CASE 1: left and centered string overlap */
-            /* there is a left string, need to merge left and center */
-            if ((left_width != 0 && center_width != 0) &&
-                (left_xpos + left_width + space_width > center_xpos)) {
-                /* replace the former separator '\0' of left and 
-                   center string with a space */
-                *(--format_align[i][curr_subline[i]].center) = ' ';
-                /* calculate the new width and position of the merged string */
-                left_width = left_width + space_width + center_width;
-                left_xpos = 0;
-                /* there is no centered string anymore */
-                center_width = 0;
-            }
-            /* there is no left string, move center to left */
-            if ((left_width == 0 && center_width != 0) &&
-                (left_xpos + left_width > center_xpos)) {
-                /* move the center string to the left string */
-                format_align[i][curr_subline[i]].left = format_align[i][curr_subline[i]].center;
-                /* calculate the new width and position of the string */
-                left_width = center_width;
-                left_xpos = 0;
-                /* there is no centered string anymore */
-                center_width = 0;
-            }
-
-            /* CASE 2: centered and right string overlap */
-            /* there is a right string, need to merge center and right */
-            if ((center_width != 0 && right_width != 0) &&
-                (center_xpos + center_width + space_width > right_xpos)) {
-                /* replace the former separator '\0' of center and 
-                   right string with a space */
-                *(--format_align[i][curr_subline[i]].right) = ' ';
-                /* move the center string to the right after merge */
-                format_align[i][curr_subline[i]].right = format_align[i][curr_subline[i]].center;
-                /* calculate the new width and position of the merged string */
-                right_width = center_width + space_width + right_width;
-                right_xpos = (LCD_WIDTH - right_width);
-                /* there is no centered string anymore */
-                center_width = 0;
-            }
-            /* there is no right string, move center to right */
-            if ((center_width != 0 && right_width == 0) &&
-                (center_xpos + center_width > right_xpos)) {
-                /* move the center string to the right string */
-                format_align[i][curr_subline[i]].right = format_align[i][curr_subline[i]].center;
-                /* calculate the new width and position of the string */
-                right_width = center_width;
-                right_xpos = (LCD_WIDTH - right_width);
-                /* there is no centered string anymore */
-                center_width = 0;
-            }
-
-            /* CASE 3: left and right overlap
-               There is no center string anymore, either there never
-               was one or it has been merged in case 1 or 2 */
-            /* there is a left string, need to merge left and right */
-            if ((left_width != 0 && center_width == 0 && right_width != 0) &&
-                (left_xpos + left_width + space_width > right_xpos)) {
-                /* replace the former separator '\0' of left and 
-                   right string with a space */
-                *(--format_align[i][curr_subline[i]].right) = ' ';
-                /* calculate the new width and position of the string */
-                left_width = left_width + space_width + right_width;
-                left_xpos = 0;
-                /* there is no right string anymore */
-                right_width = 0;
-            }
-            /* there is no left string, move right to left */
-            if ((left_width == 0 && center_width == 0 && right_width != 0) &&
-                (left_xpos + left_width > right_xpos)) {
-                /* move the right string to the left string */
-                format_align[i][curr_subline[i]].left = format_align[i][curr_subline[i]].right;
-                /* calculate the new width and position of the string */
-                left_width = right_width;
-                left_xpos = 0;
-                /* there is no right string anymore */
-                right_width = 0;
-            }
-
-#endif
-
-            if (flags & WPS_REFRESH_SCROLL) {
-
-                /* scroll line */
-                if ((refresh_mode & WPS_REFRESH_SCROLL) ||
-                    new_subline_refresh) {
-#ifdef HAVE_LCD_BITMAP
-                    ypos = (i*string_height)+lcd_getymargin();
-                    update_line = true;
-
-                    if (left_width>LCD_WIDTH) {
-                        lcd_puts_scroll(0, i, format_align[i][curr_subline[i]].left);
-                    } else {
-                        /* clear the line first */
-                        lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
-                        lcd_fillrect(0, ypos, LCD_WIDTH, string_height);
-                        lcd_set_drawmode(DRMODE_SOLID);
-
-                        /* Nasty hack: we output an empty scrolling string,
-                           which will reset the scroller for that line */
-                        lcd_puts_scroll(0, i, "");
-                        
-                        /* print aligned strings */
-                        if (left_width != 0)
-                        {
-                            lcd_putsxy(left_xpos, ypos, format_align[i][curr_subline[i]].left);
-                        }
-                        if (center_width != 0)
-                        {
-                            lcd_putsxy(center_xpos, ypos, format_align[i][curr_subline[i]].center);
-                        }
-                        if (right_width != 0)
-                        {
-                            lcd_putsxy(right_xpos, ypos, format_align[i][curr_subline[i]].right);
-                        }
-                    }
-#else
-                    lcd_puts_scroll(0, i, buf);
-                    update_line = true;
-#endif
-                }
-            }
-            else if (flags & (WPS_REFRESH_DYNAMIC | WPS_REFRESH_STATIC))
-            {
-                /* dynamic / static line */
-                if ((refresh_mode & (WPS_REFRESH_DYNAMIC|WPS_REFRESH_STATIC)) ||
-                    new_subline_refresh)
-                {
-#ifdef HAVE_LCD_BITMAP
-                    ypos = (i*string_height)+lcd_getymargin();
-                    update_line = true;
-
-                    /* clear the line first */
-                    lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
-                    lcd_fillrect(0, ypos, LCD_WIDTH, string_height);
-                    lcd_set_drawmode(DRMODE_SOLID);
-
-                    /* Nasty hack: we output an empty scrolling string,
-                       which will reset the scroller for that line */
-                    lcd_puts_scroll(0, i, "");
-                        
-                    /* print aligned strings */
-                    if (left_width != 0)
-                    {
-                        lcd_putsxy(left_xpos, ypos, format_align[i][curr_subline[i]].left);
-                    }
-                    if (center_width != 0)
-                    {
-                        lcd_putsxy(center_xpos, ypos, format_align[i][curr_subline[i]].center);
-                    }
-                    if (right_width != 0)
-                    {
-                        lcd_putsxy(right_xpos, ypos, format_align[i][curr_subline[i]].right);
-                    }
-#else
-                    update_line = true;
-                    lcd_puts(0, i, buf);
-#endif
-                }
-            }
-        }
-#ifdef HAVE_LCD_BITMAP
-        if (update_line) {
-            lcd_update_rect(0, i*h + offset, LCD_WIDTH, h);
-        }
-#endif
-    }
-
-#ifdef HAVE_LCD_BITMAP
-    /* Display all images */
-    for (i = 0; i < MAX_IMAGES; i++) {
-        if(img[i].always_display)
-           img[i].display = img[i].always_display;
-    }
-    wps_display_images();
-    
-    /* Now we know wether the peak meter is used.
-       So we can enable / disable the peak meter thread */
-    peak_meter_enabled = enable_pm;
-#endif
-
-#if defined(CONFIG_BACKLIGHT) && !defined(SIMULATOR)
-    if (global_settings.caption_backlight && id3) {
-        /* turn on backlight n seconds before track ends, and turn it off n
-           seconds into the new track. n == backlight_timeout, or 5s */
-        int n =
-            backlight_timeout_value[global_settings.backlight_timeout] * 1000;
-
-        if ( n < 1000 )
-            n = 5000; /* use 5s if backlight is always on or off */
-
-        if ((id3->elapsed < 1000) ||
-            ((id3->length - id3->elapsed) < (unsigned)n))
-            backlight_on();
-    }
-#endif
-    return true;
-}
-
-bool wps_display(struct mp3entry* id3,
-                 struct mp3entry* nid3)
-{
-    if (!id3 && !(audio_status() & AUDIO_STATUS_PLAY))
-    {
-        global_settings.resume_index = -1;
-#ifdef HAVE_LCD_CHARCELLS
-        gui_syncsplash(HZ, true, str(LANG_END_PLAYLIST_PLAYER));
-#else
-        status_draw(true);
-        gui_syncsplash(HZ, true, str(LANG_END_PLAYLIST_RECORDER));
-#endif
-        return true;
-    }
-    else
-    {
-        lcd_clear_display();
-
-        if (!wps_loaded) {
-            if ( !format_buffer[0] ) {
-#ifdef HAVE_LCD_BITMAP
-                wps_format("%s%?it<%?in<%in. |>%it|%fn>\n"
-                           "%s%?ia<%ia|%?d2<%d2|(root)>>\n"
-                           "%s%?id<%id|%?d1<%d1|(root)>> %?iy<(%iy)|>\n"
-                           "\n"
-                           "%al%pc/%pt%ar[%pp:%pe]\n"
-                           "%fbkBit %?fv<avg|> %?iv<(id3v%iv)|(no id3)>\n"
-                           "%pb\n"
-                           "%pm\n", NULL, 0);
-#else
-                wps_format("%s%pp/%pe: %?it<%it|%fn> - %?ia<%ia|%d2> - %?id<%id|%d1>\n"
-                           "%pc%?ps<*|/>%pt\n", NULL, 0);
-#endif
-            }
-        }
-    }
-    yield();
-    wps_refresh(id3, nid3, 0, WPS_REFRESH_ALL);
-    status_draw(true);
-#ifdef HAVE_LCD_BITMAP
-    wps_display_images();
-#endif
-    lcd_update();
-    return false;
-}
-
-#ifdef HAVE_LCD_CHARCELLS
-static bool draw_player_progress(const struct mp3entry* id3,
-                                 int ff_rewwind_count)
-{
-    char player_progressbar[7];
-    char binline[36];
-    int songpos = 0;
-    int i,j;
-
-    if (!id3)
-        return false;
-
-    memset(binline, 1, sizeof binline);
-    memset(player_progressbar, 1, sizeof player_progressbar);
-
-    if(id3->elapsed >= id3->length)
-        songpos = 0;
-    else
-    {
-        if(wps_time_countup == false)
-            songpos = ((id3->elapsed - ff_rewwind_count) * 36) / id3->length;
-        else
-            songpos = ((id3->elapsed + ff_rewwind_count) * 36) / id3->length;
-    }
-    for (i=0; i < songpos; i++)
-        binline[i] = 0;
-
-    for (i=0; i<=6; i++) {
-        for (j=0;j<5;j++) {
-            player_progressbar[i] <<= 1;
-            player_progressbar[i] += binline[i*5+j];
-        }
-    }
-    lcd_define_pattern(wps_progress_pat[0], player_progressbar);
-    return true;
-}
-
-static void draw_player_fullbar(char* buf, int buf_size,
-                                const struct mp3entry* id3,
-                                int ff_rewwind_count)
-{
-    int i,j,lcd_char_pos;
-
-    char player_progressbar[7];
-    char binline[36];
-    static const char numbers[12][4][3]={
-        {{1,1,1},{1,0,1},{1,0,1},{1,1,1}},/*0*/
-        {{0,1,0},{1,1,0},{0,1,0},{0,1,0}},/*1*/
-        {{1,1,1},{0,0,1},{0,1,0},{1,1,1}},/*2*/
-        {{1,1,1},{0,0,1},{0,1,1},{1,1,1}},/*3*/
-        {{1,0,0},{1,1,0},{1,1,1},{0,1,0}},/*4*/
-        {{1,1,1},{1,1,0},{0,0,1},{1,1,0}},/*5*/
-        {{1,1,1},{1,0,0},{1,1,1},{1,1,1}},/*6*/
-        {{1,1,1},{0,0,1},{0,1,0},{1,0,0}},/*7*/
-        {{1,1,1},{1,1,1},{1,0,1},{1,1,1}},/*8*/
-        {{1,1,1},{1,1,1},{0,0,1},{1,1,1}},/*9*/
-        {{0,0,0},{0,1,0},{0,0,0},{0,1,0}},/*:*/
-        {{0,0,0},{0,0,0},{0,0,0},{0,0,0}} /*<blank>*/
-    };
-
-    int songpos = 0;
-    int digits[6];
-    int time;
-    char timestr[7];
-
-    for (i=0; i < buf_size; i++)
-        buf[i] = ' ';
-
-    if(id3->elapsed >= id3->length)
-        songpos = 55;
-    else {
-        if(wps_time_countup == false)
-            songpos = ((id3->elapsed - ff_rewwind_count) * 55) / id3->length;
-        else
-            songpos = ((id3->elapsed + ff_rewwind_count) * 55) / id3->length;
-    }
-
-    time=(id3->elapsed + ff_rewind_count);
-
-    memset(timestr, 0, sizeof(timestr));
-    wps_format_time(timestr, sizeof(timestr), time);
-    for(lcd_char_pos=0; lcd_char_pos<6; lcd_char_pos++) {
-        digits[lcd_char_pos] = map_fullbar_char(timestr[lcd_char_pos]);
-    }
-
-    /* build the progressbar-icons */
-    for (lcd_char_pos=0; lcd_char_pos<6; lcd_char_pos++) {
-        memset(binline, 0, sizeof binline);
-        memset(player_progressbar, 0, sizeof player_progressbar);
-
-        /* make the character (progressbar & digit)*/
-        for (i=0; i<7; i++) {
-            for (j=0;j<5;j++) {
-                /* make the progressbar */
-                if (lcd_char_pos==(songpos/5)) {
-                    /* partial */
-                    if ((j<(songpos%5))&&(i>4))
-                        binline[i*5+j] = 1;
-                    else
-                        binline[i*5+j] = 0;
-                }
-                else {
-                    if (lcd_char_pos<(songpos/5)) {
-                        /* full character */
-                        if (i>4)
-                            binline[i*5+j] = 1;
-                    }
-                }
-                /* insert the digit */
-                if ((j<3)&&(i<4)) {
-                    if (numbers[digits[lcd_char_pos]][i][j]==1)
-                        binline[i*5+j] = 1;
-                }
-            }
-        }
-
-        for (i=0; i<=6; i++) {
-            for (j=0;j<5;j++) {
-                player_progressbar[i] <<= 1;
-                player_progressbar[i] += binline[i*5+j];
-            }
-        }
-
-        lcd_define_pattern(wps_progress_pat[lcd_char_pos+1],player_progressbar);
-        buf[lcd_char_pos]=wps_progress_pat[lcd_char_pos+1];
-
-    }
-
-    /* make rest of the progressbar if necessary */
-    if (songpos/5>5) {
-
-        /* set the characters positions that use the full 5 pixel wide bar */
-        for (lcd_char_pos=6; lcd_char_pos < (songpos/5); lcd_char_pos++)
-            buf[lcd_char_pos] = 0x86; /* '_' */
-
-        /* build the partial bar character for the tail character position */
-        memset(binline, 0, sizeof binline);
-        memset(player_progressbar, 0, sizeof player_progressbar);
-
-        for (i=5; i<7; i++) {
-            for (j=0;j<5;j++) {
-                if (j<(songpos%5)) {
-                    binline[i*5+j] = 1;
-                }
-            }
-        }
-
-        for (i=0; i<7; i++) {
-            for (j=0;j<5;j++) {
-                player_progressbar[i] <<= 1;
-                player_progressbar[i] += binline[i*5+j];
-            }
-        }
-
-        lcd_define_pattern(wps_progress_pat[7],player_progressbar);
-
-        buf[songpos/5]=wps_progress_pat[7];
-    }
-}
-
-static char map_fullbar_char(char ascii_val)
-{
-    if (ascii_val >= '0' && ascii_val <= '9') {
-        return(ascii_val - '0');
-    }
-    else if (ascii_val == ':') {
-        return(10);
-    }
-    else
-        return(11); /* anything besides a number or ':' is mapped to <blank> */
-}
-
-
-#endif
-
-/* -----------------------------------------------------------------
- * vim: et sw=4 ts=8 sts=4 tw=78
- */
diff --git a/apps/wps-display.h b/apps/wps-display.h
deleted file mode 100644
index b23c0d6..0000000
--- a/apps/wps-display.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2002 Björn Stenberg
- *
- * All files in this archive are subject to the GNU General Public License.
- * See the file COPYING in the source tree root for full license agreement.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#ifndef WPS_DISPLAY
-#define WPS_DISPLAY
-
-#include <stdbool.h>
-#include "id3.h"
-
-/* constants used in line_type and as refresh_mode for wps_refresh */
-#define WPS_REFRESH_STATIC          1    /* line doesn't change over time */
-#define WPS_REFRESH_DYNAMIC         2    /* line may change (e.g. time flag) */
-#define WPS_REFRESH_SCROLL          4    /* line scrolls */
-#define WPS_REFRESH_PLAYER_PROGRESS 8    /* line contains a progress bar */
-#define WPS_REFRESH_PEAK_METER      16   /* line contains a peak meter */
-#define WPS_REFRESH_ALL             0xff /* to refresh all line types */
-/* to refresh only those lines that change over time */
-#define WPS_REFRESH_NON_STATIC (WPS_REFRESH_ALL & ~WPS_REFRESH_STATIC & ~WPS_REFRESH_SCROLL)
-
-/* alignments */
-#define WPS_ALIGN_RIGHT 32
-#define WPS_ALIGN_CENTER 64
-#define WPS_ALIGN_LEFT 128
-
-
-void wps_format_time(char* buf, int buf_size, long time);
-bool wps_refresh(struct mp3entry* id3, struct mp3entry* nid3,
-                 int ffwd_offset, unsigned char refresh_mode);
-bool wps_display(struct mp3entry* id3, struct mp3entry* nid3);
-bool wps_load(const char* file, bool display);
-void wps_reset(void);
-
-#endif
diff --git a/apps/wps.c b/apps/wps.c
deleted file mode 100644
index 573444f..0000000
--- a/apps/wps.c
+++ /dev/null
@@ -1,882 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2002 Jerome Kuptz
- *
- * All files in this archive are subject to the GNU General Public License.
- * See the file COPYING in the source tree root for full license agreement.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "system.h"
-#include "file.h"
-#include "lcd.h"
-#include "font.h"
-#include "backlight.h"
-#include "button.h"
-#include "kernel.h"
-#include "tree.h"
-#include "debug.h"
-#include "sprintf.h"
-#include "settings.h"
-#include "wps.h"
-#include "wps-display.h"
-#include "audio.h"
-#include "mp3_playback.h"
-#include "usb.h"
-#include "status.h"
-#include "main_menu.h"
-#include "ata.h"
-#include "screens.h"
-#include "playlist.h"
-#ifdef HAVE_LCD_BITMAP
-#include "icons.h"
-#include "peakmeter.h"
-#endif
-#include "action.h"
-#include "lang.h"
-#include "bookmark.h"
-#include "misc.h"
-#include "sound.h"
-#include "onplay.h"
-#include "abrepeat.h"
-#include "playback.h"
-#include "splash.h"
-
-#define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */ 
-                                /* 3% of 30min file == 54s step size */
-#define MIN_FF_REWIND_STEP 500
-
-bool keys_locked = false;
-static bool ff_rewind = false;
-static bool paused = false;
-static struct mp3entry* id3 = NULL;
-static struct mp3entry* nid3 = NULL;
-static char current_track_path[MAX_PATH+1];
-
-/* set volume
-   return true if screen restore is needed
-   return false otherwise
-*/
-static bool setvol(void)
-{
-    if (global_settings.volume < sound_min(SOUND_VOLUME))
-        global_settings.volume = sound_min(SOUND_VOLUME);
-    if (global_settings.volume > sound_max(SOUND_VOLUME))
-        global_settings.volume = sound_max(SOUND_VOLUME);
-    sound_set_volume(global_settings.volume);
-    status_draw(false);
-    wps_refresh(id3, nid3, 0, WPS_REFRESH_NON_STATIC);
-    settings_save();
-#ifdef HAVE_LCD_CHARCELLS
-    gui_syncsplash(0, false, "Vol: %d %%   ",
-           sound_val2phys(SOUND_VOLUME, global_settings.volume));
-    return true;
-#endif
-    return false;
-}
-
-static bool ffwd_rew(int button)
-{
-    static const int ff_rew_steps[] = {
-      1000, 2000, 3000, 4000,
-      5000, 6000, 8000, 10000,
-      15000, 20000, 25000, 30000,
-      45000, 60000
-    };
-
-    unsigned int step = 0;     /* current ff/rewind step */ 
-    unsigned int max_step = 0; /* maximum ff/rewind step */ 
-    int ff_rewind_count = 0;   /* current ff/rewind count (in ticks) */
-    int direction = -1;         /* forward=1 or backward=-1 */
-    long accel_tick = 0;       /* next time at which to bump the step size */
-    bool exit = false;
-    bool usb = false;
-
-    while (!exit) {
-        switch ( button ) {
-            case WPS_FFWD:
-#ifdef WPS_RC_FFWD 
-            case WPS_RC_FFWD:
-#endif
-                 direction = 1;
-            case WPS_REW:
-#ifdef WPS_RC_REW
-            case WPS_RC_REW:
-#endif
-                if (ff_rewind)
-                {
-                    if (direction == 1)
-                    {
-                        /* fast forwarding, calc max step relative to end */
-                        max_step =
-                            (id3->length - (id3->elapsed + ff_rewind_count)) *
-                            FF_REWIND_MAX_PERCENT / 100;
-                    }
-                    else
-                    {
-                        /* rewinding, calc max step relative to start */
-                        max_step = (id3->elapsed + ff_rewind_count) *
-                            FF_REWIND_MAX_PERCENT / 100;
-                    }
-
-                    max_step = MAX(max_step, MIN_FF_REWIND_STEP);
-
-                    if (step > max_step)
-                        step = max_step;
-
-                    ff_rewind_count += step * direction;
-
-                    if (global_settings.ff_rewind_accel != 0 && 
-                        current_tick >= accel_tick)
-                    { 
-                        step *= 2;
-                        accel_tick = current_tick +
-                            global_settings.ff_rewind_accel*HZ; 
-                    } 
-                }
-                else
-                {
-                    if ( (audio_status() & AUDIO_STATUS_PLAY) &&
-                          id3 && id3->length )
-                    {
-                        if (!paused)
-                            audio_pause();
-#if CONFIG_KEYPAD == PLAYER_PAD
-                        lcd_stop_scroll();
-#endif
-                        if (direction > 0) 
-                            status_set_ffmode(STATUS_FASTFORWARD);
-                        else
-                            status_set_ffmode(STATUS_FASTBACKWARD);
-
-                        ff_rewind = true;
-
-                        step = ff_rew_steps[global_settings.ff_rewind_min_step];
-
-                        accel_tick = current_tick +
-                            global_settings.ff_rewind_accel*HZ; 
-                    }
-                    else
-                        break;
-                }
-
-                if (direction > 0) {
-                    if ((id3->elapsed + ff_rewind_count) > id3->length)
-                        ff_rewind_count = id3->length - id3->elapsed;
-                }
-                else {
-                    if ((int)(id3->elapsed + ff_rewind_count) < 0)
-                        ff_rewind_count = -id3->elapsed;
-                }
-
-                if(wps_time_countup == false)
-                    wps_refresh(id3, nid3, -ff_rewind_count,
-                                WPS_REFRESH_PLAYER_PROGRESS |
-                                WPS_REFRESH_DYNAMIC);
-                else
-                    wps_refresh(id3, nid3, ff_rewind_count,
-                                WPS_REFRESH_PLAYER_PROGRESS |
-                                WPS_REFRESH_DYNAMIC);
-
-                break;
-
-            case WPS_PREV:
-            case WPS_NEXT: 
-#ifdef WPS_RC_PREV
-            case WPS_RC_PREV:
-            case WPS_RC_NEXT:
-#endif
-                audio_ff_rewind(id3->elapsed+ff_rewind_count);
-                ff_rewind_count = 0;
-                ff_rewind = false;
-                status_set_ffmode(0);
-                if (!paused)
-                    audio_resume();
-#ifdef HAVE_LCD_CHARCELLS
-                wps_display(id3, nid3);
-#endif
-                exit = true;
-                break;
-
-            default:
-                if(default_event_handler(button) == SYS_USB_CONNECTED) {
-                    status_set_ffmode(0);
-                    usb = true;
-                    exit = true;
-                }
-                break;
-        }
-        if (!exit)
-            button = button_get(true);
-    }
-
-    /* let audio thread update id3->elapsed before calling wps_refresh */
-    yield(); 
-    wps_refresh(id3, nid3, 0, WPS_REFRESH_ALL);
-    return usb;
-}
-
-static bool update(void)
-{
-    bool track_changed = audio_has_changed_track();
-    bool retcode = false;
-
-    nid3 = audio_next_track();
-    if (track_changed)
-    {
-        lcd_stop_scroll();
-        id3 = audio_current_track();
-        if (wps_display(id3, nid3))
-            retcode = true;
-        else
-            wps_refresh(id3, nid3, 0, WPS_REFRESH_ALL);
-
-        if (id3)
-            memcpy(current_track_path, id3->path, sizeof(current_track_path));
-    }
-
-    if (id3)
-        wps_refresh(id3, nid3, 0, WPS_REFRESH_NON_STATIC);
-
-    status_draw(false);
-
-    return retcode;
-}
-
-static void fade(bool fade_in)
-{
-    unsigned fp_global_vol = global_settings.volume << 8;
-    unsigned fp_step = fp_global_vol / 30;
-
-    if (fade_in) {
-        /* fade in */
-        unsigned fp_volume = 0;
-
-        /* zero out the sound */
-        sound_set_volume(0);
-
-        sleep(HZ/10); /* let audio thread run */
-        audio_resume();
-        
-        while (fp_volume < fp_global_vol) {
-            fp_volume += fp_step;
-            sleep(1);
-            sound_set_volume(fp_volume >> 8);
-        }
-        sound_set_volume(global_settings.volume);
-    }
-    else {
-        /* fade out */
-        unsigned fp_volume = fp_global_vol;
-
-        while (fp_volume > fp_step) {
-            fp_volume -= fp_step;
-            sleep(1);
-            sound_set_volume(fp_volume >> 8);
-        }
-        audio_pause();
-#ifndef SIMULATOR
-        /* let audio thread run and wait for the mas to run out of data */
-        while (!mp3_pause_done())
-#endif
-            sleep(HZ/10);
-
-        /* reset volume to what it was before the fade */
-        sound_set_volume(global_settings.volume);
-    }
-}
-
-
-#ifdef WPS_KEYLOCK
-static void display_keylock_text(bool locked)
-{
-    char* s;
-    lcd_stop_scroll();
-#ifdef HAVE_LCD_CHARCELLS
-    if(locked)
-        s = str(LANG_KEYLOCK_ON_PLAYER);
-    else
-        s = str(LANG_KEYLOCK_OFF_PLAYER);
-#else
-    if(locked)
-        s = str(LANG_KEYLOCK_ON_RECORDER);
-    else
-        s = str(LANG_KEYLOCK_OFF_RECORDER);
-#endif
-    gui_syncsplash(HZ, true, s);
-}
-
-static void waitfor_nokey(void)
-{
-    /* wait until all keys are released */
-    while (button_get(false) != BUTTON_NONE)
-        yield();
-}
-#endif
-
-/* demonstrates showing different formats from playtune */
-long wps_show(void)
-{
-    long button = 0, lastbutton = 0;
-    bool ignore_keyup = true;
-    bool restore = false;
-    long restoretimer = 0; /* timer to delay screen redraw temporarily */
-    bool exit = false;
-    bool update_track = false;
-    unsigned long right_lastclick = 0;
-    unsigned long left_lastclick = 0;
-
-    id3 = nid3 = NULL;
-    current_track_path[0] = '\0';
-
-#ifdef HAVE_LCD_CHARCELLS
-    status_set_audio(true);
-    status_set_param(false);
-#else
-    if(global_settings.statusbar)
-        lcd_setmargins(0, STATUSBAR_HEIGHT);
-    else
-        lcd_setmargins(0, 0);
-#endif
-
-#ifdef AB_REPEAT_ENABLE
-    ab_repeat_init();
-    ab_reset_markers();
-#endif
-
-    ff_rewind = false;
-
-    if(audio_status() & AUDIO_STATUS_PLAY)
-    {
-        id3 = audio_current_track();
-        nid3 = audio_next_track();
-        if (id3) {
-            if (wps_display(id3, nid3))
-                return 0;
-            wps_refresh(id3, nid3, 0, WPS_REFRESH_ALL);
-
-            memcpy(current_track_path, id3->path, sizeof(current_track_path));
-        }
-
-        restore = true;
-    }
-
-    while ( 1 )
-    {
-        bool audio_paused = (audio_status() & AUDIO_STATUS_PAUSE)?true:false;
-        
-        /* did someone else (i.e power thread) change audio pause mode? */
-        if (paused != audio_paused) {
-            paused = audio_paused;
-
-            /* if another thread paused audio, we are probably in car mode,
-               about to shut down. lets save the settings. */
-            if (paused) {
-                settings_save();
-#if !defined(HAVE_RTC) && !defined(HAVE_SW_POWEROFF)
-                ata_flush();
-#endif
-            }
-        }
-
-#ifdef HAVE_LCD_BITMAP
-        /* when the peak meter is enabled we want to have a
-            few extra updates to make it look smooth. On the
-            other hand we don't want to waste energy if it
-            isn't displayed */
-        if (peak_meter_enabled) {
-            long next_refresh = current_tick;
-            long next_big_refresh = current_tick + HZ / 5;
-            button = BUTTON_NONE;
-            while (TIME_BEFORE(current_tick, next_big_refresh)) {
-                button = button_get(false);
-                if (button != BUTTON_NONE) {
-                    break;
-                }
-                peak_meter_peek();
-                sleep(0);   /* Sleep until end of current tick. */  
-
-                if (TIME_AFTER(current_tick, next_refresh)) {
-                    wps_refresh(id3, nid3, 0, WPS_REFRESH_PEAK_METER);
-                    next_refresh += HZ / PEAK_METER_FPS;
-                }
-            }
-
-        }
-
-        /* The peak meter is disabled
-           -> no additional screen updates needed */
-        else {
-            button = button_get_w_tmo(HZ/5);
-        }
-#else
-        button = button_get_w_tmo(HZ/5);
-#endif
-
-        /* discard first event if it's a button release */
-        if (button && ignore_keyup)
-        {
-            ignore_keyup = false;
-            /* Negative events are system events */
-            if (button >= 0 && button & BUTTON_REL )
-                continue;
-        }
-
-#ifdef WPS_KEYLOCK
-        /* ignore non-remote buttons when keys are locked */
-        if (keys_locked &&
-            ! ((button < 0) ||
-               (button == BUTTON_NONE) ||
-               ((button & WPS_KEYLOCK) == WPS_KEYLOCK) ||
-               (button & BUTTON_REMOTE)
-                ))
-        {
-            if (!(button & BUTTON_REL))
-                display_keylock_text(true);
-            restore = true;
-            button = BUTTON_NONE;
-        }
-#endif
-
-        /* Exit if audio has stopped playing. This can happen if using the
-           sleep timer with the charger plugged or if starting a recording
-           from F1 */
-        if (!audio_status())
-            exit = true;
-
-        switch(button)
-        {
-#ifdef WPS_CONTEXT
-            case WPS_CONTEXT:
-                onplay(id3->path, TREE_ATTR_MPA, CONTEXT_WPS);
-                restore = true;
-                break;
-#endif
-
-#ifdef WPS_RC_BROWSE
-            case WPS_RC_BROWSE:
-#endif
-            case WPS_BROWSE:
-#ifdef WPS_BROWSE_PRE
-                if ((lastbutton != WPS_BROWSE_PRE)
-#ifdef WPS_RC_BROWSE_PRE
-                    && (lastbutton != WPS_RC_BROWSE_PRE)
-#endif
-                    )
-                    break;
-#endif
-#ifdef HAVE_LCD_CHARCELLS
-                status_set_record(false);
-                status_set_audio(false);
-#endif
-                lcd_stop_scroll();
-
-                /* set dir browser to current playing song */
-                if (global_settings.browse_current &&
-                    current_track_path[0] != '\0')
-                    set_current_file(current_track_path);
-
-                return 0;
-                break;
-
-                /* play/pause */
-            case WPS_PAUSE:
-#ifdef WPS_PAUSE_PRE
-                if (lastbutton != WPS_PAUSE_PRE)
-                    break;
-#endif
-#ifdef WPS_RC_PAUSE
-            case WPS_RC_PAUSE:
-#ifdef WPS_RC_PAUSE_PRE
-                if ((button == WPS_RC_PAUSE) && (lastbutton != WPS_RC_PAUSE_PRE))
-                    break;
-#endif
-#endif
-                if ( paused )
-                {
-                    paused = false;
-                    if ( global_settings.fade_on_stop )
-                        fade(1);
-                    else
-                        audio_resume();
-                }
-                else
-                {
-                    paused = true;
-                    if ( global_settings.fade_on_stop )
-                        fade(0);
-                    else
-                        audio_pause();
-                    settings_save();
-#if !defined(HAVE_RTC) && !defined(HAVE_SW_POWEROFF)
-                    ata_flush();   /* make sure resume info is saved */
-#endif
-                }
-                break;
-
-                /* volume up */
-            case WPS_INCVOL:
-            case WPS_INCVOL | BUTTON_REPEAT:
-#ifdef WPS_RC_INCVOL
-            case WPS_RC_INCVOL:
-            case WPS_RC_INCVOL | BUTTON_REPEAT:
-#endif
-                global_settings.volume++;
-                if (setvol()) {
-                    restore = true;
-                    restoretimer = current_tick + HZ;
-                }
-                break;
-
-                /* volume down */
-            case WPS_DECVOL:
-            case WPS_DECVOL | BUTTON_REPEAT:
-#ifdef WPS_RC_DECVOL
-            case WPS_RC_DECVOL:
-            case WPS_RC_DECVOL | BUTTON_REPEAT:
-#endif
-                global_settings.volume--;
-                if (setvol()) {
-                    restore = true;
-                    restoretimer = current_tick + HZ;
-                }
-                break;
-
-                /* fast forward / rewind */
-#ifdef WPS_RC_FFWD
-            case WPS_RC_FFWD:
-#endif
-            case WPS_FFWD:
-#ifdef WPS_NEXT_DIR
-                if (current_tick - right_lastclick < HZ)
-                {
-                    audio_next_dir();
-                    right_lastclick = 0;
-                    break;   
-                }
-#endif
-#ifdef WPS_RC_REW
-            case WPS_RC_REW:
-#endif
-            case WPS_REW:
-#ifdef WPS_PREV_DIR
-                if (current_tick - left_lastclick < HZ)
-                {
-                    audio_prev_dir();
-                    left_lastclick = 0;
-                    break;   
-                }
-#endif
-                ffwd_rew(button);
-                break;
-
-                /* prev / restart */
-            case WPS_PREV:
-#ifdef WPS_PREV_PRE
-                if (lastbutton != WPS_PREV_PRE)
-                    break;
-#endif
-#ifdef WPS_RC_PREV
-            case WPS_RC_PREV:
-#ifdef WPS_RC_PREV_PRE
-                if ((button == WPS_RC_PREV) && (lastbutton != WPS_RC_PREV_PRE))
-                    break;
-#endif
-#endif
-                left_lastclick = current_tick;
-                update_track = true;
-
-#ifdef AB_REPEAT_ENABLE
-                /* if we're in A/B repeat mode and the current position
-                   is past the A marker, jump back to the A marker... */
-                if ( ab_repeat_mode_enabled() && ab_after_A_marker(id3->elapsed) )
-                {
-                    ab_jump_to_A_marker();
-                    break;
-                }
-                /* ...otherwise, do it normally */
-#endif
-
-                if (!id3 || (id3->elapsed < 3*1000)) {
-                    audio_prev();
-                }
-                else {
-                    if (!paused)
-                        audio_pause();
-
-                    audio_ff_rewind(0);
-
-                    if (!paused)
-                        audio_resume();
-                }
-                break;
-
-#ifdef WPS_NEXT_DIR
-#ifdef WPS_RC_NEXT_DIR
-            case WPS_RC_NEXT_DIR:
-#endif
-            case WPS_NEXT_DIR:
-                audio_next_dir();
-                break;
-#endif
-#ifdef WPS_PREV_DIR
-#ifdef WPS_RC_PREV_DIR
-            case WPS_RC_PREV_DIR:
-#endif
-            case WPS_PREV_DIR:
-                audio_prev_dir();
-                break;
-#endif
-
-                /* next */
-            case WPS_NEXT:
-#ifdef WPS_NEXT_PRE
-                if (lastbutton != WPS_NEXT_PRE)
-                    break; 
-#endif
-#ifdef WPS_RC_NEXT
-            case WPS_RC_NEXT:
-#ifdef WPS_RC_NEXT_PRE
-                if ((button == WPS_RC_NEXT) && (lastbutton != WPS_RC_NEXT_PRE))
-                    break;
-#endif
-#endif
-                right_lastclick = current_tick;
-                update_track = true;
-
-#ifdef AB_REPEAT_ENABLE
-                /* if we're in A/B repeat mode and the current position is
-                   before the A marker, jump to the A marker... */
-                if ( ab_repeat_mode_enabled() && ab_before_A_marker(id3->elapsed) )
-                {
-                    ab_jump_to_A_marker();
-                    break;
-                }
-                /* ...otherwise, do it normally */
-#endif
-
-                audio_next();
-                break;
-
-#ifdef WPS_MENU
-            /* menu key functions */
-            case WPS_MENU:
-#ifdef WPS_MENU_PRE
-                if (lastbutton != WPS_MENU_PRE)
-                    break;
-#endif
-#ifdef WPS_RC_MENU
-            case WPS_RC_MENU:
-#ifdef WPS_RC_MENU_PRE
-                if ((button == WPS_RC_MENU) && (lastbutton != WPS_RC_MENU_PRE))
-                    break;
-#endif
-#endif
-                lcd_stop_scroll();
-
-                if (main_menu())
-                    return true;
-#ifdef HAVE_LCD_BITMAP
-                if (global_settings.statusbar)
-                    lcd_setmargins(0, STATUSBAR_HEIGHT);
-                else
-                    lcd_setmargins(0, 0);
-#endif
-                restore = true;
-                break;
-#endif /* WPS_MENU */
-
-#ifdef WPS_KEYLOCK
-            /* key lock */
-            case WPS_KEYLOCK:
-            case WPS_KEYLOCK | BUTTON_REPEAT:
-                keys_locked = !keys_locked;
-                display_keylock_text(keys_locked);
-                restore = true;
-                waitfor_nokey();
-                break;
-#endif
-
-#if (CONFIG_KEYPAD == RECORDER_PAD) || (CONFIG_KEYPAD == IRIVER_H100_PAD)
-                /* play settings */
-            case WPS_QUICK:
-                if (quick_screen(CONTEXT_WPS, WPS_QUICK))
-                    return SYS_USB_CONNECTED;
-                restore = true;
-                lastbutton = 0;
-                break;
-
-                /* screen settings */
-#ifdef BUTTON_F3
-            case BUTTON_F3:
-                if (quick_screen(CONTEXT_WPS, BUTTON_F3))
-                    return SYS_USB_CONNECTED;
-                restore = true;
-                break;
-#endif
-
-                /* pitch screen */
-#if CONFIG_KEYPAD == RECORDER_PAD
-            case BUTTON_ON | BUTTON_UP:
-            case BUTTON_ON | BUTTON_DOWN:
-                if (2 == pitch_screen())
-                    return SYS_USB_CONNECTED;
-                restore = true;
-                break;
-#endif
-#endif
-
-#ifdef AB_REPEAT_ENABLE
-
-#ifdef WPS_AB_SET_A_MARKER
-            /* set A marker for A-B repeat */
-            case WPS_AB_SET_A_MARKER:
-                if (ab_repeat_mode_enabled())
-                    ab_set_A_marker(id3->elapsed);
-                break;
-#endif
-
-#ifdef WPS_AB_SET_B_MARKER
-            /* set B marker for A-B repeat and jump to A */
-            case WPS_AB_SET_B_MARKER:
-                if (ab_repeat_mode_enabled())
-                {
-                    ab_set_B_marker(id3->elapsed);
-                    ab_jump_to_A_marker();
-                    update_track = true;
-                }
-                break;
-#endif
-
-#ifdef WPS_AB_RESET_AB_MARKERS
-            /* reset A&B markers */
-            case WPS_AB_RESET_AB_MARKERS:
-                if (ab_repeat_mode_enabled())
-                {
-                    ab_reset_markers();
-                    update_track = true;
-                }
-                break;
-#endif
-
-#endif /* AB_REPEAT_ENABLE */
-
-                /* stop and exit wps */
-#ifdef WPS_EXIT
-            case WPS_EXIT:
-# ifdef WPS_EXIT_PRE
-                if (lastbutton != WPS_EXIT_PRE)
-                    break;
-# endif
-                exit = true;
-
-# ifdef WPS_RC_EXIT
-            case WPS_RC_EXIT:
-#  ifdef WPS_RC_EXIT_PRE
-                if (lastbutton != WPS_RC_EXIT_PRE)
-                    break;
-#  endif
-                exit = true;
-# endif
-                break;
-#endif
-
-#ifdef WPS_ID3
-            case WPS_ID3:
-                browse_id3();
-                restore = true;
-                break;
-#endif
-                
-            case BUTTON_NONE: /* Timeout */
-                update_track = true;
-                break;
-
-            default:
-                if(default_event_handler(button) == SYS_USB_CONNECTED)
-                    return SYS_USB_CONNECTED;
-                update_track = true;
-                break;
-        }
-
-        if (update_track)
-        {
-            if (update())
-            {
-                /* set dir browser to current playing song */
-                if (global_settings.browse_current &&
-                    current_track_path[0] != '\0')
-                    set_current_file(current_track_path);
-                
-                return 0;
-            }
-            update_track = false;
-        }
-
-        if (exit) {
-#ifdef HAVE_LCD_CHARCELLS
-            status_set_record(false);
-            status_set_audio(false);
-#endif
-            if (global_settings.fade_on_stop)
-                fade(0);
-                
-            lcd_stop_scroll();
-            bookmark_autobookmark();
-            audio_stop();
-#ifdef AB_REPEAT_ENABLE
-            ab_reset_markers();
-#endif
-
-            /* Keys can be locked when exiting, so either unlock here
-               or implement key locking in tree.c too */
-            keys_locked=false;
-
-            /* set dir browser to current playing song */
-            if (global_settings.browse_current &&
-                current_track_path[0] != '\0')
-                set_current_file(current_track_path);
-            
-            return 0;
-        }
-                    
-        if ( button )
-            ata_spin();
-
-        if (restore &&
-            ((restoretimer == 0) ||
-             (restoretimer < current_tick)))
-        {
-            restore = false;
-            restoretimer = 0;
-            if (wps_display(id3, nid3))
-            {
-                /* set dir browser to current playing song */
-                if (global_settings.browse_current &&
-                    current_track_path[0] != '\0')
-                    set_current_file(current_track_path);
-
-                return 0;
-            }
-
-            if (id3)
-                wps_refresh(id3, nid3, 0, WPS_REFRESH_NON_STATIC);
-        }
-        if (button != BUTTON_NONE)
-            lastbutton = button;
-    }
-    return 0; /* unreachable - just to reduce compiler warnings */
-}
diff --git a/apps/wps.h b/apps/wps.h
deleted file mode 100644
index 61b3d00..0000000
--- a/apps/wps.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/***************************************************************************
- *             __________               __   ___.
- *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
- *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
- *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
- *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
- *                     \/            \/     \/    \/            \/
- * $Id$
- *
- * Copyright (C) 2002 Jerome Kuptz
- *
- * All files in this archive are subject to the GNU General Public License.
- * See the file COPYING in the source tree root for full license agreement.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ****************************************************************************/
-#ifndef _WPS_H
-#define _WPS_H
-#include "id3.h"
-#include "playlist.h"
-
-/* button definitions */
-#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
-    (CONFIG_KEYPAD == IRIVER_H300_PAD)
-#define WPS_NEXT       (BUTTON_RIGHT | BUTTON_REL)
-#define WPS_NEXT_PRE   BUTTON_RIGHT
-#define WPS_PREV       (BUTTON_LEFT | BUTTON_REL)
-#define WPS_PREV_PRE   BUTTON_LEFT
-#define WPS_FFWD       (BUTTON_RIGHT | BUTTON_REPEAT)
-#define WPS_REW        (BUTTON_LEFT | BUTTON_REPEAT)
-#define WPS_INCVOL     BUTTON_UP
-#define WPS_DECVOL     BUTTON_DOWN
-#define WPS_PAUSE      (BUTTON_ON | BUTTON_REL)
-#define WPS_PAUSE_PRE  BUTTON_ON
-#define WPS_MENU       (BUTTON_MODE | BUTTON_REL)
-#define WPS_MENU_PRE   BUTTON_MODE
-#define WPS_BROWSE     (BUTTON_SELECT | BUTTON_REL)
-#define WPS_BROWSE_PRE BUTTON_SELECT
-#define WPS_EXIT       (BUTTON_OFF | BUTTON_REL)
-#define WPS_EXIT_PRE   BUTTON_OFF
-#define WPS_ID3        (BUTTON_MODE | BUTTON_ON)
-#define WPS_CONTEXT    (BUTTON_SELECT | BUTTON_REPEAT)
-#define WPS_QUICK      (BUTTON_MODE | BUTTON_REPEAT)
-#define WPS_NEXT_DIR   (BUTTON_RIGHT | BUTTON_ON)
-#define WPS_PREV_DIR   (BUTTON_LEFT | BUTTON_ON)
-
-#define WPS_RC_NEXT_DIR   (BUTTON_RC_BITRATE | BUTTON_REL)
-#define WPS_RC_PREV_DIR   (BUTTON_RC_SOURCE | BUTTON_REL)
-#define WPS_RC_NEXT    (BUTTON_RC_FF | BUTTON_REL)
-#define WPS_RC_NEXT_PRE BUTTON_RC_FF
-#define WPS_RC_PREV    (BUTTON_RC_REW | BUTTON_REL)
-#define WPS_RC_PREV_PRE BUTTON_RC_REW
-#define WPS_RC_FFWD    (BUTTON_RC_FF | BUTTON_REPEAT)
-#define WPS_RC_REW     (BUTTON_RC_REW | BUTTON_REPEAT)
-#define WPS_RC_PAUSE   BUTTON_RC_ON
-#define WPS_RC_INCVOL  BUTTON_RC_VOL_UP
-#define WPS_RC_DECVOL  BUTTON_RC_VOL_DOWN
-#define WPS_RC_EXIT    (BUTTON_RC_STOP | BUTTON_REL)
-#define WPS_RC_EXIT_PRE BUTTON_RC_STOP
-#define WPS_RC_MENU    (BUTTON_RC_MODE | BUTTON_REL)
-#define WPS_RC_MENU_PRE BUTTON_RC_MODE
-#define WPS_RC_BROWSE  (BUTTON_RC_MENU | BUTTON_REL)
-#define WPS_RC_BROWSE_PRE BUTTON_RC_MENU
-
-#elif CONFIG_KEYPAD == RECORDER_PAD
-#define WPS_NEXT       (BUTTON_RIGHT | BUTTON_REL)
-#define WPS_NEXT_PRE   BUTTON_RIGHT
-#define WPS_PREV       (BUTTON_LEFT | BUTTON_REL)
-#define WPS_PREV_PRE   BUTTON_LEFT
-#define WPS_FFWD       (BUTTON_RIGHT | BUTTON_REPEAT)
-#define WPS_REW        (BUTTON_LEFT | BUTTON_REPEAT)
-#define WPS_INCVOL     BUTTON_UP
-#define WPS_DECVOL     BUTTON_DOWN
-#define WPS_PAUSE_PRE  BUTTON_PLAY
-#define WPS_PAUSE      (BUTTON_PLAY | BUTTON_REL)
-#define WPS_MENU       (BUTTON_F1 | BUTTON_REL)
-#define WPS_MENU_PRE   BUTTON_F1
-#define WPS_BROWSE     (BUTTON_ON | BUTTON_REL)
-#define WPS_BROWSE_PRE BUTTON_ON
-#define WPS_EXIT       BUTTON_OFF
-#define WPS_KEYLOCK    (BUTTON_F1 | BUTTON_DOWN)
-#define WPS_ID3        (BUTTON_F1 | BUTTON_ON)
-#define WPS_CONTEXT    (BUTTON_PLAY | BUTTON_REPEAT)
-#define WPS_QUICK      BUTTON_F2
-
-#ifdef AB_REPEAT_ENABLE
-#define WPS_AB_SET_A_MARKER     (BUTTON_ON | BUTTON_LEFT)
-#define WPS_AB_SET_B_MARKER     (BUTTON_ON | BUTTON_RIGHT)
-#define WPS_AB_RESET_AB_MARKERS (BUTTON_ON | BUTTON_OFF)
-#endif
-
-#define WPS_RC_NEXT    BUTTON_RC_RIGHT
-#define WPS_RC_PREV    BUTTON_RC_LEFT
-#define WPS_RC_PAUSE   BUTTON_RC_PLAY
-#define WPS_RC_INCVOL  BUTTON_RC_VOL_UP
-#define WPS_RC_DECVOL  BUTTON_RC_VOL_DOWN
-#define WPS_RC_EXIT    BUTTON_RC_STOP
-
-#elif CONFIG_KEYPAD == PLAYER_PAD
-#define WPS_NEXT       (BUTTON_RIGHT | BUTTON_REL)
-#define WPS_NEXT_PRE   BUTTON_RIGHT
-#define WPS_PREV       (BUTTON_LEFT | BUTTON_REL)
-#define WPS_PREV_PRE   BUTTON_LEFT
-#define WPS_FFWD       (BUTTON_RIGHT | BUTTON_REPEAT)
-#define WPS_REW        (BUTTON_LEFT | BUTTON_REPEAT)
-#define WPS_INCVOL     (BUTTON_MENU | BUTTON_RIGHT)
-#define WPS_DECVOL     (BUTTON_MENU | BUTTON_LEFT)
-#define WPS_PAUSE_PRE  BUTTON_PLAY
-#define WPS_PAUSE      (BUTTON_PLAY | BUTTON_REL)
-#define WPS_MENU       (BUTTON_MENU | BUTTON_REL)
-#define WPS_MENU_PRE   BUTTON_MENU
-#define WPS_BROWSE     (BUTTON_ON | BUTTON_REL)
-#define WPS_BROWSE_PRE BUTTON_ON
-#define WPS_EXIT       BUTTON_STOP
-#define WPS_KEYLOCK    (BUTTON_MENU | BUTTON_STOP)
-#define WPS_ID3        (BUTTON_MENU | BUTTON_ON)
-#define WPS_CONTEXT    (BUTTON_PLAY | BUTTON_REPEAT)
-
-#ifdef AB_REPEAT_ENABLE
-#define WPS_AB_SET_A_MARKER     (BUTTON_ON | BUTTON_LEFT)
-#define WPS_AB_SET_B_MARKER     (BUTTON_ON | BUTTON_RIGHT)
-#define WPS_AB_RESET_AB_MARKERS (BUTTON_ON | BUTTON_STOP)
-#endif
-
-#define WPS_RC_NEXT    BUTTON_RC_RIGHT
-#define WPS_RC_PREV    BUTTON_RC_LEFT
-#define WPS_RC_PAUSE   BUTTON_RC_PLAY
-#define WPS_RC_INCVOL  BUTTON_RC_VOL_UP
-#define WPS_RC_DECVOL  BUTTON_RC_VOL_DOWN
-#define WPS_RC_EXIT    BUTTON_RC_STOP
-
-#elif CONFIG_KEYPAD == ONDIO_PAD
-#define WPS_NEXT       (BUTTON_RIGHT | BUTTON_REL)
-#define WPS_NEXT_PRE   BUTTON_RIGHT
-#define WPS_PREV       (BUTTON_LEFT | BUTTON_REL)
-#define WPS_PREV_PRE   BUTTON_LEFT
-#define WPS_FFWD       (BUTTON_RIGHT | BUTTON_REPEAT)
-#define WPS_REW        (BUTTON_LEFT | BUTTON_REPEAT)
-#define WPS_INCVOL     BUTTON_UP
-#define WPS_DECVOL     BUTTON_DOWN
-#define WPS_PAUSE      BUTTON_OFF
-/* #define WPS_MENU    Ondio can't have both main menu and context menu in wps */
-#define WPS_BROWSE     (BUTTON_MENU | BUTTON_REL)
-#define WPS_BROWSE_PRE BUTTON_MENU
-#define WPS_KEYLOCK    (BUTTON_MENU | BUTTON_DOWN)
-#define WPS_EXIT       (BUTTON_OFF | BUTTON_REPEAT)
-#define WPS_CONTEXT    (BUTTON_MENU | BUTTON_REPEAT)
-
-#elif CONFIG_KEYPAD == GMINI100_PAD
-#define WPS_NEXT       (BUTTON_RIGHT | BUTTON_REL)
-#define WPS_NEXT_PRE   BUTTON_RIGHT
-#define WPS_PREV       (BUTTON_LEFT | BUTTON_REL)
-#define WPS_PREV_PRE   BUTTON_LEFT
-#define WPS_FFWD       (BUTTON_RIGHT | BUTTON_REPEAT)
-#define WPS_REW        (BUTTON_LEFT | BUTTON_REPEAT)
-#define WPS_INCVOL     BUTTON_UP
-#define WPS_DECVOL     BUTTON_DOWN
-#define WPS_PAUSE      BUTTON_PLAY
-#define WPS_MENU       (BUTTON_MENU | BUTTON_REL)
-#define WPS_MENU_PRE   BUTTON_MENU
-#define WPS_BROWSE     (BUTTON_ON | BUTTON_REL)
-#define WPS_BROWSE_PRE BUTTON_ON
-#define WPS_EXIT       BUTTON_OFF
-#define WPS_KEYLOCK    (BUTTON_MENU | BUTTON_DOWN)
-#define WPS_ID3        (BUTTON_MENU | BUTTON_ON)
-
-#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_NANO_PAD)
-
-/* TODO: Check WPS button assignments */
-
-#define WPS_NEXT       (BUTTON_RIGHT | BUTTON_REL)
-#define WPS_NEXT_PRE   BUTTON_RIGHT
-#define WPS_PREV       (BUTTON_LEFT | BUTTON_REL)
-#define WPS_PREV_PRE   BUTTON_LEFT
-#define WPS_FFWD       (BUTTON_RIGHT | BUTTON_REPEAT)
-#define WPS_REW        (BUTTON_LEFT | BUTTON_REPEAT)
-#define WPS_INCVOL     BUTTON_UP
-#define WPS_DECVOL     BUTTON_DOWN
-#define WPS_PAUSE      BUTTON_OFF
-/* #define WPS_MENU    iPod can't have both main menu and context menu in wps */
-#define WPS_BROWSE     (BUTTON_MENU | BUTTON_REL)
-#define WPS_BROWSE_PRE BUTTON_MENU
-#define WPS_KEYLOCK    (BUTTON_MENU | BUTTON_DOWN)
-#define WPS_EXIT       (BUTTON_OFF | BUTTON_REPEAT)
-#define WPS_CONTEXT    (BUTTON_MENU | BUTTON_REPEAT)
-
-
-#endif
-
-extern bool keys_locked;
-extern bool wps_time_countup;
-
-long wps_show(void);
-bool refresh_wps(bool refresh_scroll);
-void handle_usb(void);
-
-#if CONFIG_KEYPAD == RECORDER_PAD
-bool f2_screen(void);
-bool f3_screen(void);
-#endif
-
-#endif
-
diff --git a/docs/CREDITS b/docs/CREDITS
index 2877fd2..9380a0e 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -139,3 +139,4 @@
 Kevin Ferrare
 Anton Oleynikov
 Mark Arigo
+Magnus Westerlund
diff --git a/wps/rockbox_default.rwps b/wps/rockbox_default.rwps
new file mode 100644
index 0000000..b1427ca
--- /dev/null
+++ b/wps/rockbox_default.rwps
@@ -0,0 +1,2 @@
+# Dummy file to allow Rockbox to reset to the default WPS config.
+# Do not edit this file.  It's never actually loaded by Rockbox.