/* create and init a new wpsll item. * passing NULL to token will alloc a new one. * You should only pass NULL for the token when the token type (table above) * is WPS_NO_TOKEN which means it is not stored automatically in the skins token array */ static struct skin_token_list *new_skin_token_list_item(struct wps_token *token, void* token_data) { struct skin_token_list *llitem = (struct skin_token_list *)skin_buffer_alloc(sizeof(struct skin_token_list)); if (!token) token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token)); if (!llitem || !token) return NULL; llitem->next = NULL; llitem->token = token; if (token_data) llitem->token->value.data = token_data; return llitem; }
void skin_backdrop_load_setting(void) { int i; char filename[MAX_PATH], dir[MAX_PATH]; for(i=0;i<SKINNABLE_SCREENS_COUNT*NB_SCREENS;i++) { if (backdrops[i].name[0] == '-' && backdrops[i].screen == SCREEN_MAIN) { if (global_settings.backdrop_file[0] && global_settings.backdrop_file[0] != '-') { if (!backdrops[i].buffer) backdrops[i].buffer = (char*)skin_buffer_alloc(LCD_BACKDROP_BYTES); snprintf(filename, sizeof filename, "%s/%s.bmp", get_user_file_path(BACKDROP_DIR, 0, dir, sizeof(dir)), global_settings.backdrop_file); bool loaded = backdrops[i].buffer && screens[SCREEN_MAIN].backdrop_load(filename, backdrops[i].buffer); backdrops[i].name[2] = loaded ? '.' : '\0'; return; } else backdrops[i].name[2] = '\0'; } #if NB_SCREENS > 1 else if (backdrops[i].name[0] == '-') { backdrops[i].name[2] = '\0'; return; } #endif } }
static int parse_logical_if(struct skin_element *element, struct wps_token *token, struct wps_data *wps_data) { (void)wps_data; char *op = element->params[1].data.text; struct logical_if *lif = skin_buffer_alloc(sizeof(struct logical_if)); if (!lif) return -1; token->value.data = lif; lif->token = element->params[0].data.code->data; if (!strcmp(op, "=")) lif->op = IF_EQUALS; if (!strcmp(op, "!=")) lif->op = IF_NOTEQUALS; if (!strcmp(op, "<")) lif->op = IF_LESSTHAN; if (!strcmp(op, "<=")) lif->op = IF_LESSTHAN_EQ; if (!strcmp(op, ">")) lif->op = IF_GREATERTHAN; if (!strcmp(op, ">=")) lif->op = IF_GREATERTHAN_EQ; memcpy(&lif->operand, &element->params[2], sizeof(lif->operand)); if (element->params_count > 3) lif->num_options = element->params[3].data.number; else lif->num_options = TOKEN_VALUE_ONLY; return 0; }
static int parse_image_display(struct skin_element *element, struct wps_token *token, struct wps_data *wps_data) { char *label = element->params[0].data.text; char sublabel = '\0'; int subimage; struct gui_img *img; struct image_display *id = skin_buffer_alloc(sizeof(struct image_display)); if (element->params_count == 1 && strlen(label) <= 2) { /* backwards compatability. Allow %xd(Aa) to still work */ sublabel = label[1]; label[1] = '\0'; } /* sanity check */ img = find_image(label, wps_data); if (!img || !id) { return WPS_ERROR_INVALID_PARAM; } id->label = label; id->offset = 0; id->token = NULL; if (img->using_preloaded_icons) { token->type = SKIN_TOKEN_IMAGE_DISPLAY_LISTICON; } if (element->params_count > 1) { if (element->params[1].type == CODE) id->token = element->params[1].data.code->data; /* specify a number. 1 being the first subimage (i.e top) NOT 0 */ else if (element->params[1].type == INTEGER) id->subimage = element->params[1].data.number - 1; if (element->params_count > 2) id->offset = element->params[2].data.number; } else { if ((subimage = get_image_id(sublabel)) != -1) { if (subimage >= img->num_subimages) return WPS_ERROR_INVALID_PARAM; id->subimage = subimage; } else { id->subimage = 0; } } token->value.data = id; return 0; }
static bool load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char* bmpdir) { (void)wps_data; /* only needed for remote targets */ char img_path[MAX_PATH]; int fd; get_image_filename(bitmap->data, bmpdir, img_path, sizeof(img_path)); /* load the image */ int format; #ifdef HAVE_REMOTE_LCD if (curr_screen == SCREEN_REMOTE) format = FORMAT_ANY|FORMAT_REMOTE; else #endif format = FORMAT_ANY|FORMAT_TRANSPARENT; fd = open(img_path, O_RDONLY); if (fd < 0) { DEBUGF("Couldn't open %s\n", img_path); return false; } size_t buf_size = read_bmp_fd(fd, bitmap, 0, format|FORMAT_RETURN_SIZE, NULL); char* imgbuf = (char*)skin_buffer_alloc(buf_size); if (!imgbuf) { #ifndef APPLICATION DEBUGF("Not enough skin buffer: need %zd more.\n", buf_size - skin_buffer_freespace()); #endif close(fd); return NULL; } lseek(fd, 0, SEEK_SET); bitmap->data = imgbuf; int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL); close(fd); if (ret > 0) { return true; } else { /* Abort if we can't load an image */ DEBUGF("Couldn't load '%s'\n", img_path); return false; } }
/* Memory management */ static struct skin_element* skin_alloc_element() { struct skin_element* retval = (struct skin_element*) skin_buffer_alloc(sizeof(struct skin_element)); if (!retval) return NULL; retval->type = UNKNOWN; retval->next = skin_buffer_to_offset(NULL); retval->params = skin_buffer_to_offset(NULL); retval->tag = NULL; retval->params_count = 0; retval->children_count = 0; retval->data = INVALID_OFFSET; return retval; }
static int parse_playlistview(struct skin_element *element, struct wps_token *token, struct wps_data *wps_data) { (void)wps_data; struct playlistviewer *viewer = (struct playlistviewer *)skin_buffer_alloc(sizeof(struct playlistviewer)); if (!viewer) return WPS_ERROR_INVALID_PARAM; viewer->vp = &curr_vp->vp; viewer->show_icons = true; viewer->start_offset = element->params[0].data.number; viewer->line = element->params[1].data.code; token->value.data = (void*)viewer; return 0; }
bool skin_backdrops_preload(void) { bool retval = true; int i; char *filename; for (i=0; i<NB_BDROPS; i++) { if (backdrops[i].name[0] && !backdrops[i].buffer) { size_t buf_size; enum screen_type screen = backdrops[i].screen; #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) if (screen == SCREEN_REMOTE) buf_size = REMOTE_LCD_BACKDROP_BYTES; else #endif buf_size = LCD_BACKDROP_BYTES; filename = backdrops[i].name; if (screen == SCREEN_MAIN && global_settings.backdrop_file[0] && global_settings.backdrop_file[0] != '-' && filename[0] == '-') { char dir[MAX_PATH]; char* temp = filename+2; /* slightly hacky to get a buffer */ size_t size = sizeof(backdrops[i].name) - 2; snprintf(temp, size, "%s/%s.bmp", get_user_file_path(BACKDROP_DIR, 0, dir, sizeof(dir)), global_settings.backdrop_file); filename = temp; } if (*filename && *filename != '-') { backdrops[i].buffer = (char*)skin_buffer_alloc(buf_size); backdrops[i].loaded = backdrops[i].buffer && screens[screen].backdrop_load(filename, backdrops[i].buffer); if (!backdrops[i].loaded) retval = false; } if (backdrops[i].name[0] == '-' && backdrops[i].loaded) backdrops[i].name[2] = '.'; } } return retval; }
static int parse_viewportcolour(struct skin_element *element, struct wps_token *token, struct wps_data *wps_data) { (void)wps_data; struct skin_tag_parameter *param = element->params; struct viewport_colour *colour = (struct viewport_colour *)skin_buffer_alloc(sizeof(struct viewport_colour)); if (!colour) return -1; if (isdefault(param)) { colour->colour = get_viewport_default_colour(curr_screen, token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR); } else { if (!parse_color(curr_screen, param->data.text, &colour->colour)) return -1; } colour->vp = &curr_vp->vp; token->value.data = colour; if (element->line == curr_viewport_element->line) { if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR) { curr_vp->start_fgcolour = colour->colour; curr_vp->vp.fg_pattern = colour->colour; } else { curr_vp->start_bgcolour = colour->colour; curr_vp->vp.bg_pattern = colour->colour; } } return 0; }
/* load a font into the skin buffer. return the font id. */ int skin_font_load(char* font_name, int glyphs) { int i; int skin_font_size = 0; struct font *pf; struct skin_font_info *font = NULL; char filename[MAX_PATH]; if (!strcmp(font_name, global_settings.font_file)) return FONT_UI; #ifdef HAVE_REMOTE_LCD if (!strcmp(font_name, global_settings.remote_font_file)) return FONT_UI_REMOTE; #endif snprintf(filename, MAX_PATH, FONT_DIR "/%s.fnt", font_name); for(i=0;i<MAXUSERFONTS;i++) { if (font_table[i].font_id >= 0 && !strcmp(font_table[i].name, filename)) { font_table[i].ref_count++; return font_table[i].font_id; } else if (!font && font_table[i].font_id == -1) { font = &font_table[i]; strcpy(font_table[i].name, filename); } } if (!font) return -1; /* too many fonts loaded */ pf = &font->font; if (!font->buffer) { if (!glyphs) glyphs = GLYPHS_TO_CACHE; #ifndef __PCTOOL__ skin_font_size = font_glyphs_to_bufsize(filename, glyphs); #endif if ( !skin_font_size ) { skin_font_size = SKIN_FONT_SIZE; } pf->buffer_start = (char*)skin_buffer_alloc(skin_font_size); if (!pf->buffer_start) return -1; font->buffer = pf->buffer_start; pf->buffer_size = skin_font_size; } else { pf->buffer_start = font->buffer; } pf->fd = -1; font->font_id = font_load(pf, filename); if (font->font_id < 0) return -1; font->ref_count = 1; return font->font_id; }
static int parse_touchregion(struct skin_element *element, struct wps_token *token, struct wps_data *wps_data) { (void)token; unsigned i, imax; struct touchregion *region = NULL; const char *action; const char pb_string[] = "progressbar"; const char vol_string[] = "volume"; char temp[20]; /* format: %T(x,y,width,height,action) * if action starts with & the area must be held to happen * action is one of: * play - play/pause playback * stop - stop playback, exit the wps * prev - prev track * next - next track * ffwd - seek forward * rwd - seek backwards * menu - go back to the main menu * browse - go back to the file/db browser * shuffle - toggle shuffle mode * repmode - cycle the repeat mode * quickscreen - go into the quickscreen * contextmenu - open the context menu * playlist - go into the playlist * pitch - go into the pitchscreen * volup - increase volume by one step * voldown - decrease volume by one step */ region = (struct touchregion*)skin_buffer_alloc(sizeof(struct touchregion)); if (!region) return WPS_ERROR_INVALID_PARAM; /* should probably do some bounds checking here with the viewport... but later */ region->action = ACTION_NONE; region->x = element->params[0].data.number; region->y = element->params[1].data.number; region->width = element->params[2].data.number; region->height = element->params[3].data.number; region->wvp = curr_vp; region->armed = false; region->reverse_bar = false; region->extradata = NULL; action = element->params[4].data.text; strcpy(temp, action); action = temp; if (*action == '!') { region->reverse_bar = true; action++; } if(!strcmp(pb_string, action)) region->type = WPS_TOUCHREGION_SCROLLBAR; else if(!strcmp(vol_string, action)) region->type = WPS_TOUCHREGION_VOLUME; else { region->type = WPS_TOUCHREGION_ACTION; if (*action == '&') { action++; region->repeat = true; } else region->repeat = false; imax = ARRAYLEN(touchactions); for (i = 0; i < imax; i++) { /* try to match with one of our touchregion screens */ if (!strcmp(touchactions[i].s, action)) { region->action = touchactions[i].action; if (region->action == ACTION_SETTINGS_INC || region->action == ACTION_SETTINGS_DEC) { if (element->params_count < 6) { return WPS_ERROR_INVALID_PARAM; } else { char *name = element->params[5].data.text; int j; /* Find the setting */ for (j=0; j<nb_settings; j++) if (settings[j].cfg_name && !strcmp(settings[j].cfg_name, name)) break; if (j==nb_settings) return WPS_ERROR_INVALID_PARAM; region->extradata = (void*)&settings[j]; } } break; } } if (region->action == ACTION_NONE) return WPS_ERROR_INVALID_PARAM; } struct skin_token_list *item = new_skin_token_list_item(NULL, region); if (!item) return WPS_ERROR_INVALID_PARAM; add_to_ll_chain(&wps_data->touchregions, item); return 0; }
static int parse_albumart_load(struct skin_element* element, struct wps_token *token, struct wps_data *wps_data) { struct dim dimensions; int albumart_slot; bool swap_for_rtl = lang_is_rtl() && follow_lang_direction; struct skin_albumart *aa = (struct skin_albumart *)skin_buffer_alloc(sizeof(struct skin_albumart)); (void)token; /* silence warning */ if (!aa) return -1; /* reset albumart info in wps */ aa->width = -1; aa->height = -1; aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */ aa->x = element->params[0].data.number; aa->y = element->params[1].data.number; aa->width = element->params[2].data.number; aa->height = element->params[3].data.number; aa->vp = &curr_vp->vp; aa->draw_handle = -1; /* if we got here, we parsed everything ok .. ! */ if (aa->width < 0) aa->width = 0; else if (aa->width > LCD_WIDTH) aa->width = LCD_WIDTH; if (aa->height < 0) aa->height = 0; else if (aa->height > LCD_HEIGHT) aa->height = LCD_HEIGHT; if (swap_for_rtl) aa->x = LCD_WIDTH - (aa->x + aa->width); aa->state = WPS_ALBUMART_LOAD; wps_data->albumart = aa; dimensions.width = aa->width; dimensions.height = aa->height; albumart_slot = playback_claim_aa_slot(&dimensions); if (0 <= albumart_slot) wps_data->playback_aa_slot = albumart_slot; if (element->params_count > 4 && !isdefault(&element->params[4])) { switch (*element->params[4].data.text) { case 'l': case 'L': if (swap_for_rtl) aa->xalign = WPS_ALBUMART_ALIGN_RIGHT; else aa->xalign = WPS_ALBUMART_ALIGN_LEFT; break; case 'c': case 'C': aa->xalign = WPS_ALBUMART_ALIGN_CENTER; break; case 'r': case 'R': if (swap_for_rtl) aa->xalign = WPS_ALBUMART_ALIGN_LEFT; else aa->xalign = WPS_ALBUMART_ALIGN_RIGHT; break; } } if (element->params_count > 5 && !isdefault(&element->params[5])) { switch (*element->params[5].data.text) { case 't': case 'T': aa->yalign = WPS_ALBUMART_ALIGN_TOP; break; case 'c': case 'C': aa->yalign = WPS_ALBUMART_ALIGN_CENTER; break; case 'b': case 'B': aa->yalign = WPS_ALBUMART_ALIGN_BOTTOM; break; } } return 0; }
/* finally, assign the font_id to the viewport */ vp->font = font->id; } return success; } #endif /* HAVE_LCD_BITMAP */ static int convert_viewport(struct wps_data *data, struct skin_element* element) { struct skin_viewport *skin_vp = (struct skin_viewport *)skin_buffer_alloc(sizeof(struct skin_viewport)); struct screen *display = &screens[curr_screen]; if (!skin_vp) return CALLBACK_ERROR; skin_vp->hidden_flags = 0; skin_vp->label = NULL; skin_vp->is_infovp = false; element->data = skin_vp; curr_vp = skin_vp; curr_viewport_element = element; viewport_set_defaults(&skin_vp->vp, curr_screen); #ifdef HAVE_REMOTE_LCD /* viewport_set_defaults() sets the font to FONT_UI+curr_screen. * This parser requires font 1 to always be the UI font, * so force it back to FONT_UI and handle the screen number at the end */ skin_vp->vp.font = FONT_UI; #endif #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) skin_vp->start_fgcolour = skin_vp->vp.fg_pattern; skin_vp->start_bgcolour = skin_vp->vp.bg_pattern; #endif struct skin_tag_parameter *param = element->params; if (element->params_count == 0) /* default viewport */ { if (!data->tree) /* first viewport in the skin */ data->tree = element; skin_vp->label = VP_DEFAULT_LABEL; return CALLBACK_OK; } if (element->params_count == 6) { if (element->tag->type == SKIN_TOKEN_UIVIEWPORT_LOAD) { skin_vp->is_infovp = true; if (isdefault(param)) { skin_vp->hidden_flags = VP_NEVER_VISIBLE; skin_vp->label = VP_DEFAULT_LABEL; } else { skin_vp->hidden_flags = VP_NEVER_VISIBLE; skin_vp->label = param->data.text; } } else { skin_vp->hidden_flags = VP_DRAW_HIDEABLE|VP_DRAW_HIDDEN; skin_vp->label = param->data.text; } param++; } /* x */ if (!isdefault(param)) { skin_vp->vp.x = param->data.number; if (param->data.number < 0) skin_vp->vp.x += display->lcdwidth; } param++; /* y */ if (!isdefault(param)) { skin_vp->vp.y = param->data.number; if (param->data.number < 0) skin_vp->vp.y += display->lcdheight; } param++; /* width */ if (!isdefault(param)) { skin_vp->vp.width = param->data.number; if (param->data.number < 0) skin_vp->vp.width = (skin_vp->vp.width + display->lcdwidth) - skin_vp->vp.x; } else { skin_vp->vp.width = display->lcdwidth - skin_vp->vp.x; } param++; /* height */ if (!isdefault(param)) { skin_vp->vp.height = param->data.number; if (param->data.number < 0) skin_vp->vp.height = (skin_vp->vp.height + display->lcdheight) - skin_vp->vp.y; } else { skin_vp->vp.height = display->lcdheight - skin_vp->vp.y; } param++; #ifdef HAVE_LCD_BITMAP /* font */ if (!isdefault(param)) { skin_vp->vp.font = param->data.number; } #endif if ((unsigned) skin_vp->vp.x >= (unsigned) display->lcdwidth || skin_vp->vp.width + skin_vp->vp.x > display->lcdwidth || (unsigned) skin_vp->vp.y >= (unsigned) display->lcdheight || skin_vp->vp.height + skin_vp->vp.y > display->lcdheight) return CALLBACK_ERROR; return CALLBACK_OK; }
static int parse_image_load(struct skin_element *element, struct wps_token *token, struct wps_data *wps_data) { const char* filename; const char* id; int x,y; struct gui_img *img; /* format: %x(n,filename.bmp,x,y) or %xl(n,filename.bmp,x,y) or %xl(n,filename.bmp,x,y,num_subimages) */ id = element->params[0].data.text; filename = element->params[1].data.text; x = element->params[2].data.number; y = element->params[3].data.number; /* check the image number and load state */ if(find_image(id, wps_data)) { /* Invalid image ID */ return WPS_ERROR_INVALID_PARAM; } img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img)); if (!img) return WPS_ERROR_INVALID_PARAM; /* save a pointer to the filename */ img->bm.data = (char*)filename; img->label = id; img->x = x; img->y = y; img->num_subimages = 1; img->always_display = false; img->display = -1; img->using_preloaded_icons = false; /* save current viewport */ img->vp = &curr_vp->vp; if (token->type == SKIN_TOKEN_IMAGE_DISPLAY) { img->always_display = true; } else if (element->params_count == 5) { img->num_subimages = element->params[4].data.number; if (img->num_subimages <= 0) return WPS_ERROR_INVALID_PARAM; } if (!strcmp(img->bm.data, "__list_icons__")) { img->num_subimages = Icon_Last_Themeable; img->using_preloaded_icons = true; } struct skin_token_list *item = (struct skin_token_list *)new_skin_token_list_item(NULL, img); if (!item) return WPS_ERROR_INVALID_PARAM; add_to_ll_chain(&wps_data->images, item); return 0; }
static int skin_element_callback(struct skin_element* element, void* data) { struct wps_data *wps_data = (struct wps_data *)data; struct wps_token *token; parse_function function = NULL; switch (element->type) { /* IMPORTANT: element params are shared, so copy them if needed * or use then NOW, dont presume they have a long lifespan */ case TAG: { token = (struct wps_token*)skin_buffer_alloc(sizeof(struct wps_token)); memset(token, 0, sizeof(*token)); token->type = element->tag->type; if (element->tag->flags&SKIN_RTC_REFRESH) { #if CONFIG_RTC curr_line->update_mode |= SKIN_REFRESH_DYNAMIC; #else curr_line->update_mode |= SKIN_REFRESH_STATIC; #endif } else curr_line->update_mode |= element->tag->flags&SKIN_REFRESH_ALL; element->data = token; /* Some tags need special handling for the tag, so add them here */ switch (token->type) { case SKIN_TOKEN_ALIGN_LANGDIRECTION: follow_lang_direction = 2; break; case SKIN_TOKEN_LOGICAL_IF: function = parse_logical_if; break; case SKIN_TOKEN_PROGRESSBAR: case SKIN_TOKEN_VOLUME: case SKIN_TOKEN_BATTERY_PERCENT: case SKIN_TOKEN_PLAYER_PROGRESSBAR: #ifdef HAVE_RADIO_RSSI case SKIN_TOKEN_TUNER_RSSI: #endif function = parse_progressbar_tag; break; case SKIN_TOKEN_SUBLINE_TIMEOUT: case SKIN_TOKEN_BUTTON_VOLUME: case SKIN_TOKEN_TRACK_STARTING: case SKIN_TOKEN_TRACK_ENDING: case SKIN_TOKEN_LASTTOUCH: function = parse_timeout_tag; break; #ifdef HAVE_LCD_BITMAP case SKIN_TOKEN_DISABLE_THEME: case SKIN_TOKEN_ENABLE_THEME: case SKIN_TOKEN_DRAW_INBUILTBAR: function = parse_statusbar_tags; break; case SKIN_TOKEN_LIST_TITLE_TEXT: #ifndef __PCTOOL__ sb_skin_has_title(curr_screen); #endif break; #endif case SKIN_TOKEN_FILE_DIRECTORY: token->value.i = element->params[0].data.number; break; #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) case SKIN_TOKEN_VIEWPORT_FGCOLOUR: case SKIN_TOKEN_VIEWPORT_BGCOLOUR: function = parse_viewportcolour; break; case SKIN_TOKEN_IMAGE_BACKDROP: function = parse_image_special; break; #endif case SKIN_TOKEN_TRANSLATEDSTRING: case SKIN_TOKEN_SETTING: function = parse_setting_and_lang; break; #ifdef HAVE_LCD_BITMAP case SKIN_TOKEN_VIEWPORT_CUSTOMLIST: function = parse_playlistview; break; case SKIN_TOKEN_LOAD_FONT: function = parse_font_load; break; case SKIN_TOKEN_VIEWPORT_ENABLE: case SKIN_TOKEN_UIVIEWPORT_ENABLE: token->value.data = element->params[0].data.text; break; case SKIN_TOKEN_IMAGE_PRELOAD_DISPLAY: function = parse_image_display; break; case SKIN_TOKEN_IMAGE_PRELOAD: case SKIN_TOKEN_IMAGE_DISPLAY: function = parse_image_load; break; #endif #ifdef HAVE_TOUCHSCREEN case SKIN_TOKEN_TOUCHREGION: function = parse_touchregion; break; #endif #ifdef HAVE_ALBUMART case SKIN_TOKEN_ALBUMART_DISPLAY: if (wps_data->albumart) wps_data->albumart->vp = &curr_vp->vp; break; case SKIN_TOKEN_ALBUMART_LOAD: function = parse_albumart_load; break; #endif default: break; } if (function) { if (function(element, token, wps_data) < 0) return CALLBACK_ERROR; } /* tags that start with 'F', 'I' or 'D' are for the next file */ if ( *(element->tag->name) == 'I' || *(element->tag->name) == 'F' || *(element->tag->name) == 'D') token->next = true; if (follow_lang_direction > 0 ) follow_lang_direction--; break; } case VIEWPORT: return convert_viewport(wps_data, element); case LINE: { struct line *line = (struct line *)skin_buffer_alloc(sizeof(struct line)); line->update_mode = SKIN_REFRESH_STATIC; curr_line = line; element->data = line; } break; case LINE_ALTERNATOR: { struct line_alternator *alternator = (struct line_alternator *)skin_buffer_alloc(sizeof(struct line_alternator)); alternator->current_line = 0; #ifndef __PCTOOL__ alternator->next_change_tick = current_tick; #endif element->data = alternator; } break; case CONDITIONAL: { struct conditional *conditional = (struct conditional *)skin_buffer_alloc(sizeof(struct conditional)); conditional->last_value = -1; conditional->token = element->data; element->data = conditional; if (!check_feature_tag(element->tag->type)) { return FEATURE_NOT_AVAILABLE; } return CALLBACK_OK; } case TEXT: curr_line->update_mode |= SKIN_REFRESH_STATIC; break; default: break; } return CALLBACK_OK; }
/* On a ROCKBOX build we try to save space as much as possible * so if we can, use a shared param pool which should be more then large * enough for any tag. params should be used straight away by the callback * so this is safe. */ static struct skin_tag_parameter* skin_alloc_params(int count) { size_t size = sizeof(struct skin_tag_parameter) * count; return (struct skin_tag_parameter*)skin_buffer_alloc(size); }
char* skin_alloc_string(int length) { return (char*)skin_buffer_alloc(sizeof(char) * (length + 1)); }
static int parse_progressbar_tag(struct skin_element* element, struct wps_token *token, struct wps_data *wps_data) { #ifdef HAVE_LCD_BITMAP struct progressbar *pb; struct viewport *vp = &curr_vp->vp; struct skin_tag_parameter *param = element->params; int curr_param = 0; char *image_filename = NULL; if (element->params_count == 0 && element->tag->type != SKIN_TOKEN_PROGRESSBAR) return 0; /* nothing to do */ pb = (struct progressbar*)skin_buffer_alloc(sizeof(struct progressbar)); token->value.data = pb; if (!pb) return WPS_ERROR_INVALID_PARAM; pb->vp = vp; pb->follow_lang_direction = follow_lang_direction > 0; pb->nofill = false; pb->nobar = false; pb->image = NULL; pb->slider = NULL; pb->invert_fill_direction = false; pb->horizontal = true; if (element->params_count == 0) { pb->x = 0; pb->width = vp->width; pb->height = SYSFONT_HEIGHT-2; pb->y = -1; /* Will be computed during the rendering */ pb->type = element->tag->type; return 0; } /* (x, y, width, height, ...) */ if (!isdefault(param)) pb->x = param->data.number; else pb->x = 0; param++; if (!isdefault(param)) pb->y = param->data.number; else pb->y = -1; /* computed at rendering */ param++; if (!isdefault(param)) pb->width = param->data.number; else pb->width = vp->width - pb->x; param++; if (!isdefault(param)) { /* A zero height makes no sense - reject it */ if (param->data.number == 0) return WPS_ERROR_INVALID_PARAM; pb->height = param->data.number; } else { if (vp->font > FONT_UI) pb->height = -1; /* calculate at display time */ else { #ifndef __PCTOOL__ pb->height = font_get(vp->font)->height; #else pb->height = 8; #endif } } /* optional params, first is the image filename if it isnt recognised as a keyword */ curr_param = 4; if (isdefault(&element->params[curr_param])) { param++; curr_param++; } pb->horizontal = pb->width > pb->height; while (curr_param < element->params_count) { param++; if (!strcmp(param->data.text, "invert")) pb->invert_fill_direction = true; else if (!strcmp(param->data.text, "nofill")) pb->nofill = true; else if (!strcmp(param->data.text, "nobar")) pb->nobar = true; else if (!strcmp(param->data.text, "slider")) { if (curr_param+1 < element->params_count) { curr_param++; param++; pb->slider = find_image(param->data.text, wps_data); } else /* option needs the next param */ return -1; } else if (!strcmp(param->data.text, "image")) { if (curr_param+1 < element->params_count) { curr_param++; param++; image_filename = param->data.text; } else /* option needs the next param */ return -1; } else if (!strcmp(param->data.text, "vertical")) { pb->horizontal = false; if (isdefault(&element->params[3])) pb->height = vp->height - pb->y; } else if (!strcmp(param->data.text, "horizontal")) pb->horizontal = true; else if (curr_param == 4) image_filename = param->data.text; curr_param++; } if (image_filename) { pb->image = find_image(image_filename, wps_data); if (!pb->image) /* load later */ { struct gui_img* img = (struct gui_img*)skin_buffer_alloc(sizeof(struct gui_img)); if (!img) return WPS_ERROR_INVALID_PARAM; /* save a pointer to the filename */ img->bm.data = (char*)image_filename; img->label = image_filename; img->x = 0; img->y = 0; img->num_subimages = 1; img->always_display = false; img->display = -1; img->using_preloaded_icons = false; img->vp = &curr_vp->vp; struct skin_token_list *item = (struct skin_token_list *)new_skin_token_list_item(NULL, img); if (!item) return WPS_ERROR_INVALID_PARAM; add_to_ll_chain(&wps_data->images, item); pb->image = img; } } if (token->type == SKIN_TOKEN_VOLUME) token->type = SKIN_TOKEN_VOLUMEBAR; else if (token->type == SKIN_TOKEN_BATTERY_PERCENT) token->type = SKIN_TOKEN_BATTERY_PERCENTBAR; else if (token->type == SKIN_TOKEN_TUNER_RSSI) token->type = SKIN_TOKEN_TUNER_RSSI_BAR; pb->type = token->type; return 0; #else (void)element; if (token->type == SKIN_TOKEN_PROGRESSBAR || token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR) { wps_data->full_line_progressbar = token->type == SKIN_TOKEN_PLAYER_PROGRESSBAR; } return 0; #endif }