diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c index 304ebf1..d0221a8 100644 --- a/apps/gui/skin_engine/skin_render.c +++ b/apps/gui/skin_engine/skin_render.c @@ -68,8 +68,8 @@ struct skin_draw_info { int offset; /* used by the playlist viewer */ }; -typedef bool (*skin_render_func)(struct skin_element* alternator, struct skin_draw_info *info); -bool skin_render_alternator(struct skin_element* alternator, struct skin_draw_info *info); +static int alternator_change_line(struct skin_element* alternator, + struct skin_draw_info *info, bool* line_changed); #ifdef HAVE_LCD_BITMAP static void skin_render_playlistviewer(struct playlistviewer* viewer, @@ -375,14 +375,29 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i { bool needs_update = false; int last_value, value; + bool in_changed_alternator = false; + struct skin_element *child; + struct conditional *conditional; + int old_refresh_mode = info->refresh_type; + + if (line->type == LINE_ALTERNATOR) + { + line = line->children[alternator_change_line(line, info, + &in_changed_alternator)]; + if (line->children_count == 0) + return in_changed_alternator; + if (in_changed_alternator) + { + info->refresh_type = SKIN_REFRESH_ALL; + info->force_redraw = true; + } + + } if (line->children_count == 0) return false; /* empty line, do nothing */ + child = line->children[0]; - struct skin_element *child = line->children[0]; - struct conditional *conditional; - skin_render_func func = skin_render_line; - int old_refresh_mode = info->refresh_type; while (child) { switch (child->type) @@ -411,20 +426,13 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i if (last_value >= 0 && value != last_value && last_value < child->children_count) do_tags_in_hidden_conditional(child->children[last_value], info); } - if (child->children[value]->type == LINE_ALTERNATOR) - { - func = skin_render_alternator; - } - else if (child->children[value]->type == LINE) - func = skin_render_line; - if (value != last_value) { info->refresh_type = SKIN_REFRESH_ALL; info->force_redraw = true; } - if (func(child->children[value], info)) + if (skin_render_line(child->children[value], info)) needs_update = true; else needs_update = needs_update || (last_value != value); @@ -475,6 +483,12 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i child = child->next; } + if (in_changed_alternator) + { + info->refresh_type = old_refresh_mode; + info->force_redraw = false; + needs_update = true; + } return needs_update; } @@ -483,6 +497,8 @@ static int get_subline_timeout(struct gui_wps *gwps, struct skin_element* line) struct skin_element *element=line; struct wps_token *token; int retval = DEFAULT_SUBLINE_TIME_MULTIPLIER*TIMEOUT_UNIT; +restart: /* we are really using tail recursion so do it with a messy goto + to prevent stack overusage */ if (element->type == LINE) { if (element->children_count == 0) @@ -504,9 +520,8 @@ static int get_subline_timeout(struct gui_wps *gwps, struct skin_element* line) element->children_count); if (val >= 0) { - retval = get_subline_timeout(gwps, element->children[val]); - if (retval >= 0) - return retval; + element = element->children[val]; + goto restart; } } element = element->next; @@ -514,11 +529,11 @@ static int get_subline_timeout(struct gui_wps *gwps, struct skin_element* line) return retval; } -bool skin_render_alternator(struct skin_element* element, struct skin_draw_info *info) +static int alternator_change_line(struct skin_element* element, + struct skin_draw_info *info, bool* line_changed) { bool changed_lines = false; struct line_alternator *alternator = (struct line_alternator*)element->data; - unsigned old_refresh = info->refresh_type; if (info->refresh_type == SKIN_REFRESH_ALL) { alternator->current_line = element->children_count-1; @@ -561,13 +576,9 @@ bool skin_render_alternator(struct skin_element* element, struct skin_draw_info alternator->current_line = try_line; alternator->next_change_tick = current_tick + rettimeout; } - - info->refresh_type = SKIN_REFRESH_ALL; - info->force_redraw = true; } - bool ret = skin_render_line(element->children[alternator->current_line], info); - info->refresh_type = old_refresh; - return changed_lines || ret; + *line_changed = changed_lines; + return alternator->current_line; } static void skin_render_viewport(struct skin_element* viewport, struct gui_wps *gwps, @@ -575,7 +586,6 @@ static void skin_render_viewport(struct skin_element* viewport, struct gui_wps * { struct screen *display = gwps->display; char linebuf[MAX_LINE]; - skin_render_func func = skin_render_line; struct skin_element* line = viewport; struct skin_draw_info info = { .gwps = gwps, @@ -613,14 +623,8 @@ static void skin_render_viewport(struct skin_element* viewport, struct gui_wps * align->left = info.buf; align->center = NULL; align->right = NULL; - - - if (line->type == LINE_ALTERNATOR) - func = skin_render_alternator; - else if (line->type == LINE) - func = skin_render_line; - - needs_update = func(line, &info); + + needs_update = skin_render_line(line, &info); /* only update if the line needs to be, and there is something to write */ if (refresh_type && needs_update) @@ -715,14 +719,13 @@ void skin_render(struct gui_wps *gwps, unsigned refresh_mode) } #ifdef HAVE_LCD_BITMAP -static void skin_render_playlistviewer(struct playlistviewer* viewer, +static __attribute__((noinline)) void skin_render_playlistviewer(struct playlistviewer* viewer, struct gui_wps *gwps, struct skin_viewport* skin_viewport, unsigned long refresh_type) { struct screen *display = gwps->display; char linebuf[MAX_LINE]; - skin_render_func func = skin_render_line; struct skin_element* line; struct skin_draw_info info = { .gwps = gwps, @@ -774,13 +777,7 @@ static void skin_render_playlistviewer(struct playlistviewer* viewer, align->center = NULL; align->right = NULL; - - if (line->type == LINE_ALTERNATOR) - func = skin_render_alternator; - else if (line->type == LINE) - func = skin_render_line; - - needs_update = func(line, &info); + needs_update = skin_render_line(line, &info); /* only update if the line needs to be, and there is something to write */ if (refresh_type && needs_update)