int sb_postproccess(enum screen_type screen, struct wps_data *data) { if (data->wps_loaded) { /* hide the sb's default viewport because it has nasty effect with stuff * not part of the statusbar, * hence .sbs's without any other vps are unsupported*/ struct skin_viewport *vp = skin_find_item(VP_DEFAULT_LABEL_STRING, SKIN_FIND_VP, data); struct skin_element *tree = SKINOFFSETTOPTR(get_skin_buffer(data), data->tree); struct skin_element *next_vp = SKINOFFSETTOPTR(get_skin_buffer(data), tree->next); if (vp) { if (!next_vp) { /* no second viewport, let parsing fail */ return 0; } /* hide this viewport, forever */ vp->hidden_flags = VP_NEVER_VISIBLE; } sb_set_info_vp(screen, VP_DEFAULT_LABEL); sbs_loaded[screen] = true; } viewportmanager_theme_undo(screen, false); return 1; }
/* Evaluate the conditional that is at *token_index and return whether a skip has ocurred. *token_index is updated with the new position. */ int evaluate_conditional(struct gui_wps *gwps, int offset, struct conditional *conditional, int num_options) { if (!gwps) return false; char result[128]; const char *value; int intval = num_options < 2 ? 2 : num_options; /* get_token_value needs to know the number of options in the enum */ value = get_token_value(gwps, SKINOFFSETTOPTR(get_skin_buffer(gwps->data), conditional->token), offset, result, sizeof(result), &intval); /* intval is now the number of the enum option we want to read, starting from 1. If intval is -1, we check if value is empty. */ if (intval == -1) { if (num_options == 1) /* so %?AA<true> */ intval = (value && *value) ? 1 : 0; /* returned as 0 for true, -1 for false */ else intval = (value && *value) ? 1 : num_options; } else if (intval > num_options || intval < 1) intval = num_options; return intval -1; }
/** Disarms all touchregions. */ void skin_disarm_touchregions(struct wps_data *data) { char* skin_buffer = get_skin_buffer(data); struct skin_token_list *regions = SKINOFFSETTOPTR(skin_buffer, data->touchregions); while (regions) { struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, regions->token); struct touchregion *region = SKINOFFSETTOPTR(skin_buffer, token->value.data); region->armed = false; regions = SKINOFFSETTOPTR(skin_buffer, regions->next); } }
void wps_display_images(struct gui_wps *gwps, struct viewport* vp) { if(!gwps || !gwps->data || !gwps->display) return; (void)vp; struct wps_data *data = gwps->data; struct screen *display = gwps->display; struct skin_token_list *list = SKINOFFSETTOPTR(get_skin_buffer(data), data->images); while (list) { struct wps_token *token = SKINOFFSETTOPTR(get_skin_buffer(data), list->token); struct gui_img *img = (struct gui_img*)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data); if (img->using_preloaded_icons && img->display >= 0) { screen_put_icon(display, img->x, img->y, img->display); } else if (img->loaded) { if (img->display >= 0) { wps_draw_image(gwps, img, img->display); } } list = SKINOFFSETTOPTR(get_skin_buffer(data), list->next); } #ifdef HAVE_ALBUMART /* now draw the AA */ struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart); if (aa && SKINOFFSETTOPTR(get_skin_buffer(data), aa->vp) == vp && aa->draw_handle >= 0) { draw_album_art(gwps, aa->draw_handle, false); aa->draw_handle = -1; } #endif display->set_drawmode(DRMODE_SOLID); }
/* Get the touched action. * egde_offset is a percentage value for the position of the touch * inside the bar for regions which arnt WPS_TOUCHREGION_ACTION type. */ int skin_get_touchaction(struct wps_data *data, int* edge_offset, struct touchregion **retregion) { int returncode = ACTION_NONE; short x,y; short vx, vy; int type = action_get_touchscreen_press(&x, &y); struct skin_viewport *wvp; struct touchregion *r, *temp = NULL; char* skin_buffer = get_skin_buffer(data); bool repeated = (type == BUTTON_REPEAT); bool released = (type == BUTTON_REL); bool pressed = (type == BUTTON_TOUCHSCREEN); struct skin_token_list *regions = SKINOFFSETTOPTR(skin_buffer, data->touchregions); bool needs_repeat; while (regions) { struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, regions->token); r = SKINOFFSETTOPTR(skin_buffer, token->value.data); wvp = SKINOFFSETTOPTR(skin_buffer, r->wvp); /* make sure this region's viewport is visible */ if (wvp->hidden_flags&VP_DRAW_HIDDEN) { regions = SKINOFFSETTOPTR(skin_buffer, regions->next); continue; } if (data->touchscreen_locked && (r->action != ACTION_TOUCH_SOFTLOCK && !r->allow_while_locked)) { regions = SKINOFFSETTOPTR(skin_buffer, regions->next); continue; } needs_repeat = r->press_length != PRESS; /* check if it's inside this viewport */ if (viewport_point_within_vp(&(wvp->vp), x, y)) { /* reposition the touch inside the viewport since touchregions * are relative to a preceding viewport */ vx = x - wvp->vp.x; vy = y - wvp->vp.y; /* now see if the point is inside this region */ if (vx >= r->x && vx < r->x+r->width && vy >= r->y && vy < r->y+r->height) { /* reposition the touch within the area */ vx -= r->x; vy -= r->y; switch(r->action) { case ACTION_TOUCH_SCROLLBAR: case ACTION_TOUCH_VOLUME: case ACTION_TOUCH_SETTING: if (edge_offset) { struct progressbar *bar = SKINOFFSETTOPTR(skin_buffer, r->bar); if(r->width > r->height) *edge_offset = vx*100/r->width; else *edge_offset = vy*100/r->height; if (r->reverse_bar || (bar && bar->invert_fill_direction)) *edge_offset = 100 - *edge_offset; } temp = r; returncode = r->action; r->last_press = current_tick; break; default: if (r->armed && ((repeated && needs_repeat) || (released && !needs_repeat))) { returncode = r->action; temp = r; } if (pressed) { r->armed = true; r->last_press = current_tick; } break; } } } regions = SKINOFFSETTOPTR(skin_buffer, regions->next); } /* On release, all regions are disarmed. */ if (released) skin_disarm_touchregions(data); if (retregion && temp) *retregion = temp; if (temp && temp->press_length == LONG_PRESS) temp->armed = false; if (returncode != ACTION_NONE) { if (global_settings.party_mode) { switch (returncode) { case ACTION_WPS_PLAY: case ACTION_WPS_SKIPPREV: case ACTION_WPS_SKIPNEXT: case ACTION_WPS_STOP: returncode = ACTION_NONE; break; default: break; } } switch (returncode) { case ACTION_TOUCH_SOFTLOCK: data->touchscreen_locked = !data->touchscreen_locked; returncode = ACTION_NONE; break; case ACTION_WPS_PLAY: if (!audio_status()) { if ( global_status.resume_index != -1 ) { if (playlist_resume() != -1) { playlist_start(global_status.resume_index, global_status.resume_offset); } } else { splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME)); } } else { wps_do_playpause(false); } returncode = ACTION_REDRAW; break; case ACTION_WPS_SKIPPREV: audio_prev(); returncode = ACTION_REDRAW; break; case ACTION_WPS_SKIPNEXT: audio_next(); returncode = ACTION_REDRAW; break; case ACTION_WPS_STOP: audio_stop(); returncode = ACTION_REDRAW; break; case ACTION_SETTINGS_INC: case ACTION_SETTINGS_DEC: { const struct settings_list *setting = temp->setting_data.setting; option_select_next_val(setting, returncode == ACTION_SETTINGS_DEC, true); returncode = ACTION_REDRAW; } break; case ACTION_SETTINGS_SET: { struct touchsetting *data = &temp->setting_data; const struct settings_list *s = data->setting; void (*f)(int) = NULL; switch (s->flags&F_T_MASK) { case F_T_CUSTOM: s->custom_setting ->load_from_cfg(s->setting, SKINOFFSETTOPTR(skin_buffer, data->value.text)); break; case F_T_INT: case F_T_UINT: *(int*)s->setting = data->value.number; if ((s->flags & F_T_SOUND) == F_T_SOUND) sound_set(s->sound_setting->setting, data->value.number); else if (s->flags&F_CHOICE_SETTING) f = s->choice_setting->option_callback; else if (s->flags&F_TABLE_SETTING) f = s->table_setting->option_callback; else f = s->int_setting->option_callback; if (f) f(data->value.number); break; case F_T_BOOL: *(bool*)s->setting = data->value.number ? true : false; if (s->bool_setting->option_callback) s->bool_setting ->option_callback(data->value.number ? true : false); break; } returncode = ACTION_REDRAW; } break; case ACTION_TOUCH_MUTE: { const int min_vol = sound_min(SOUND_VOLUME); if (global_settings.volume == min_vol) global_settings.volume = temp->value; else { temp->value = global_settings.volume; global_settings.volume = min_vol; } setvol(); returncode = ACTION_REDRAW; } break; case ACTION_TOUCH_SHUFFLE: /* toggle shuffle mode */ { global_settings.playlist_shuffle = !global_settings.playlist_shuffle; replaygain_update(); if (global_settings.playlist_shuffle) playlist_randomise(NULL, current_tick, true); else playlist_sort(NULL, true); returncode = ACTION_REDRAW; } break; case ACTION_TOUCH_REPMODE: /* cycle the repeat mode setting */ { const struct settings_list *rep_setting = find_setting(&global_settings.repeat_mode, NULL); option_select_next_val(rep_setting, false, true); audio_flush_and_reload_tracks(); returncode = ACTION_REDRAW; } break; case ACTION_TOUCH_SETTING: { struct progressbar *bar = SKINOFFSETTOPTR(skin_buffer, temp->bar); if (bar && edge_offset) { int val, count; get_setting_info_for_bar(bar->setting_id, &count, &val); val = *edge_offset * count / 100; update_setting_value_from_touch(bar->setting_id, val); } } break; } return returncode; } return ACTION_TOUCHSCREEN; }
void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb) { struct screen *display = gwps->display; struct viewport *vp = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->vp); struct wps_state *state = skin_get_global_state(); struct mp3entry *id3 = state->id3; int x = pb->x, y = pb->y, width = pb->width, height = pb->height; unsigned long length, end; int flags = HORIZONTAL; if (height < 0) height = font_get(vp->font)->height; if (y < 0) { int line_height = font_get(vp->font)->height; /* center the pb in the line, but only if the line is higher than the pb */ int center = (line_height-height)/2; /* if Y was not set calculate by font height,Y is -line_number-1 */ y = line*line_height + (0 > center ? 0 : center); } if (pb->type == SKIN_TOKEN_VOLUMEBAR) { int minvol = sound_min(SOUND_VOLUME); int maxvol = sound_max(SOUND_VOLUME); length = maxvol-minvol; end = global_settings.volume-minvol; } else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR) { length = 100; end = battery_level(); } else if (pb->type == SKIN_TOKEN_PEAKMETER_LEFTBAR || pb->type == SKIN_TOKEN_PEAKMETER_RIGHTBAR) { int left, right, val; peak_meter_current_vals(&left, &right); val = pb->type == SKIN_TOKEN_PEAKMETER_LEFTBAR ? left : right; length = MAX_PEAK; end = peak_meter_scale_value(val, length); } else if (pb->type == SKIN_TOKEN_LIST_SCROLLBAR) { int val, min, max; skinlist_get_scrollbar(&val, &min, &max); end = val - min; length = max - min; } #if CONFIG_TUNER else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF)) { #ifdef HAVE_RADIO_RSSI if (pb->type == SKIN_TOKEN_TUNER_RSSI_BAR) { int val = tuner_get(RADIO_RSSI); int min = tuner_get(RADIO_RSSI_MIN); int max = tuner_get(RADIO_RSSI_MAX); end = val - min; length = max - min; } else #endif { int min = fm_region_data[global_settings.fm_region].freq_min; end = radio_current_frequency() - min; length = fm_region_data[global_settings.fm_region].freq_max - min; } } #endif else if (id3 && id3->length) { length = id3->length; end = id3->elapsed + state->ff_rewind_count; } else { length = 1; end = 0; } if (!pb->horizontal) { /* we want to fill upwards which is technically inverted. */ flags = INVERTFILL; } if (pb->invert_fill_direction) { flags ^= INVERTFILL; } if (pb->nofill) { flags |= INNER_NOFILL; } if (SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider)) { struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider); /* clear the slider */ screen_clear_area(display, x, y, width, height); /* shrink the bar so the slider is inside bounds */ if (flags&HORIZONTAL) { width -= img->bm.width; x += img->bm.width / 2; } else { height -= img->bm.height; y += img->bm.height / 2; } } if (SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->backdrop)) { struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->backdrop); img->bm.data = core_get_data(img->buflib_handle); display->bmp_part(&img->bm, 0, 0, x, y, width, height); flags |= DONT_CLEAR_EXCESS; } if (!pb->nobar) { struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->image); if (img) { char *img_data = core_get_data(img->buflib_handle); img->bm.data = img_data; gui_bitmap_scrollbar_draw(display, &img->bm, x, y, width, height, length, 0, end, flags); } else gui_scrollbar_draw(display, x, y, width, height, length, 0, end, flags); } if (SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider)) { int xoff = 0, yoff = 0; int w = width, h = height; struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider); img->bm.data = core_get_data(img->buflib_handle); if (flags&HORIZONTAL) { w = img->bm.width; xoff = width * end / length; if (flags&INVERTFILL) xoff = width - xoff; xoff -= w / 2; } else { h = img->bm.height; yoff = height * end / length; if (flags&INVERTFILL) yoff = height - yoff; yoff -= h / 2; } display->bmp_part(&img->bm, 0, 0, x + xoff, y + yoff, w, h); } if (pb->type == SKIN_TOKEN_PROGRESSBAR) { if (id3 && id3->length) { #ifdef AB_REPEAT_ENABLE if (ab_repeat_mode_enabled()) ab_draw_markers(display, id3->length, x, y, width, height); #endif if (id3->cuesheet) cue_draw_markers(display, id3->cuesheet, id3->length, x, y+1, width, height-2); } #if 0 /* disable for now CONFIG_TUNER */ else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF)) { presets_draw_markers(display, x, y, width, height); } #endif } }
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; }
/* Draw the album art bitmap from the given handle ID onto the given WPS. Call with clear = true to clear the bitmap instead of drawing it. */ void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear) { if (!gwps || !gwps->data || !gwps->display || handle_id < 0) return; struct wps_data *data = gwps->data; struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart); if (!aa) return; struct bitmap *bmp; if (bufgetdata(handle_id, 0, (void *)&bmp) <= 0) return; short x = aa->x; short y = aa->y; short width = bmp->width; short height = bmp->height; if (aa->width > 0) { /* Crop if the bitmap is too wide */ width = MIN(bmp->width, aa->width); /* Align */ if (aa->xalign & WPS_ALBUMART_ALIGN_RIGHT) x += aa->width - width; else if (aa->xalign & WPS_ALBUMART_ALIGN_CENTER) x += (aa->width - width) / 2; } if (aa->height > 0) { /* Crop if the bitmap is too high */ height = MIN(bmp->height, aa->height); /* Align */ if (aa->yalign & WPS_ALBUMART_ALIGN_BOTTOM) y += aa->height - height; else if (aa->yalign & WPS_ALBUMART_ALIGN_CENTER) y += (aa->height - height) / 2; } if (!clear) { /* Draw the bitmap */ gwps->display->bitmap_part((fb_data*)bmp->data, 0, 0, STRIDE(gwps->display->screen_type, bmp->width, bmp->height), x, y, width, height); #ifdef HAVE_LCD_INVERT if (global_settings.invert) { gwps->display->set_drawmode(DRMODE_COMPLEMENT); gwps->display->fillrect(x, y, width, height); gwps->display->set_drawmode(DRMODE_SOLID); } #endif } else { /* Clear the bitmap */ gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); gwps->display->fillrect(x, y, width, height); gwps->display->set_drawmode(DRMODE_SOLID); } }