summaryrefslogtreecommitdiff
path: root/apps/gui/skin_engine
diff options
context:
space:
mode:
authorJonathan Gordon <rockbox@jdgordon.info>2009-09-02 02:55:33 +0000
committerJonathan Gordon <rockbox@jdgordon.info>2009-09-02 02:55:33 +0000
commit8cb74438bc7c282f1ac9803afd1d1f9e68af17ae (patch)
tree9f2aaf1dd8aff6395452152ae7e0d41978f5a9e5 /apps/gui/skin_engine
parent8964fd1495ba2c69cff40e378d08aec4a651877f (diff)
downloadrockbox-8cb74438bc7c282f1ac9803afd1d1f9e68af17ae.tar.gz
rockbox-8cb74438bc7c282f1ac9803afd1d1f9e68af17ae.zip
Almost the last of the skin ram wastage fixing... This one moved the line/subline handling into the alloced buffer and links them more sensibly with their viewports.
now it works something like this: a skin is a list of viewports, each viewport has a list of lines, each line is a list of sublines, each subline has an *index* of its first and last tokens... git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22602 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/gui/skin_engine')
-rw-r--r--apps/gui/skin_engine/skin_buffer.c2
-rw-r--r--apps/gui/skin_engine/skin_display.c196
-rw-r--r--apps/gui/skin_engine/skin_parser.c137
-rw-r--r--apps/gui/skin_engine/skin_tokens.c2
-rw-r--r--apps/gui/skin_engine/wps_debug.c28
-rw-r--r--apps/gui/skin_engine/wps_internals.h43
6 files changed, 188 insertions, 220 deletions
diff --git a/apps/gui/skin_engine/skin_buffer.c b/apps/gui/skin_engine/skin_buffer.c
index c7e01ba5cd..1d18fb9431 100644
--- a/apps/gui/skin_engine/skin_buffer.c
+++ b/apps/gui/skin_engine/skin_buffer.c
@@ -118,6 +118,8 @@ void* skin_buffer_alloc(size_t size)
118 buffer_back -= size; 118 buffer_back -= size;
119 /* 32-bit aligned */ 119 /* 32-bit aligned */
120 buffer_back = (void *)(((unsigned long)buffer_back) & ~3); 120 buffer_back = (void *)(((unsigned long)buffer_back) & ~3);
121
122 memset(buffer_back, 0, size);
121 return buffer_back; 123 return buffer_back;
122} 124}
123 125
diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c
index 409984494c..4aeafb595d 100644
--- a/apps/gui/skin_engine/skin_display.c
+++ b/apps/gui/skin_engine/skin_display.c
@@ -391,41 +391,6 @@ static void draw_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
391 391
392#endif /* HAVE_LCD_CHARCELL */ 392#endif /* HAVE_LCD_CHARCELL */
393 393
394/* Returns the index of the subline in the subline array
395 line - 0-based line number
396 subline - 0-based subline number within the line
397 */
398static int subline_index(struct wps_data *data, int line, int subline)
399{
400 return data->lines[line].first_subline_idx + subline;
401}
402
403/* Returns the index of the first subline's token in the token array
404 line - 0-based line number
405 subline - 0-based subline number within the line
406 */
407static int first_token_index(struct wps_data *data, int line, int subline)
408{
409 int first_subline_idx = data->lines[line].first_subline_idx;
410 return data->sublines[first_subline_idx + subline].first_token_idx;
411}
412
413int skin_last_token_index(struct wps_data *data, int line, int subline)
414{
415 int first_subline_idx = data->lines[line].first_subline_idx;
416 int idx = first_subline_idx + subline;
417 if (idx < data->num_sublines - 1)
418 {
419 /* This subline ends where the next begins */
420 return data->sublines[idx+1].first_token_idx - 1;
421 }
422 else
423 {
424 /* The last subline goes to the end */
425 return data->num_tokens - 1;
426 }
427}
428
429/* Return the index to the end token for the conditional token at index. 394/* Return the index to the end token for the conditional token at index.
430 The conditional token can be either a start token or a separator 395 The conditional token can be either a start token or a separator
431 (i.e. option) token. 396 (i.e. option) token.
@@ -541,7 +506,7 @@ struct skin_viewport* find_viewport(char label, struct wps_data *data)
541 The return value indicates whether the line needs to be updated. 506 The return value indicates whether the line needs to be updated.
542*/ 507*/
543static bool get_line(struct gui_wps *gwps, 508static bool get_line(struct gui_wps *gwps,
544 int line, int subline, 509 struct wps_subline *subline,
545 struct align_pos *align, 510 struct align_pos *align,
546 char *linebuf, 511 char *linebuf,
547 int linebuf_size) 512 int linebuf_size)
@@ -551,8 +516,8 @@ static bool get_line(struct gui_wps *gwps,
551 char temp_buf[128]; 516 char temp_buf[128];
552 char *buf = linebuf; /* will always point to the writing position */ 517 char *buf = linebuf; /* will always point to the writing position */
553 char *linebuf_end = linebuf + linebuf_size - 1; 518 char *linebuf_end = linebuf + linebuf_size - 1;
554 int i, last_token_idx;
555 bool update = false; 519 bool update = false;
520 int i;
556 521
557 /* alignment-related variables */ 522 /* alignment-related variables */
558 int cur_align; 523 int cur_align;
@@ -562,11 +527,9 @@ static bool get_line(struct gui_wps *gwps,
562 align->left = NULL; 527 align->left = NULL;
563 align->center = NULL; 528 align->center = NULL;
564 align->right = NULL; 529 align->right = NULL;
565
566 /* Process all tokens of the desired subline */ 530 /* Process all tokens of the desired subline */
567 last_token_idx = skin_last_token_index(data, line, subline); 531 for (i = subline->first_token_idx;
568 for (i = first_token_index(data, line, subline); 532 i <= subline->last_token_idx; i++)
569 i <= last_token_idx; i++)
570 { 533 {
571 switch(data->tokens[i].type) 534 switch(data->tokens[i].type)
572 { 535 {
@@ -685,18 +648,14 @@ static bool get_line(struct gui_wps *gwps,
685 648
686 return update; 649 return update;
687} 650}
688 651static void get_subline_timeout(struct gui_wps *gwps, struct wps_subline *subline)
689static void get_subline_timeout(struct gui_wps *gwps, int line, int subline)
690{ 652{
691 struct wps_data *data = gwps->data; 653 struct wps_data *data = gwps->data;
692 int i; 654 int i;
693 int subline_idx = subline_index(data, line, subline); 655 subline->time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER;
694 int last_token_idx = skin_last_token_index(data, line, subline);
695 656
696 data->sublines[subline_idx].time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER; 657 for (i = subline->first_token_idx;
697 658 i <= subline->last_token_idx; i++)
698 for (i = first_token_index(data, line, subline);
699 i <= last_token_idx; i++)
700 { 659 {
701 switch(data->tokens[i].type) 660 switch(data->tokens[i].type)
702 { 661 {
@@ -712,7 +671,7 @@ static void get_subline_timeout(struct gui_wps *gwps, int line, int subline)
712 break; 671 break;
713 672
714 case WPS_TOKEN_SUBLINE_TIMEOUT: 673 case WPS_TOKEN_SUBLINE_TIMEOUT:
715 data->sublines[subline_idx].time_mult = data->tokens[i].value.i; 674 subline->time_mult = data->tokens[i].value.i;
716 break; 675 break;
717 676
718 default: 677 default:
@@ -723,77 +682,37 @@ static void get_subline_timeout(struct gui_wps *gwps, int line, int subline)
723 682
724/* Calculates which subline should be displayed for the specified line 683/* Calculates which subline should be displayed for the specified line
725 Returns true iff the subline must be refreshed */ 684 Returns true iff the subline must be refreshed */
726static bool update_curr_subline(struct gui_wps *gwps, int line) 685static bool update_curr_subline(struct gui_wps *gwps, struct wps_line *line)
727{ 686{
728 struct wps_data *data = gwps->data; 687 /* shortcut this whole thing if we need to reset the line completly */
729 688 if (line->curr_subline == NULL)
730 int search, search_start, num_sublines; 689 {
731 bool reset_subline; 690 int next_refresh = current_tick;
732 bool new_subline_refresh; 691 line->curr_subline = &line->sublines;
733 bool only_one_subline; 692 if (!line->curr_subline->next)
734 693 next_refresh += 100*HZ;
735 num_sublines = data->lines[line].num_sublines; 694 line->subline_expire_time = next_refresh;
736 reset_subline = (data->lines[line].curr_subline == SUBLINE_RESET); 695 return true;
737 new_subline_refresh = false; 696 }
738 only_one_subline = false;
739
740 /* if time to advance to next sub-line */ 697 /* if time to advance to next sub-line */
741 if (TIME_AFTER(current_tick, data->lines[line].subline_expire_time - 1) || 698 if (TIME_AFTER(current_tick, line->subline_expire_time - 1))
742 reset_subline)
743 { 699 {
744 /* search all sublines until the next subline with time > 0 700 /* if there is only one subline, there is no need to search for a new one */
745 is found or we get back to the subline we started with */ 701 if (&line->sublines == line->curr_subline &&
746 if (reset_subline) 702 line->curr_subline->next == NULL)
747 search_start = 0;
748 else
749 search_start = data->lines[line].curr_subline;
750
751 for (search = 0; search < num_sublines; search++)
752 { 703 {
753 data->lines[line].curr_subline++; 704 line->subline_expire_time += 100 * HZ;
754 705 return true;
755 /* wrap around if beyond last defined subline or WPS_MAX_SUBLINES */
756 if (data->lines[line].curr_subline == num_sublines)
757 {
758 if (data->lines[line].curr_subline == 1)
759 only_one_subline = true;
760 data->lines[line].curr_subline = 0;
761 }
762
763 /* if back where we started after search or
764 only one subline is defined on the line */
765 if (((search > 0) &&
766 (data->lines[line].curr_subline == search_start)) ||
767 only_one_subline)
768 {
769 /* no other subline with a time > 0 exists */
770 data->lines[line].subline_expire_time = (reset_subline ?
771 current_tick :
772 data->lines[line].subline_expire_time) + 100 * HZ;
773 break;
774 }
775 else
776 {
777 /* get initial time multiplier for this subline */
778 get_subline_timeout(gwps, line, data->lines[line].curr_subline);
779
780 int subline_idx = subline_index(data, line,
781 data->lines[line].curr_subline);
782
783 /* only use this subline if subline time > 0 */
784 if (data->sublines[subline_idx].time_mult > 0)
785 {
786 new_subline_refresh = true;
787 data->lines[line].subline_expire_time = (reset_subline ?
788 current_tick : data->lines[line].subline_expire_time) +
789 TIMEOUT_UNIT*data->sublines[subline_idx].time_mult;
790 break;
791 }
792 }
793 } 706 }
707 if (line->curr_subline->next)
708 line->curr_subline = line->curr_subline->next;
709 else
710 line->curr_subline = &line->sublines;
711 get_subline_timeout(gwps, line->curr_subline);
712 line->subline_expire_time += TIMEOUT_UNIT*line->curr_subline->time_mult;
713 return true;
794 } 714 }
795 715 return false;
796 return new_subline_refresh;
797} 716}
798 717
799/* Display a line appropriately according to its alignment format. 718/* Display a line appropriately according to its alignment format.
@@ -971,8 +890,7 @@ static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode)
971 890
972 if (!id3) 891 if (!id3)
973 return false; 892 return false;
974 893
975 int line, i, subline_idx;
976 unsigned flags; 894 unsigned flags;
977 char linebuf[MAX_PATH]; 895 char linebuf[MAX_PATH];
978 896
@@ -980,6 +898,9 @@ static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode)
980 align.left = NULL; 898 align.left = NULL;
981 align.center = NULL; 899 align.center = NULL;
982 align.right = NULL; 900 align.right = NULL;
901
902
903 struct skin_token_list *viewport_list;
983 904
984 bool update_line, new_subline_refresh; 905 bool update_line, new_subline_refresh;
985 906
@@ -999,12 +920,20 @@ static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode)
999 /* reset to first subline if refresh all flag is set */ 920 /* reset to first subline if refresh all flag is set */
1000 if (refresh_mode == WPS_REFRESH_ALL) 921 if (refresh_mode == WPS_REFRESH_ALL)
1001 { 922 {
923 struct wps_line *line;
924
1002 display->set_viewport(&find_viewport(VP_DEFAULT_LABEL, data)->vp); 925 display->set_viewport(&find_viewport(VP_DEFAULT_LABEL, data)->vp);
1003 display->clear_viewport(); 926 display->clear_viewport();
1004 927
1005 for (i = 0; i <= data->num_lines; i++) 928 for (viewport_list = data->viewports;
929 viewport_list; viewport_list = viewport_list->next)
1006 { 930 {
1007 data->lines[i].curr_subline = SUBLINE_RESET; 931 struct skin_viewport *skin_viewport =
932 (struct skin_viewport *)viewport_list->token->value.data;
933 for(line = skin_viewport->lines; line; line = line->next)
934 {
935 line->curr_subline = NULL;
936 }
1008 } 937 }
1009 } 938 }
1010 939
@@ -1017,7 +946,6 @@ static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode)
1017#endif 946#endif
1018 947
1019 /* disable any viewports which are conditionally displayed */ 948 /* disable any viewports which are conditionally displayed */
1020 struct skin_token_list *viewport_list;
1021 for (viewport_list = data->viewports; 949 for (viewport_list = data->viewports;
1022 viewport_list; viewport_list = viewport_list->next) 950 viewport_list; viewport_list = viewport_list->next)
1023 { 951 {
@@ -1069,25 +997,27 @@ static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode)
1069 { 997 {
1070 display->clear_viewport(); 998 display->clear_viewport();
1071 } 999 }
1000
1001 /* loop over the lines for this viewport */
1002 struct wps_line *line;
1003 int line_count = 0;
1072 1004
1073 for (line = skin_viewport->first_line; 1005 for (line = skin_viewport->lines; line; line = line->next, line_count++)
1074 line <= skin_viewport->last_line; line++)
1075 { 1006 {
1007 struct wps_subline *subline;
1076 memset(linebuf, 0, sizeof(linebuf)); 1008 memset(linebuf, 0, sizeof(linebuf));
1077 update_line = false; 1009 update_line = false;
1078 1010
1079 /* get current subline for the line */ 1011 /* get current subline for the line */
1080 new_subline_refresh = update_curr_subline(gwps, line); 1012 new_subline_refresh = update_curr_subline(gwps, line);
1081 1013 subline = line->curr_subline;
1082 subline_idx = subline_index(data, line, 1014 flags = line->curr_subline->line_type;
1083 data->lines[line].curr_subline);
1084 flags = data->sublines[subline_idx].line_type;
1085 1015
1086 if (vp_refresh_mode == WPS_REFRESH_ALL || (flags & vp_refresh_mode) 1016 if (vp_refresh_mode == WPS_REFRESH_ALL || (flags & vp_refresh_mode)
1087 || new_subline_refresh) 1017 || new_subline_refresh)
1088 { 1018 {
1089 /* get_line tells us if we need to update the line */ 1019 /* get_line tells us if we need to update the line */
1090 update_line = get_line(gwps, line, data->lines[line].curr_subline, 1020 update_line = get_line(gwps, subline,
1091 &align, linebuf, sizeof(linebuf)); 1021 &align, linebuf, sizeof(linebuf));
1092 } 1022 }
1093#ifdef HAVE_LCD_BITMAP 1023#ifdef HAVE_LCD_BITMAP
@@ -1098,19 +1028,19 @@ static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode)
1098 update_line = false; 1028 update_line = false;
1099 1029
1100 int h = font_get(skin_viewport->vp.font)->height; 1030 int h = font_get(skin_viewport->vp.font)->height;
1101 int peak_meter_y = (line - skin_viewport->first_line)* h; 1031 int peak_meter_y = line_count* h;
1102 1032
1103 /* The user might decide to have the peak meter in the last 1033 /* The user might decide to have the peak meter in the last
1104 line so that it is only displayed if no status bar is 1034 line so that it is only displayed if no status bar is
1105 visible. If so we neither want do draw nor enable the 1035 visible. If so we neither want do draw nor enable the
1106 peak meter. */ 1036 peak meter. */
1107 if (peak_meter_y + h <= display->getheight()) { 1037 if (peak_meter_y + h <= skin_viewport->vp.y+skin_viewport->vp.height) {
1108 /* found a line with a peak meter -> remember that we must 1038 /* found a line with a peak meter -> remember that we must
1109 enable it later */ 1039 enable it later */
1110 enable_pm = true; 1040 enable_pm = true;
1111 peak_meter_enabled = true; 1041 peak_meter_enabled = true;
1112 peak_meter_screen(gwps->display, 0, peak_meter_y, 1042 peak_meter_screen(gwps->display, 0, peak_meter_y,
1113 MIN(h, display->getheight() - peak_meter_y)); 1043 MIN(h, skin_viewport->vp.y+skin_viewport->vp.height - peak_meter_y));
1114 } 1044 }
1115 else 1045 else
1116 { 1046 {
@@ -1143,10 +1073,10 @@ static bool skin_redraw(struct gui_wps *gwps, unsigned refresh_mode)
1143 /* if the line is a scrolling one we don't want to update 1073 /* if the line is a scrolling one we don't want to update
1144 too often, so that it has the time to scroll */ 1074 too often, so that it has the time to scroll */
1145 if ((vp_refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh) 1075 if ((vp_refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh)
1146 write_line(display, &align, line - skin_viewport->first_line, true); 1076 write_line(display, &align, line_count, true);
1147 } 1077 }
1148 else 1078 else
1149 write_line(display, &align, line - skin_viewport->first_line, false); 1079 write_line(display, &align, line_count, false);
1150 } 1080 }
1151 } 1081 }
1152 1082
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index 68bddf6205..f8c9b75a87 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -72,11 +72,13 @@ static int condindex[WPS_MAX_COND_LEVEL];
72/* number of condtional options in current level */ 72/* number of condtional options in current level */
73static int numoptions[WPS_MAX_COND_LEVEL]; 73static int numoptions[WPS_MAX_COND_LEVEL];
74 74
75/* the current line in the file */ 75/* line number, debug only */
76static int line; 76static int line_number;
77 77
78/* the current viewport */ 78/* the current viewport */
79static struct skin_viewport *curr_vp; 79static struct skin_viewport *curr_vp;
80/* the current line, linked to the above viewport */
81static struct wps_line *curr_line;
80 82
81#ifdef HAVE_LCD_BITMAP 83#ifdef HAVE_LCD_BITMAP
82 84
@@ -397,7 +399,7 @@ static struct skin_token_list *new_skin_token_list_item(struct wps_token *token,
397 immediately after the first eol, i.e. to the start of the next line */ 399 immediately after the first eol, i.e. to the start of the next line */
398static int skip_end_of_line(const char *wps_bufptr) 400static int skip_end_of_line(const char *wps_bufptr)
399{ 401{
400 line++; 402 line_number++;
401 int skip = 0; 403 int skip = 0;
402 while(*(wps_bufptr + skip) != '\n') 404 while(*(wps_bufptr + skip) != '\n')
403 skip++; 405 skip++;
@@ -405,11 +407,59 @@ static int skip_end_of_line(const char *wps_bufptr)
405} 407}
406 408
407/* Starts a new subline in the current line during parsing */ 409/* Starts a new subline in the current line during parsing */
408static void wps_start_new_subline(struct wps_data *data) 410static bool wps_start_new_subline(struct wps_line *line, int curr_token)
409{ 411{
410 data->num_sublines++; 412 struct wps_subline *subline = skin_buffer_alloc(sizeof(struct wps_subline));
411 data->sublines[data->num_sublines].first_token_idx = data->num_tokens; 413 if (!subline)
412 data->lines[data->num_lines].num_sublines++; 414 return false;
415
416 subline->first_token_idx = curr_token;
417 subline->next = NULL;
418
419 subline->line_type = 0;
420 subline->time_mult = 0;
421
422 line->curr_subline->last_token_idx = curr_token-1;
423 line->curr_subline->next = subline;
424 line->curr_subline = subline;
425 return true;
426}
427
428static bool wps_start_new_line(struct skin_viewport *vp, int curr_token)
429{
430 struct wps_line *line = skin_buffer_alloc(sizeof(struct wps_line));
431 struct wps_subline *subline = NULL;
432 if (!line)
433 return false;
434
435 /* init the subline */
436 subline = &line->sublines;
437 subline->first_token_idx = curr_token;
438 subline->next = NULL;
439 subline->line_type = 0;
440 subline->time_mult = 0;
441
442 /* init the new line */
443 line->curr_subline = &line->sublines;
444 line->next = NULL;
445 line->subline_expire_time = 0;
446
447 /* connect to curr_line and vp pointers.
448 * 1) close the previous lines subline
449 * 2) connect to vp pointer
450 * 3) connect to curr_line global pointer
451 */
452 if (curr_line)
453 {
454 curr_line->curr_subline->last_token_idx = curr_token - 1;
455 curr_line->next = line;
456 curr_line->curr_subline = NULL;
457 }
458 curr_line = line;
459 if (!vp->lines)
460 vp->lines = line;
461 line_number++;
462 return true;
413} 463}
414 464
415#ifdef HAVE_LCD_BITMAP 465#ifdef HAVE_LCD_BITMAP
@@ -617,6 +667,12 @@ static int parse_viewport(const char *wps_bufptr,
617 skin_vp->hidden_flags = 0; 667 skin_vp->hidden_flags = 0;
618 skin_vp->label = VP_NO_LABEL; 668 skin_vp->label = VP_NO_LABEL;
619 skin_vp->pb = NULL; 669 skin_vp->pb = NULL;
670 skin_vp->lines = NULL;
671
672 curr_line = NULL;
673 if (!wps_start_new_line(skin_vp, wps_data->num_tokens))
674 return WPS_ERROR_INVALID_PARAM;
675
620 676
621 if (*ptr == 'l') 677 if (*ptr == 'l')
622 { 678 {
@@ -647,18 +703,6 @@ static int parse_viewport(const char *wps_bufptr,
647 if (*ptr != '|') 703 if (*ptr != '|')
648 return WPS_ERROR_INVALID_PARAM; 704 return WPS_ERROR_INVALID_PARAM;
649 705
650 curr_vp->last_line = wps_data->num_lines - 1;
651
652 skin_vp->first_line = wps_data->num_lines;
653
654 if (wps_data->num_sublines < WPS_MAX_SUBLINES)
655 {
656 wps_data->lines[wps_data->num_lines].first_subline_idx =
657 wps_data->num_sublines;
658
659 wps_data->sublines[wps_data->num_sublines].first_token_idx =
660 wps_data->num_tokens;
661 }
662 706
663 struct skin_token_list *list = new_skin_token_list_item(NULL, skin_vp); 707 struct skin_token_list *list = new_skin_token_list_item(NULL, skin_vp);
664 if (!list) 708 if (!list)
@@ -826,8 +870,15 @@ static int parse_progressbar(const char *wps_bufptr,
826#else 870#else
827 int font_height = 8; 871 int font_height = 8;
828#endif 872#endif
829 int line_num = wps_data->num_lines - curr_vp->first_line; 873 /* we need to know what line number (viewport relative) this pb is,
830 874 * so count them... */
875 int line_num = -1;
876 struct wps_line *line = curr_vp->lines;
877 while (line)
878 {
879 line_num++;
880 line = line->next;
881 }
831 pb->have_bitmap_pb = false; 882 pb->have_bitmap_pb = false;
832 pb->bm.data = NULL; /* no bitmap specified */ 883 pb->bm.data = NULL; /* no bitmap specified */
833 884
@@ -1241,8 +1292,7 @@ static int parse_token(const char *wps_bufptr, struct wps_data *wps_data)
1241 1292
1242 taglen = (tag->type != WPS_TOKEN_UNKNOWN) ? strlen(tag->name) : 2; 1293 taglen = (tag->type != WPS_TOKEN_UNKNOWN) ? strlen(tag->name) : 2;
1243 token->type = tag->type; 1294 token->type = tag->type;
1244 wps_data->sublines[wps_data->num_sublines].line_type |= 1295 curr_line->curr_subline->line_type |= tag->refresh_type;
1245 tag->refresh_type;
1246 1296
1247 /* if the tag has a special parsing function, we call it */ 1297 /* if the tag has a special parsing function, we call it */
1248 if (tag->parse_func) 1298 if (tag->parse_func)
@@ -1282,7 +1332,7 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
1282 int ret; 1332 int ret;
1283 int max_tokens = TOKEN_BLOCK_SIZE; 1333 int max_tokens = TOKEN_BLOCK_SIZE;
1284 size_t buf_free = 0; 1334 size_t buf_free = 0;
1285 line = 1; 1335 line_number = 1;
1286 level = -1; 1336 level = -1;
1287 1337
1288 /* allocate enough RAM for a reasonable skin, grow as needed. 1338 /* allocate enough RAM for a reasonable skin, grow as needed.
@@ -1293,8 +1343,7 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
1293 skin_buffer_increment(max_tokens * sizeof(struct wps_token), false); 1343 skin_buffer_increment(max_tokens * sizeof(struct wps_token), false);
1294 data->num_tokens = 0; 1344 data->num_tokens = 0;
1295 1345
1296 while(*wps_bufptr && !fail 1346 while (*wps_bufptr && !fail)
1297 && data->num_lines < WPS_MAX_LINES)
1298 { 1347 {
1299 /* first make sure there is enough room for tokens */ 1348 /* first make sure there is enough room for tokens */
1300 if (max_tokens -1 == data->num_tokens) 1349 if (max_tokens -1 == data->num_tokens)
@@ -1337,9 +1386,7 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
1337 break; 1386 break;
1338 } 1387 }
1339 1388
1340 if (data->num_sublines+1 < WPS_MAX_SUBLINES) 1389 if (!wps_start_new_subline(curr_line, data->num_tokens))
1341 wps_start_new_subline(data);
1342 else
1343 fail = PARSE_FAIL_LIMITS_EXCEEDED; 1390 fail = PARSE_FAIL_LIMITS_EXCEEDED;
1344 1391
1345 break; 1392 break;
@@ -1419,19 +1466,16 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
1419 fail = PARSE_FAIL_UNCLOSED_COND; 1466 fail = PARSE_FAIL_UNCLOSED_COND;
1420 break; 1467 break;
1421 } 1468 }
1469 /* add a new token for the \n so empty lines are correct */
1470 data->tokens[data->num_tokens].type = WPS_TOKEN_CHARACTER;
1471 data->tokens[data->num_tokens].value.c = '\n';
1472 data->tokens[data->num_tokens].next = false;
1473 data->num_tokens++;
1422 1474
1423 line++; 1475 if (!wps_start_new_line(curr_vp, data->num_tokens))
1424 wps_start_new_subline(data); 1476 {
1425 data->num_lines++; /* Start a new line */ 1477 fail = PARSE_FAIL_LIMITS_EXCEEDED;
1426 1478 break;
1427 if ((data->num_lines < WPS_MAX_LINES) &&
1428 (data->num_sublines < WPS_MAX_SUBLINES))
1429 {
1430 data->lines[data->num_lines].first_subline_idx =
1431 data->num_sublines;
1432
1433 data->sublines[data->num_sublines].first_token_idx =
1434 data->num_tokens;
1435 } 1479 }
1436 1480
1437 break; 1481 break;
@@ -1511,11 +1555,12 @@ static bool wps_parse(struct wps_data *data, const char *wps_bufptr, bool debug)
1511 /* freeup unused tokens */ 1555 /* freeup unused tokens */
1512 skin_buffer_free_from_front(sizeof(struct wps_token) 1556 skin_buffer_free_from_front(sizeof(struct wps_token)
1513 * (max_tokens - data->num_tokens)); 1557 * (max_tokens - data->num_tokens));
1514 curr_vp->last_line = data->num_lines - 1; 1558 /* close the last subline */
1559 curr_line->curr_subline->last_token_idx = data->num_tokens;
1515 1560
1516#if defined(DEBUG) || defined(SIMULATOR) 1561#if defined(DEBUG) || defined(SIMULATOR)
1517 if (debug) 1562 if (debug)
1518 print_debug_info(data, fail, line); 1563 print_debug_info(data, fail, line_number);
1519#else 1564#else
1520 (void)debug; 1565 (void)debug;
1521#endif 1566#endif
@@ -1658,6 +1703,12 @@ bool skin_data_load(struct wps_data *wps_data,
1658 curr_vp->vp.height = display->getheight(); 1703 curr_vp->vp.height = display->getheight();
1659 curr_vp->pb = NULL; 1704 curr_vp->pb = NULL;
1660 curr_vp->hidden_flags = 0; 1705 curr_vp->hidden_flags = 0;
1706 curr_vp->lines = NULL;
1707
1708 curr_line = NULL;
1709 if (!wps_start_new_line(curr_vp, 0))
1710 return false;
1711
1661 switch (statusbar_position(display->screen_type)) 1712 switch (statusbar_position(display->screen_type))
1662 { 1713 {
1663 case STATUSBAR_OFF: 1714 case STATUSBAR_OFF:
diff --git a/apps/gui/skin_engine/skin_tokens.c b/apps/gui/skin_engine/skin_tokens.c
index 386dc5ded8..1254900844 100644
--- a/apps/gui/skin_engine/skin_tokens.c
+++ b/apps/gui/skin_engine/skin_tokens.c
@@ -164,6 +164,8 @@ const char *get_token_value(struct gui_wps *gwps,
164 switch (token->type) 164 switch (token->type)
165 { 165 {
166 case WPS_TOKEN_CHARACTER: 166 case WPS_TOKEN_CHARACTER:
167 if (token->value.c == '\n')
168 return NULL;
167 return &(token->value.c); 169 return &(token->value.c);
168 170
169 case WPS_TOKEN_STRING: 171 case WPS_TOKEN_STRING:
diff --git a/apps/gui/skin_engine/wps_debug.c b/apps/gui/skin_engine/wps_debug.c
index 78f58c42b1..8e0727516a 100644
--- a/apps/gui/skin_engine/wps_debug.c
+++ b/apps/gui/skin_engine/wps_debug.c
@@ -60,8 +60,11 @@ static char *get_token_desc(struct wps_token *token, char *buf, int bufsize)
60 break; 60 break;
61 61
62 case WPS_TOKEN_CHARACTER: 62 case WPS_TOKEN_CHARACTER:
63 snprintf(buf, bufsize, "Character '%c'", 63 if (token->value.c == '\n')
64 token->value.c); 64 snprintf(buf, bufsize, "Character '\\n'");
65 else
66 snprintf(buf, bufsize, "Character '%c'",
67 token->value.c);
65 break; 68 break;
66 69
67 case WPS_TOKEN_STRING: 70 case WPS_TOKEN_STRING:
@@ -486,7 +489,6 @@ static void dump_wps_tokens(struct wps_data *data)
486 489
487static void print_line_info(struct wps_data *data) 490static void print_line_info(struct wps_data *data)
488{ 491{
489 int i, j;
490 struct wps_line *line; 492 struct wps_line *line;
491 struct wps_subline *subline; 493 struct wps_subline *subline;
492 if (wps_verbose_level > 0) 494 if (wps_verbose_level > 0)
@@ -498,16 +500,14 @@ static void print_line_info(struct wps_data *data)
498 struct skin_viewport *v = 500 struct skin_viewport *v =
499 (struct skin_viewport *)viewport_list->token->value.data; 501 (struct skin_viewport *)viewport_list->token->value.data;
500 DEBUGF("vp Label:'%c' Hidden flags:%x\n", v->label, v->hidden_flags); 502 DEBUGF("vp Label:'%c' Hidden flags:%x\n", v->label, v->hidden_flags);
501 DEBUGF(" First line: %d\n", v->first_line);
502 DEBUGF(" Last line: %d\n", v->last_line);
503 } 503 }
504 DEBUGF("Number of sublines : %d\n", data->num_sublines);
505 DEBUGF("Number of tokens : %d\n", data->num_tokens); 504 DEBUGF("Number of tokens : %d\n", data->num_tokens);
506 DEBUGF("\n"); 505 DEBUGF("\n");
507 } 506 }
508 507
509 if (wps_verbose_level > 1) 508 if (wps_verbose_level > 1)
510 { 509 {
510 int line_number = 0;
511 struct skin_token_list *viewport_list; 511 struct skin_token_list *viewport_list;
512 for (viewport_list = data->viewports; 512 for (viewport_list = data->viewports;
513 viewport_list; viewport_list = viewport_list->next) 513 viewport_list; viewport_list = viewport_list->next)
@@ -516,17 +516,15 @@ static void print_line_info(struct wps_data *data)
516 (struct skin_viewport *)viewport_list->token->value.data; 516 (struct skin_viewport *)viewport_list->token->value.data;
517 DEBUGF("Viewport '%c' - +%d+%d (%dx%d)\n",v->label, v->vp.x, v->vp.y, 517 DEBUGF("Viewport '%c' - +%d+%d (%dx%d)\n",v->label, v->vp.x, v->vp.y,
518 v->vp.width, v->vp.height); 518 v->vp.width, v->vp.height);
519 for (i = v->first_line, line = &data->lines[v->first_line]; i <= v->last_line; i++,line++) 519 for (line = v->lines; line; line = line->next, line_number++)
520 { 520 {
521 DEBUGF("Line %2d (num_sublines=%d, first_subline=%d)\n", 521 DEBUGF("Line %2d\n", line_number);
522 i, line->num_sublines, line->first_subline_idx); 522 int subline_number = 0;
523 523 subline = &line->sublines;
524 for (j = 0, subline = data->sublines + line->first_subline_idx; 524 while (subline)
525 j < line->num_sublines; j++, subline++)
526 { 525 {
527 DEBUGF(" Subline %d: first_token=%3d, last_token=%3d", 526 DEBUGF(" Subline %d: first_token=%3d, last_token=%3d",
528 j, subline->first_token_idx, 527 subline_number, subline->first_token_idx,subline->last_token_idx);
529 skin_last_token_index(data, i, j));
530 528
531 if (subline->line_type & WPS_REFRESH_SCROLL) 529 if (subline->line_type & WPS_REFRESH_SCROLL)
532 DEBUGF(", scrolled"); 530 DEBUGF(", scrolled");
@@ -536,6 +534,8 @@ static void print_line_info(struct wps_data *data)
536 DEBUGF(", peakmeter"); 534 DEBUGF(", peakmeter");
537 535
538 DEBUGF("\n"); 536 DEBUGF("\n");
537 subline = subline->next;
538 subline_number++;
539 } 539 }
540 } 540 }
541 } 541 }
diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h
index fbd18b9f73..bcc68a88f0 100644
--- a/apps/gui/skin_engine/wps_internals.h
+++ b/apps/gui/skin_engine/wps_internals.h
@@ -160,12 +160,16 @@ struct wps_subline {
160 Tokens of this subline end where tokens for the next subline 160 Tokens of this subline end where tokens for the next subline
161 begin. */ 161 begin. */
162 unsigned short first_token_idx; 162 unsigned short first_token_idx;
163 unsigned short last_token_idx;
163 164
164 /* Bit or'ed WPS_REFRESH_xxx */ 165 /* Bit or'ed WPS_REFRESH_xxx */
165 unsigned char line_type; 166 unsigned char line_type;
166 167
167 /* How long the subline should be displayed, in 10ths of sec */ 168 /* How long the subline should be displayed, in 10ths of sec */
168 unsigned char time_mult; 169 unsigned char time_mult;
170
171 /* pointer to the next subline in this line */
172 struct wps_subline *next;
169}; 173};
170 174
171/* Description of a line on the WPS. A line is a set of sublines. 175/* Description of a line on the WPS. A line is a set of sublines.
@@ -173,19 +177,18 @@ struct wps_subline {
173 the next subline of the line is displayed. And so on. */ 177 the next subline of the line is displayed. And so on. */
174struct wps_line { 178struct wps_line {
175 179
176 /* Number of sublines in this line */ 180 /* Linked list of all the sublines on this line,
177 signed char num_sublines; 181 * a line *must* have at least one subline so no need to add an extra pointer */
178 182 struct wps_subline sublines;
179 /* Number (0-based) of the subline within this line currently being displayed */ 183 /* pointer to the current subline */
180 signed char curr_subline; 184 struct wps_subline *curr_subline;
181
182 /* Index of the first subline of this line in the subline array.
183 Sublines for this line end where sublines for the next line begin. */
184 unsigned short first_subline_idx;
185 185
186 /* When the next subline of this line should be displayed 186 /* When the next subline of this line should be displayed
187 (absolute time value in ticks) */ 187 (absolute time value in ticks) */
188 long subline_expire_time; 188 long subline_expire_time;
189
190 /* pointer to the next line */
191 struct wps_line *next;
189}; 192};
190 193
191#define VP_DRAW_HIDEABLE 0x1 194#define VP_DRAW_HIDEABLE 0x1
@@ -196,9 +199,7 @@ struct wps_line {
196struct skin_viewport { 199struct skin_viewport {
197 struct viewport vp; /* The LCD viewport struct */ 200 struct viewport vp; /* The LCD viewport struct */
198 struct progressbar *pb; 201 struct progressbar *pb;
199 /* Indexes of the first and last lines belonging to this viewport in the 202 struct wps_line *lines;
200 lines[] array */
201 int first_line, last_line;
202 char hidden_flags; 203 char hidden_flags;
203 char label; 204 char label;
204}; 205};
@@ -259,20 +260,8 @@ struct wps_data
259 bool remote_wps; 260 bool remote_wps;
260#endif 261#endif
261 262
262 /* Number of lines in the WPS. During WPS parsing, this is
263 the index of the line being parsed. */
264 int num_lines;
265
266 /* Number of viewports in the WPS */
267 struct skin_token_list *viewports; 263 struct skin_token_list *viewports;
268 264
269 struct wps_line lines[WPS_MAX_LINES];
270
271 /* Total number of sublines in the WPS. During WPS parsing, this is
272 the index of the subline where the parsed tokens are added to. */
273 int num_sublines;
274 struct wps_subline sublines[WPS_MAX_SUBLINES];
275
276 /* Total number of tokens in the WPS. During WPS parsing, this is 265 /* Total number of tokens in the WPS. During WPS parsing, this is
277 the index of the token being parsed. */ 266 the index of the token being parsed. */
278 int num_tokens; 267 int num_tokens;
@@ -286,12 +275,6 @@ struct wps_data
286 unsigned int button_time_volume; 275 unsigned int button_time_volume;
287}; 276};
288 277
289/* Returns the index of the last subline's token in the token array.
290 line - 0-based line number
291 subline - 0-based subline number within the line
292 */
293int skin_last_token_index(struct wps_data *data, int line, int subline);
294
295/* wps_data end */ 278/* wps_data end */
296 279
297/* wps_state 280/* wps_state