static void skin_render_viewport(struct skin_element* viewport, 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 = viewport; struct skin_draw_info info = { .gwps = gwps, .buf = linebuf, .buf_size = sizeof(linebuf), .line_number = 0, .no_line_break = false, .line_scrolls = false, .refresh_type = refresh_type, .skin_vp = skin_viewport, .offset = 0 }; struct align_pos * align = &info.align; bool needs_update; #ifdef HAVE_LCD_BITMAP /* Set images to not to be displayed */ struct skin_token_list *imglist = gwps->data->images; while (imglist) { struct gui_img *img = (struct gui_img *)imglist->token->value.data; img->display = -1; imglist = imglist->next; } #endif while (line) { linebuf[0] = '\0'; info.no_line_break = false; info.line_scrolls = false; info.force_redraw = false; info.cur_align_start = info.buf; 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); #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) if (skin_viewport->vp.fg_pattern != skin_viewport->start_fgcolour || skin_viewport->vp.bg_pattern != skin_viewport->start_bgcolour) { /* 2bit lcd drivers need lcd_set_viewport() to be called to change * the colour, 16bit doesnt. But doing this makes static text * get the new colour also */ needs_update = true; display->set_viewport(&skin_viewport->vp); } #endif /* only update if the line needs to be, and there is something to write */ if (refresh_type && needs_update) { if (info.line_scrolls) { /* if the line is a scrolling one we don't want to update too often, so that it has the time to scroll */ if ((refresh_type & SKIN_REFRESH_SCROLL) || info.force_redraw) write_line(display, align, info.line_number, true); } else write_line(display, align, info.line_number, false); } if (!info.no_line_break) info.line_number++; line = line->next; } #ifdef HAVE_LCD_BITMAP wps_display_images(gwps, &skin_viewport->vp); #endif } void skin_render(struct gui_wps *gwps, unsigned refresh_mode) { struct wps_data *data = gwps->data; struct screen *display = gwps->display; struct skin_element* viewport = data->tree; struct skin_viewport* skin_viewport; int old_refresh_mode = refresh_mode; #ifdef HAVE_LCD_CHARCELLS int i; for (i = 0; i < 8; i++) { if (data->wps_progress_pat[i] == 0) data->wps_progress_pat[i] = display->get_locked_pattern(); } #endif viewport = data->tree; skin_viewport = (struct skin_viewport *)viewport->data; if (skin_viewport->label && viewport->next && !strcmp(skin_viewport->label,VP_DEFAULT_LABEL)) refresh_mode = 0; for (viewport = data->tree; viewport; viewport = viewport->next) { /* SETUP */ skin_viewport = (struct skin_viewport*)viewport->data; unsigned vp_refresh_mode = refresh_mode; #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) skin_viewport->vp.fg_pattern = skin_viewport->start_fgcolour; skin_viewport->vp.bg_pattern = skin_viewport->start_bgcolour; #endif /* dont redraw the viewport if its disabled */ if (skin_viewport->hidden_flags&VP_NEVER_VISIBLE) { /* don't draw anything into this one */ vp_refresh_mode = 0; } else if ((skin_viewport->hidden_flags&VP_DRAW_HIDDEN)) { skin_viewport->hidden_flags |= VP_DRAW_WASHIDDEN; continue; } else if (((skin_viewport->hidden_flags& (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE)) == (VP_DRAW_WASHIDDEN|VP_DRAW_HIDEABLE))) { vp_refresh_mode = SKIN_REFRESH_ALL; skin_viewport->hidden_flags = VP_DRAW_HIDEABLE; } display->set_viewport(&skin_viewport->vp); if ((vp_refresh_mode&SKIN_REFRESH_ALL) == SKIN_REFRESH_ALL) { display->clear_viewport(); } /* render */ if (viewport->children_count) skin_render_viewport(viewport->children[0], gwps, skin_viewport, vp_refresh_mode); refresh_mode = old_refresh_mode; } /* Restore the default viewport */ display->set_viewport(NULL); display->update(); } #ifdef HAVE_LCD_BITMAP 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, .buf = linebuf, .buf_size = sizeof(linebuf), .line_number = 0, .no_line_break = false, .line_scrolls = false, .refresh_type = refresh_type, .skin_vp = skin_viewport, .offset = viewer->start_offset }; struct align_pos * align = &info.align; bool needs_update; int cur_pos, start_item, max; int nb_lines = viewport_get_nb_lines(viewer->vp); #if CONFIG_TUNER if (current_screen() == GO_TO_FM) { cur_pos = radio_current_preset(); start_item = cur_pos + viewer->start_offset; max = start_item+radio_preset_count(); } else #endif { struct cuesheet *cue = skin_get_global_state()->id3 ? skin_get_global_state()->id3->cuesheet : NULL; cur_pos = playlist_get_display_index(); max = playlist_amount()+1; if (cue) max += cue->track_count; start_item = MAX(0, cur_pos + viewer->start_offset); } if (max-start_item > nb_lines) max = start_item + nb_lines; line = viewer->line; while (start_item < max) { linebuf[0] = '\0'; info.no_line_break = false; info.line_scrolls = false; info.force_redraw = false; info.cur_align_start = info.buf; 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); /* only update if the line needs to be, and there is something to write */ if (refresh_type && needs_update) { if (info.line_scrolls) { /* if the line is a scrolling one we don't want to update too often, so that it has the time to scroll */ if ((refresh_type & SKIN_REFRESH_SCROLL) || info.force_redraw) write_line(display, align, info.line_number, true); } else write_line(display, align, info.line_number, false); } info.line_number++; info.offset++; start_item++; } }
bool skinlist_draw(struct screen *display, struct gui_synclist *list) { int cur_line, display_lines; const int screen = display->screen_type; struct viewport *parent = (list->parent[screen]); char* label = NULL; const int list_start_item = list->start_item[screen]; struct gui_wps wps; if (!skinlist_is_configured(screen, list)) return false; current_list = list; wps.display = display; wps.data = listcfg[screen]->data; display_lines = skinlist_get_line_count(screen, list); label = (char *)SKINOFFSETTOPTR(get_skin_buffer(wps.data), listcfg[screen]->label); display->set_viewport(parent); display->clear_viewport(); current_item = list->selected_item; current_nbitems = list->nb_items; needs_scrollbar[screen] = list->nb_items > display_lines; for (cur_line = 0; cur_line < display_lines; cur_line++) { struct skin_element* viewport; struct skin_viewport* skin_viewport = NULL; if (list_start_item+cur_line+1 > list->nb_items) break; current_drawing_line = list_start_item+cur_line; is_selected = list->show_selection_marker && list_start_item+cur_line == list->selected_item; for (viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), listcfg[screen]->data->tree); viewport; viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->next)) { int original_x, original_y; skin_viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->data); char *viewport_label = SKINOFFSETTOPTR(get_skin_buffer(wps.data), skin_viewport->label); if (viewport->children == 0 || !viewport_label || (skin_viewport->label && strcmp(label, viewport_label)) ) continue; if (is_selected) { memcpy(&listcfg[screen]->selected_item_vp, skin_viewport, sizeof(struct skin_viewport)); skin_viewport = &listcfg[screen]->selected_item_vp; } original_x = skin_viewport->vp.x; original_y = skin_viewport->vp.y; if (listcfg[screen]->tile) { int cols = (parent->width / listcfg[screen]->width); current_column = (cur_line)%cols; current_row = (cur_line)/cols; skin_viewport->vp.x = parent->x + listcfg[screen]->width*current_column + original_x; skin_viewport->vp.y = parent->y + listcfg[screen]->height*current_row + original_y; } else { current_column = 1; current_row = cur_line; skin_viewport->vp.x = parent->x + original_x; skin_viewport->vp.y = parent->y + original_y + (listcfg[screen]->height*cur_line); } display->set_viewport(&skin_viewport->vp); #ifdef HAVE_LCD_BITMAP /* Set images to not to be displayed */ struct skin_token_list *imglist = SKINOFFSETTOPTR(get_skin_buffer(wps.data), wps.data->images); while (imglist) { struct wps_token *token = SKINOFFSETTOPTR(get_skin_buffer(wps.data), imglist->token); struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(wps.data), token->value.data); img->display = -1; imglist = SKINOFFSETTOPTR(get_skin_buffer(wps.data), imglist->next); } #endif struct skin_element** children = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->children); skin_render_viewport(SKINOFFSETTOPTR(get_skin_buffer(wps.data), (intptr_t)children[0]), &wps, skin_viewport, SKIN_REFRESH_ALL); #ifdef HAVE_LCD_BITMAP wps_display_images(&wps, &skin_viewport->vp); #endif /* force disableing scroll because it breaks later */ if (!is_selected) { display->scroll_stop_viewport(&skin_viewport->vp); skin_viewport->vp.x = original_x; skin_viewport->vp.y = original_y; } } } current_column = -1; current_row = -1; display->set_viewport(parent); display->update_viewport(); current_drawing_line = list->selected_item; return true; }