Index: apps/gui/skin_engine/wps_debug.c =================================================================== --- apps/gui/skin_engine/wps_debug.c (revision 22559) +++ apps/gui/skin_engine/wps_debug.c (working copy) @@ -486,7 +486,6 @@ static void print_line_info(struct wps_data *data) { - int i, j; struct wps_line *line; struct wps_subline *subline; if (wps_verbose_level > 0) @@ -498,16 +497,14 @@ struct skin_viewport *v = (struct skin_viewport *)viewport_list->token->value.data; DEBUGF("vp Label:'%c' Hidden flags:%x\n", v->label, v->hidden_flags); - DEBUGF(" First line: %d\n", v->first_line); - DEBUGF(" Last line: %d\n", v->last_line); } - DEBUGF("Number of sublines : %d\n", data->num_sublines); DEBUGF("Number of tokens : %d\n", data->num_tokens); DEBUGF("\n"); } if (wps_verbose_level > 1) { + int line_number = 0; struct skin_token_list *viewport_list; for (viewport_list = data->viewports; viewport_list; viewport_list = viewport_list->next) @@ -516,17 +513,16 @@ (struct skin_viewport *)viewport_list->token->value.data; DEBUGF("Viewport '%c' - +%d+%d (%dx%d)\n",v->label, v->vp.x, v->vp.y, v->vp.width, v->vp.height); - for (i = v->first_line, line = &data->lines[v->first_line]; i <= v->last_line; i++,line++) + for (line = v->lines; line; line = line->next, line_number++) { - DEBUGF("Line %2d (num_sublines=%d, first_subline=%d)\n", - i, line->num_sublines, line->first_subline_idx); - - for (j = 0, subline = data->sublines + line->first_subline_idx; - j < line->num_sublines; j++, subline++) + DEBUGF("Line %2d\n", line_number); + int subline_number = 0; + subline = &line->sublines; + //for(; subline; subline = subline->next, subline_number++); + while (subline) { DEBUGF(" Subline %d: first_token=%3d, last_token=%3d", - j, subline->first_token_idx, - skin_last_token_index(data, i, j)); + subline_number, subline->first_token_idx,subline->last_token_idx); if (subline->line_type & WPS_REFRESH_SCROLL) DEBUGF(", scrolled"); @@ -536,6 +532,8 @@ DEBUGF(", peakmeter"); DEBUGF("\n"); + subline = subline->next; + subline_number++; } } } Index: apps/gui/skin_engine/skin_parser.c =================================================================== --- apps/gui/skin_engine/skin_parser.c (revision 22559) +++ apps/gui/skin_engine/skin_parser.c (working copy) @@ -72,11 +72,13 @@ /* number of condtional options in current level */ static int numoptions[WPS_MAX_COND_LEVEL]; -/* the current line in the file */ -static int line; +/* line number, debug only */ +static int line_number; /* the current viewport */ static struct skin_viewport *curr_vp; +/* the current line, linked to the above viewport */ +static struct wps_line *curr_line; #ifdef HAVE_LCD_BITMAP @@ -397,7 +399,7 @@ immediately after the first eol, i.e. to the start of the next line */ static int skip_end_of_line(const char *wps_bufptr) { - line++; + line_number++; int skip = 0; while(*(wps_bufptr + skip) != '\n') skip++; @@ -405,13 +407,63 @@ } /* Starts a new subline in the current line during parsing */ -static void wps_start_new_subline(struct wps_data *data) +static bool wps_start_new_subline(struct wps_line *line, int curr_token) { - data->num_sublines++; - data->sublines[data->num_sublines].first_token_idx = data->num_tokens; - data->lines[data->num_lines].num_sublines++; + struct wps_subline *subline = skin_buffer_alloc(sizeof(struct wps_subline)); + if (!subline) + return false; + subline->first_token_idx = curr_token; + subline->next = NULL; + + subline->line_type = 0; + subline->time_mult = 0; + + line->curr_subline->last_token_idx = curr_token-1; + line->curr_subline->next = subline; + line->curr_subline = subline; + return true; } +static bool wps_start_new_line(struct skin_viewport *vp, int curr_token) +{ + struct wps_line *line = skin_buffer_alloc(sizeof(struct wps_line)); + struct wps_subline *subline = NULL; + if (!line) + return false; + line_number++; + + + /* init the subline */ + subline = &line->sublines; + subline->first_token_idx = curr_token; + subline->next = NULL; + subline->line_type = 0; + subline->time_mult = 0; + + /* init the new line */ + line->curr_subline = &line->sublines; + line->next = NULL; + line->subline_expire_time = 0; + + /* connect to curr_line and vp pointers. + * 1) close the previous lines subline + * 2) connect to vp pointer + * 3) connect to curr_line global pointer + */ + if (curr_line) + { + if (curr_line->curr_subline->first_token_idx != curr_token) + curr_token--; + curr_line->curr_subline->last_token_idx = curr_token; + curr_line->next = line; + curr_line->curr_subline = NULL; + } + curr_line = line; + if (!vp->lines) + vp->lines = line; + return true; +} + #ifdef HAVE_LCD_BITMAP static int parse_statusbar_enable(const char *wps_bufptr, @@ -618,6 +670,11 @@ skin_vp->label = VP_NO_LABEL; skin_vp->pb = NULL; + curr_line = NULL; + if (!wps_start_new_line(skin_vp, wps_data->num_tokens)) + return WPS_ERROR_INVALID_PARAM; + + if (*ptr == 'l') { if (*(ptr+1) == '|') @@ -647,19 +704,7 @@ if (*ptr != '|') return WPS_ERROR_INVALID_PARAM; - curr_vp->last_line = wps_data->num_lines - 1; - skin_vp->first_line = wps_data->num_lines; - - if (wps_data->num_sublines < WPS_MAX_SUBLINES) - { - wps_data->lines[wps_data->num_lines].first_subline_idx = - wps_data->num_sublines; - - wps_data->sublines[wps_data->num_sublines].first_token_idx = - wps_data->num_tokens; - } - struct skin_token_list *list = new_skin_token_list_item(NULL, skin_vp); if (!list) return WPS_ERROR_INVALID_PARAM; @@ -826,8 +871,15 @@ #else int font_height = 8; #endif - int line_num = wps_data->num_lines - curr_vp->first_line; - + /* we need to know what line number (viewport relative) this pb is, + * so count them... */ + int line_num = -1; + struct wps_line *line = curr_vp->lines; + while (line) + { + line_num++; + line = line->next; + } pb->have_bitmap_pb = false; pb->bm.data = NULL; /* no bitmap specified */ @@ -1241,8 +1293,7 @@ taglen = (tag->type != WPS_TOKEN_UNKNOWN) ? strlen(tag->name) : 2; token->type = tag->type; - wps_data->sublines[wps_data->num_sublines].line_type |= - tag->refresh_type; + curr_line->curr_subline->line_type |= tag->refresh_type; /* if the tag has a special parsing function, we call it */ if (tag->parse_func) @@ -1282,7 +1333,7 @@ int ret; int max_tokens = TOKEN_BLOCK_SIZE; size_t buf_free = 0; - line = 1; + line_number = 1; level = -1; /* allocate enough RAM for a reasonable skin, grow as needed. @@ -1293,8 +1344,7 @@ skin_buffer_increment(max_tokens * sizeof(struct wps_token), false); data->num_tokens = 0; - while(*wps_bufptr && !fail - && data->num_lines < WPS_MAX_LINES) + while (*wps_bufptr && !fail) { /* first make sure there is enough room for tokens */ if (max_tokens -1 == data->num_tokens) @@ -1337,9 +1387,7 @@ break; } - if (data->num_sublines+1 < WPS_MAX_SUBLINES) - wps_start_new_subline(data); - else + if (!wps_start_new_subline(curr_line, data->num_tokens)) fail = PARSE_FAIL_LIMITS_EXCEEDED; break; @@ -1419,19 +1467,15 @@ fail = PARSE_FAIL_UNCLOSED_COND; break; } + data->tokens[data->num_tokens].type = WPS_TOKEN_CHARACTER; + data->tokens[data->num_tokens].value.c = '\n'; + data->tokens[data->num_tokens].next = false; + data->num_tokens++; - line++; - wps_start_new_subline(data); - data->num_lines++; /* Start a new line */ - - if ((data->num_lines < WPS_MAX_LINES) && - (data->num_sublines < WPS_MAX_SUBLINES)) - { - data->lines[data->num_lines].first_subline_idx = - data->num_sublines; - - data->sublines[data->num_sublines].first_token_idx = - data->num_tokens; + if (!wps_start_new_line(curr_vp, data->num_tokens)) + { + fail = PARSE_FAIL_LIMITS_EXCEEDED; + break; } break; @@ -1511,11 +1555,12 @@ /* freeup unused tokens */ skin_buffer_free_from_front(sizeof(struct wps_token) * (max_tokens - data->num_tokens)); - curr_vp->last_line = data->num_lines - 1; + /* close the last subline */ + curr_line->curr_subline->last_token_idx = data->num_tokens; #if defined(DEBUG) || defined(SIMULATOR) if (debug) - print_debug_info(data, fail, line); + print_debug_info(data, fail, line_number); #else (void)debug; #endif @@ -1658,6 +1703,11 @@ curr_vp->vp.height = display->getheight(); curr_vp->pb = NULL; curr_vp->hidden_flags = 0; + + if (!wps_start_new_line(curr_vp, 0)) + return false; + curr_line = curr_vp->lines; + switch (statusbar_position(display->screen_type)) { case STATUSBAR_OFF: Index: apps/gui/skin_engine/skin_tokens.c =================================================================== --- apps/gui/skin_engine/skin_tokens.c (revision 22559) +++ apps/gui/skin_engine/skin_tokens.c (working copy) @@ -164,6 +164,8 @@ switch (token->type) { case WPS_TOKEN_CHARACTER: + if (token->value.c == '\n') + return NULL; return &(token->value.c); case WPS_TOKEN_STRING: Index: apps/gui/skin_engine/skin_display.c =================================================================== --- apps/gui/skin_engine/skin_display.c (revision 22559) +++ apps/gui/skin_engine/skin_display.c (working copy) @@ -391,25 +391,7 @@ #endif /* HAVE_LCD_CHARCELL */ -/* Returns the index of the subline in the subline array - line - 0-based line number - subline - 0-based subline number within the line - */ -static int subline_index(struct wps_data *data, int line, int subline) -{ - return data->lines[line].first_subline_idx + subline; -} - -/* Returns the index of the first subline's token in the token array - line - 0-based line number - subline - 0-based subline number within the line - */ -static int first_token_index(struct wps_data *data, int line, int subline) -{ - int first_subline_idx = data->lines[line].first_subline_idx; - return data->sublines[first_subline_idx + subline].first_token_idx; -} - +#if 0 int skin_last_token_index(struct wps_data *data, int line, int subline) { int first_subline_idx = data->lines[line].first_subline_idx; @@ -425,7 +407,7 @@ return data->num_tokens - 1; } } - +#endif /* Return the index to the end token for the conditional token at index. The conditional token can be either a start token or a separator (i.e. option) token. @@ -541,7 +523,7 @@ The return value indicates whether the line needs to be updated. */ static bool get_line(struct gui_wps *gwps, - int line, int subline, + struct wps_subline *subline, struct align_pos *align, char *linebuf, int linebuf_size) @@ -551,8 +533,8 @@ char temp_buf[128]; char *buf = linebuf; /* will always point to the writing position */ char *linebuf_end = linebuf + linebuf_size - 1; - int i, last_token_idx; bool update = false; + int i; /* alignment-related variables */ int cur_align; @@ -562,11 +544,9 @@ align->left = NULL; align->center = NULL; align->right = NULL; - /* Process all tokens of the desired subline */ - last_token_idx = skin_last_token_index(data, line, subline); - for (i = first_token_index(data, line, subline); - i <= last_token_idx; i++) + for (i = subline->first_token_idx; + i <= subline->last_token_idx; i++) { switch(data->tokens[i].type) { @@ -685,18 +665,14 @@ return update; } - -static void get_subline_timeout(struct gui_wps *gwps, int line, int subline) +static void get_subline_timeout(struct gui_wps *gwps, struct wps_subline *subline) { struct wps_data *data = gwps->data; int i; - int subline_idx = subline_index(data, line, subline); - int last_token_idx = skin_last_token_index(data, line, subline); + subline->time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER; - data->sublines[subline_idx].time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER; - - for (i = first_token_index(data, line, subline); - i <= last_token_idx; i++) + for (i = subline->first_token_idx; + i <= subline->last_token_idx; i++) { switch(data->tokens[i].type) { @@ -712,7 +688,7 @@ break; case WPS_TOKEN_SUBLINE_TIMEOUT: - data->sublines[subline_idx].time_mult = data->tokens[i].value.i; + subline->time_mult = data->tokens[i].value.i; break; default: @@ -723,77 +699,34 @@ /* Calculates which subline should be displayed for the specified line Returns true iff the subline must be refreshed */ -static bool update_curr_subline(struct gui_wps *gwps, int line) +static bool update_curr_subline(struct gui_wps *gwps, struct wps_line *line) { - struct wps_data *data = gwps->data; - - int search, search_start, num_sublines; - bool reset_subline; - bool new_subline_refresh; - bool only_one_subline; - - num_sublines = data->lines[line].num_sublines; - reset_subline = (data->lines[line].curr_subline == SUBLINE_RESET); - new_subline_refresh = false; - only_one_subline = false; - + /* shortcut this whole thing if we need to reset the line completly */ + if (line->curr_subline == NULL) + { + line->curr_subline = &line->sublines; + line->subline_expire_time = current_tick; + return true; + } /* if time to advance to next sub-line */ - if (TIME_AFTER(current_tick, data->lines[line].subline_expire_time - 1) || - reset_subline) + if (TIME_AFTER(current_tick, line->subline_expire_time - 1)) { - /* search all sublines until the next subline with time > 0 - is found or we get back to the subline we started with */ - if (reset_subline) - search_start = 0; - else - search_start = data->lines[line].curr_subline; - - for (search = 0; search < num_sublines; search++) + /* if there is only one subline, there is no need to search for a new one */ + if (&line->sublines == line->curr_subline && + line->curr_subline->next == NULL) { - data->lines[line].curr_subline++; - - /* wrap around if beyond last defined subline or WPS_MAX_SUBLINES */ - if (data->lines[line].curr_subline == num_sublines) - { - if (data->lines[line].curr_subline == 1) - only_one_subline = true; - data->lines[line].curr_subline = 0; - } - - /* if back where we started after search or - only one subline is defined on the line */ - if (((search > 0) && - (data->lines[line].curr_subline == search_start)) || - only_one_subline) - { - /* no other subline with a time > 0 exists */ - data->lines[line].subline_expire_time = (reset_subline ? - current_tick : - data->lines[line].subline_expire_time) + 100 * HZ; - break; - } - else - { - /* get initial time multiplier for this subline */ - get_subline_timeout(gwps, line, data->lines[line].curr_subline); - - int subline_idx = subline_index(data, line, - data->lines[line].curr_subline); - - /* only use this subline if subline time > 0 */ - if (data->sublines[subline_idx].time_mult > 0) - { - new_subline_refresh = true; - data->lines[line].subline_expire_time = (reset_subline ? - current_tick : data->lines[line].subline_expire_time) + - TIMEOUT_UNIT*data->sublines[subline_idx].time_mult; - break; - } - } + line->subline_expire_time += HZ; + return true; } + if (line->curr_subline->next) + line->curr_subline = line->curr_subline->next; + else + line->curr_subline = &line->sublines; + get_subline_timeout(gwps, line->curr_subline); + line->subline_expire_time += TIMEOUT_UNIT*line->curr_subline->time_mult; + return true; } - - return new_subline_refresh; + return false; } /* Display a line appropriately according to its alignment format. @@ -971,8 +904,7 @@ if (!id3) return false; - - int line, i, subline_idx; + unsigned flags; char linebuf[MAX_PATH]; @@ -980,6 +912,9 @@ align.left = NULL; align.center = NULL; align.right = NULL; + + + struct skin_token_list *viewport_list; bool update_line, new_subline_refresh; @@ -999,12 +934,20 @@ /* reset to first subline if refresh all flag is set */ if (refresh_mode == WPS_REFRESH_ALL) { + struct wps_line *line; + display->set_viewport(&find_viewport(VP_DEFAULT_LABEL, data)->vp); display->clear_viewport(); - - for (i = 0; i <= data->num_lines; i++) + + for (viewport_list = data->viewports; + viewport_list; viewport_list = viewport_list->next) { - data->lines[i].curr_subline = SUBLINE_RESET; + struct skin_viewport *skin_viewport = + (struct skin_viewport *)viewport_list->token->value.data; + for(line = skin_viewport->lines; line; line = line->next) + { + line->curr_subline = NULL; + } } } @@ -1017,7 +960,6 @@ #endif /* disable any viewports which are conditionally displayed */ - struct skin_token_list *viewport_list; for (viewport_list = data->viewports; viewport_list; viewport_list = viewport_list->next) { @@ -1069,25 +1011,27 @@ { display->clear_viewport(); } + + /* loop over the lines for this viewport */ + struct wps_line *line; + int line_count = 0; - for (line = skin_viewport->first_line; - line <= skin_viewport->last_line; line++) + for (line = skin_viewport->lines; line; line = line->next, line_count++) { + struct wps_subline *subline; memset(linebuf, 0, sizeof(linebuf)); update_line = false; /* get current subline for the line */ new_subline_refresh = update_curr_subline(gwps, line); + subline = line->curr_subline; + flags = line->curr_subline->line_type; - subline_idx = subline_index(data, line, - data->lines[line].curr_subline); - flags = data->sublines[subline_idx].line_type; - if (vp_refresh_mode == WPS_REFRESH_ALL || (flags & vp_refresh_mode) || new_subline_refresh) { /* get_line tells us if we need to update the line */ - update_line = get_line(gwps, line, data->lines[line].curr_subline, + update_line = get_line(gwps, subline, &align, linebuf, sizeof(linebuf)); } #ifdef HAVE_LCD_BITMAP @@ -1098,19 +1042,19 @@ update_line = false; int h = font_get(skin_viewport->vp.font)->height; - int peak_meter_y = (line - skin_viewport->first_line)* h; + int peak_meter_y = line_count* h; /* The user might decide to have the peak meter in the last line so that it is only displayed if no status bar is visible. If so we neither want do draw nor enable the peak meter. */ - if (peak_meter_y + h <= display->getheight()) { + if (peak_meter_y + h <= skin_viewport->vp.y+skin_viewport->vp.height) { /* found a line with a peak meter -> remember that we must enable it later */ enable_pm = true; peak_meter_enabled = true; peak_meter_screen(gwps->display, 0, peak_meter_y, - MIN(h, display->getheight() - peak_meter_y)); + MIN(h, skin_viewport->vp.y+skin_viewport->vp.height - peak_meter_y)); } else { @@ -1143,10 +1087,10 @@ /* if the line is a scrolling one we don't want to update too often, so that it has the time to scroll */ if ((vp_refresh_mode & WPS_REFRESH_SCROLL) || new_subline_refresh) - write_line(display, &align, line - skin_viewport->first_line, true); + write_line(display, &align, line_count, true); } else - write_line(display, &align, line - skin_viewport->first_line, false); + write_line(display, &align, line_count, false); } } Index: apps/gui/skin_engine/wps_internals.h =================================================================== --- apps/gui/skin_engine/wps_internals.h (revision 22559) +++ apps/gui/skin_engine/wps_internals.h (working copy) @@ -160,12 +160,16 @@ Tokens of this subline end where tokens for the next subline begin. */ unsigned short first_token_idx; + unsigned short last_token_idx; /* Bit or'ed WPS_REFRESH_xxx */ unsigned char line_type; /* How long the subline should be displayed, in 10ths of sec */ unsigned char time_mult; + + /* pointer to the next subline in this line */ + struct wps_subline *next; }; /* Description of a line on the WPS. A line is a set of sublines. @@ -173,19 +177,18 @@ the next subline of the line is displayed. And so on. */ struct wps_line { - /* Number of sublines in this line */ - signed char num_sublines; + /* Linked list of all the sublines on this line, + * a line *must* have at least one subline so no need to add an extra pointer */ + struct wps_subline sublines; + /* pointer to the current subline */ + struct wps_subline *curr_subline; - /* Number (0-based) of the subline within this line currently being displayed */ - signed char curr_subline; - - /* Index of the first subline of this line in the subline array. - Sublines for this line end where sublines for the next line begin. */ - unsigned short first_subline_idx; - /* When the next subline of this line should be displayed (absolute time value in ticks) */ long subline_expire_time; + + /* pointer to the next line */ + struct wps_line *next; }; #define VP_DRAW_HIDEABLE 0x1 @@ -196,9 +199,7 @@ struct skin_viewport { struct viewport vp; /* The LCD viewport struct */ struct progressbar *pb; - /* Indexes of the first and last lines belonging to this viewport in the - lines[] array */ - int first_line, last_line; + struct wps_line *lines; char hidden_flags; char label; }; @@ -259,20 +260,8 @@ bool remote_wps; #endif - /* Number of lines in the WPS. During WPS parsing, this is - the index of the line being parsed. */ - int num_lines; - - /* Number of viewports in the WPS */ struct skin_token_list *viewports; - struct wps_line lines[WPS_MAX_LINES]; - - /* Total number of sublines in the WPS. During WPS parsing, this is - the index of the subline where the parsed tokens are added to. */ - int num_sublines; - struct wps_subline sublines[WPS_MAX_SUBLINES]; - /* Total number of tokens in the WPS. During WPS parsing, this is the index of the token being parsed. */ int num_tokens;