diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c
index 3d3a654..86884a0 100644
--- a/apps/gui/skin_engine/skin_display.c
+++ b/apps/gui/skin_engine/skin_display.c
@@ -207,7 +207,7 @@ static void draw_progressbar(struct gui_wps *gwps,
 #endif
     }
 }
-
+int playlistviewer_find_tag(struct skin_element *element);
 static void draw_playlist_viewer_list(struct gui_wps *gwps,
                                       struct playlistviewer *viewer)
 {
@@ -217,6 +217,7 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
     int cur_pos, max;
     int start_item;
     int i;
+    bool scroll = false;
     struct wps_token token;
     int x, length, alignment = WPS_TOKEN_ALIGN_LEFT;
     
@@ -281,13 +282,23 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
             }
             line = pid3 ? TRACK_HAS_INFO : TRACK_HAS_NO_INFO;
         }
-        int j = 0, cur_string = 0;
         unsigned int line_len = 0;
+        if (viewer->lines[line]->children_count == 0)
+            return;
+        struct skin_element *element = viewer->lines[line]->children[0];
         buf[0] = '\0';
-        while (j < viewer->lines[line].count && line_len < sizeof(buf))
+        while (element && line_len < sizeof(buf))
         {
             const char *out = NULL;
-            token.type = viewer->lines[line].tokens[j];
+            if (element->type == TEXT)
+            {
+                line_len = strlcat(buf, (char*)element->data, sizeof(buf));
+                element = element->next;
+                continue;
+            }
+            if (element->tag->type == SKIN_TOKEN_SUBLINE_SCROLL)
+                scroll = true;
+            token.type = playlistviewer_find_tag(element);
             token.value.i = 0;
             token.next = false;
             out = get_id3_token(&token, pid3, tempbuf, sizeof(tempbuf), -1, NULL);
@@ -299,26 +310,20 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
             if (out)
             {
                 line_len = strlcat(buf, out, sizeof(buf));
-                j++;
+                element = element->next;
                 continue;
             }
             
-            switch (viewer->lines[line].tokens[j])
+            switch (token.type)
             {
                 case WPS_TOKEN_ALIGN_CENTER:
                 case WPS_TOKEN_ALIGN_LEFT:
                 case WPS_TOKEN_ALIGN_LEFT_RTL:
                 case WPS_TOKEN_ALIGN_RIGHT:
                 case WPS_TOKEN_ALIGN_RIGHT_RTL:
-                    alignment = viewer->lines[line].tokens[j];
+                    alignment = token.type;
                     tempbuf[0] = '\0';
                     break;
-                case WPS_TOKEN_STRING:
-                case WPS_TOKEN_CHARACTER:
-                    snprintf(tempbuf, sizeof(tempbuf), "%s",
-                             viewer->lines[line].strings[cur_string]);
-                    cur_string++;
-                    break;
                 case WPS_TOKEN_PLAYLIST_POSITION:
                     snprintf(tempbuf, sizeof(tempbuf), "%d", i);
                     break;
@@ -336,12 +341,12 @@ static void draw_playlist_viewer_list(struct gui_wps *gwps,
             {
                 line_len = strlcat(buf, tempbuf, sizeof(buf));
             }
-            j++;
+            element = element->next;
         }
 
         int vpwidth = viewer->vp->width;
         length = gwps->display->getstringsize(buf, NULL, NULL);
-        if (viewer->lines[line].scroll && length >= vpwidth)
+        if (scroll && length >= vpwidth)
         {
             gwps->display->puts_scroll(0, (i-start_item), buf );
         }
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index ae6e226..1f3b291 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -159,8 +159,6 @@ static int parse_languagedirection(const char *wps_bufptr,
 #ifdef HAVE_LCD_BITMAP
 static int parse_viewport_display(const char *wps_bufptr,
         struct wps_token *token, struct wps_data *wps_data);
-static int parse_playlistview(const char *wps_bufptr,
-        struct wps_token *token, struct wps_data *wps_data);
 static int parse_statusbar_enable(const char *wps_bufptr,
         struct wps_token *token, struct wps_data *wps_data);
 static int parse_statusbar_disable(const char *wps_bufptr,
@@ -406,7 +404,7 @@ static const struct wps_tag all_tags[] = {
     { WPS_TOKEN_UIVIEWPORT_ENABLE,        "VI",  WPS_REFRESH_STATIC,
                                                     parse_viewport_display },
 #ifdef HAVE_LCD_BITMAP
-    { WPS_VIEWPORT_CUSTOMLIST,            "Vp",  WPS_REFRESH_STATIC, parse_playlistview },
+    { WPS_VIEWPORT_CUSTOMLIST,            "Vp",  WPS_REFRESH_STATIC, NULL },
     { WPS_TOKEN_LIST_TITLE_TEXT,          "Lt",  WPS_REFRESH_DYNAMIC, NULL },
     { WPS_TOKEN_LIST_TITLE_ICON,          "Li",  WPS_REFRESH_DYNAMIC, NULL },
 #endif
@@ -816,123 +814,32 @@ static int parse_viewport_display(const char *wps_bufptr,
 }
 
 #ifdef HAVE_LCD_BITMAP
-static int parse_playlistview_text(struct playlistviewer *viewer,
-                             enum info_line_type line,  char* text)
+int playlistviewer_find_tag(struct skin_element *element)
 {
-    int cur_string = 0;
     const struct wps_tag *tag;
-    int taglen = 0;
-    const char *start = text;
-    if (*text != ',')
-        return -1;
-    text++;
-    viewer->lines[line].count = 0;
-    viewer->lines[line].scroll = false;
-    while (*text != ',' && *text != ')')
-    {
-        if (*text == '%') /* it is a token of some type */
-        {
-            text++;
-            taglen = 0;
-            switch(*text)
-            {
-                case '%':
-                case '<':
-                case '|':
-                case '>':
-                case ';':
-                case '#':
-                case '(':
-                case ')':
-                case ',':
-                    /* escaped characters */
-                    viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_CHARACTER;
-                    viewer->lines[line].strings[cur_string][0] = *text;
-                    viewer->lines[line].strings[cur_string++][1] = '\0';
-                    text++;
-                    break;
-                default:
-                for (tag = all_tags;
-                     strncmp(text, tag->name, strlen(tag->name)) != 0;
-                     tag++) ;
-                /* %s isnt stored as a tag so manually check for it */
-                if (tag->type == WPS_NO_TOKEN)
-                {
-                    if (!strncmp(tag->name, "s", 1))
-                    {
-                        viewer->lines[line].scroll = true;
-                        taglen = 1;
-                    }
-                }
-                else if (tag->type == WPS_TOKEN_UNKNOWN)
-                {
-                    int i = 0;
-                    /* just copy the string */
-                    viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_STRING;
-                    while (i<(MAX_PLAYLISTLINE_STRLEN-1) && text[i] != ',' && text[i] != ')' && text[i] != '%')
-                    {
-                        viewer->lines[line].strings[cur_string][i] = text[i];
-                        i++;
-                    }
-                    viewer->lines[line].strings[cur_string][i] = '\0';
-                    cur_string++;
-                    taglen = i;
-                }
-                else
-                {
-                    if (tag->parse_func)
-                    {
-                        /* unsupported tag, reject */
-                        return -1;
-                    }
-                    taglen = strlen(tag->name);
-                    viewer->lines[line].tokens[viewer->lines[line].count++] = tag->type;
-                }
-                text += taglen;
-            }
-        }
-        else
-        {
-            /* regular string */
-            int i = 0;
-            /* just copy the string */
-            viewer->lines[line].tokens[viewer->lines[line].count++] = WPS_TOKEN_STRING;
-            while (i<(MAX_PLAYLISTLINE_STRLEN-1) && text[i] != ',' && text[i] != ')' && text[i] != '%')
-            {
-                viewer->lines[line].strings[cur_string][i] = text[i];
-                i++;
-            }
-            viewer->lines[line].strings[cur_string][i] = '\0';
-            cur_string++;
-            text += i;
-        }
-    }
-    return text - start;
+    for (tag = all_tags;
+         strncmp(element->tag->name, tag->name, strlen(tag->name)) != 0;
+         tag++) ;
+    return tag->type;
 }
 
-static int parse_playlistview(const char *wps_bufptr,
-        struct wps_token *token, struct wps_data *wps_data)
+static int parse_playlistview(struct wps_token *token, struct wps_data *wps_data,
+                              struct skin_element *root)
 {
     (void)wps_data;
-    /* %Vp|<use icons>|<start offset>|info line text|no info text| */
     struct playlistviewer *viewer = skin_buffer_alloc(sizeof(struct playlistviewer));
-    char *ptr = strchr(wps_bufptr, '(');
-    int length;
-    if (!viewer || !ptr)
+    if (!viewer)
         return WPS_ERROR_INVALID_PARAM;
     viewer->vp = &curr_vp->vp;
     viewer->show_icons = true;
-    viewer->start_offset = atoi(ptr+1);
+    viewer->start_offset = root->params[0].data.numeric;
+    viewer->lines[0] = root->params[1].data.code;
+    viewer->lines[1] = root->params[2].data.code;
+    
+    token->type = WPS_VIEWPORT_CUSTOMLIST;
     token->value.data = (void*)viewer;
-    ptr = strchr(ptr+1, ',');
-    length = parse_playlistview_text(viewer, TRACK_HAS_INFO, ptr);
-    if (length < 0)
-        return WPS_ERROR_INVALID_PARAM;
-    length = parse_playlistview_text(viewer, TRACK_HAS_NO_INFO, ptr+length);
-    if (length < 0)
-        return WPS_ERROR_INVALID_PARAM;
-
-    return skip_end_of_line(wps_bufptr);
+    
+    return skip_end_of_line(NULL);
 }
 #endif
 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1))
@@ -2260,7 +2167,15 @@ int convert_elements(struct wps_data *data, struct skin_element* tree, struct sk
                 token = data->tokens + data->num_tokens;
                 memset(token, 0, sizeof(*token));
                 text[0] = '\0';
-                if (element->params_count > 0)
+                
+                if (element->tag->type == SKIN_TOKEN_VIEWPORT_CUSTOMLIST)
+                {
+                    parse_playlistview(token, data, element);
+                    data->num_tokens++;
+                    element = element->next;
+                    continue;
+                }
+                else if (element->params_count > 0)
                 {
                     for(i=0;i<element->params_count;i++)
                     {
diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h
index 3d95ebd..86523c9 100644
--- a/apps/gui/skin_engine/wps_internals.h
+++ b/apps/gui/skin_engine/wps_internals.h
@@ -253,12 +253,7 @@ struct playlistviewer {
 #ifdef HAVE_TC_RAMCACHE
     struct mp3entry tempid3;
 #endif
-    struct {
-        enum wps_token_type tokens[MAX_PLAYLISTLINE_TOKENS];
-        char strings[MAX_PLAYLISTLINE_STRINGS][MAX_PLAYLISTLINE_STRLEN];
-        int count;
-        bool scroll;
-    } lines[2];
+    struct skin_element *lines[2];
 };
 
 
