skin tags: fix the id3 track/disc numbers in conditionals
[maemo-rb.git] / apps / gui / skin_engine / skin_tokens.c
blob33ffc53a9ca583c67dca791f984d10a9856bcf5d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002-2007 Björn Stenberg
11 * Copyright (C) 2007-2008 Nicolas Pennequin
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include "font.h"
23 #include <stdio.h>
24 #include "string-extra.h"
25 #include <stdlib.h>
26 #include "action.h"
27 #include "system.h"
28 #include "settings.h"
29 #include "settings_list.h"
30 #include "rbunicode.h"
31 #include "timefuncs.h"
32 #include "status.h"
33 #include "power.h"
34 #include "powermgmt.h"
35 #include "sound.h"
36 #include "debug.h"
37 #include "cuesheet.h"
38 #include "replaygain.h"
39 #include "core_alloc.h"
40 #ifdef HAVE_LCD_CHARCELLS
41 #include "hwcompat.h"
42 #endif
43 #include "abrepeat.h"
44 #include "lang.h"
45 #include "misc.h"
46 #include "led.h"
47 #ifdef HAVE_LCD_BITMAP
48 #include "peakmeter.h"
49 /* Image stuff */
50 #include "albumart.h"
51 #endif
52 #include "playlist.h"
53 #if CONFIG_CODEC == SWCODEC
54 #include "playback.h"
55 #include "tdspeed.h"
56 #endif
57 #include "viewport.h"
58 #include "tagcache.h"
60 #include "wps_internals.h"
61 #include "skin_engine.h"
62 #include "statusbar-skinned.h"
63 #include "root_menu.h"
64 #ifdef HAVE_RECORDING
65 #include "recording.h"
66 #include "pcm_record.h"
67 #endif
68 #include "language.h"
69 #include "usb.h"
70 #if CONFIG_TUNER
71 #include "radio.h"
72 #include "tuner.h"
73 #endif
74 #include "list.h"
76 #define NOINLINE __attribute__ ((noinline))
78 extern struct wps_state wps_state;
80 static const char* get_codectype(const struct mp3entry* id3)
82 if (id3 && id3->codectype < AFMT_NUM_CODECS) {
83 return audio_formats[id3->codectype].label;
84 } else {
85 return NULL;
89 /* Extract a part from a path.
91 * buf - buffer extract part to.
92 * buf_size - size of buffer.
93 * path - path to extract from.
94 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
95 * parent of parent, etc.
97 * Returns buf if the desired level was found, NULL otherwise.
99 char* get_dir(char* buf, int buf_size, const char* path, int level)
101 const char* sep;
102 const char* last_sep;
103 int len;
105 sep = path + strlen(path);
106 last_sep = sep;
108 while (sep > path)
110 if ('/' == *(--sep))
112 if (!level)
113 break;
115 level--;
116 last_sep = sep - 1;
120 if (level || (last_sep <= sep))
121 return NULL;
123 len = MIN(last_sep - sep, buf_size - 1);
124 strlcpy(buf, sep + 1, len + 1);
125 return buf;
128 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHCONTROL)
129 /* A helper to determine the enum value for pitch/speed.
131 When there are two choices (i.e. boolean), return 1 if the value is
132 different from normal value and 2 if the value is the same as the
133 normal value. E.g. "%?Sp<%Sp>" would show the pitch only when
134 playing at a modified pitch.
136 When there are more than two choices (i.e. enum), the left half of
137 the choices are to show 0..normal range, and the right half of the
138 choices are to show values over that. The last entry is used when
139 it is set to the normal setting, following the rockbox convention
140 to use the last entry for special values.
142 E.g.
144 2 items: %?Sp<0..99 or 101..infinity|100>
145 3 items: %?Sp<0..99|101..infinity|100>
146 4 items: %?Sp<0..49|50..99|101..infinity|100>
147 5 items: %?Sp<0..49|50..99|101..149|150..infinity|100>
148 6 items: %?Sp<0..33|34..66|67..99|101..133|134..infinity|100>
149 7 items: %?Sp<0..33|34..66|67..99|101..133|134..167|167..infinity|100>
151 static int pitch_speed_enum(int range, int32_t val, int32_t normval)
153 int center;
154 int n;
156 if (range < 3)
157 return (val == normval) + 1;
158 if (val == normval)
159 return range;
160 center = range / 2;
161 n = (center * val) / normval + 1;
162 return (range <= n) ? (range - 1) : n;
164 #endif
166 const char *get_cuesheetid3_token(struct wps_token *token, struct mp3entry *id3,
167 int offset_tracks, char *buf, int buf_size)
169 struct cuesheet *cue = id3?id3->cuesheet:NULL;
170 if (!cue || !cue->curr_track)
171 return NULL;
173 struct cue_track_info *track = cue->curr_track;
174 if (offset_tracks)
176 if (cue->curr_track_idx+offset_tracks < cue->track_count)
177 track+=offset_tracks;
178 else
179 return NULL;
181 switch (token->type)
183 case SKIN_TOKEN_METADATA_ARTIST:
184 return *track->performer ? track->performer : NULL;
185 case SKIN_TOKEN_METADATA_COMPOSER:
186 return *track->songwriter ? track->songwriter : NULL;
187 case SKIN_TOKEN_METADATA_ALBUM:
188 return *cue->title ? cue->title : NULL;
189 case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
190 return *cue->performer ? cue->performer : NULL;
191 case SKIN_TOKEN_METADATA_TRACK_TITLE:
192 return *track->title ? track->title : NULL;
193 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
194 snprintf(buf, buf_size, "%d/%d",
195 cue->curr_track_idx+offset_tracks+1, cue->track_count);
196 return buf;
197 default:
198 return NULL;
200 return NULL;
203 static const char* get_filename_token(struct wps_token *token, char* filename,
204 char *buf, int buf_size)
206 if (filename)
208 switch (token->type)
210 case SKIN_TOKEN_FILE_PATH:
211 return filename;
212 case SKIN_TOKEN_FILE_NAME:
213 if (get_dir(buf, buf_size, filename, 0)) {
214 /* Remove extension */
215 char* sep = strrchr(buf, '.');
216 if (NULL != sep) {
217 *sep = 0;
219 return buf;
221 return NULL;
222 case SKIN_TOKEN_FILE_NAME_WITH_EXTENSION:
223 return get_dir(buf, buf_size, filename, 0);
224 case SKIN_TOKEN_FILE_DIRECTORY:
225 return get_dir(buf, buf_size, filename, token->value.i);
226 default:
227 return NULL;
230 return NULL;
233 /* All tokens which only need the info to return a value go in here */
234 const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
235 char *filename, char *buf, int buf_size, int limit, int *intval)
237 struct wps_state *state = &wps_state;
238 if (id3)
240 unsigned long length = id3->length;
241 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
242 switch (token->type)
244 case SKIN_TOKEN_METADATA_ARTIST:
245 return id3->artist;
246 case SKIN_TOKEN_METADATA_COMPOSER:
247 return id3->composer;
248 case SKIN_TOKEN_METADATA_ALBUM:
249 return id3->album;
250 case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
251 return id3->albumartist;
252 case SKIN_TOKEN_METADATA_GROUPING:
253 return id3->grouping;
254 case SKIN_TOKEN_METADATA_GENRE:
255 return id3->genre_string;
256 case SKIN_TOKEN_METADATA_DISC_NUMBER:
257 if (id3->disc_string) {
258 if (intval)
259 *intval = atoi(id3->disc_string);
260 return id3->disc_string;
262 if (id3->discnum) {
263 if (intval)
264 *intval = id3->discnum;
265 snprintf(buf, buf_size, "%d", id3->discnum);
266 return buf;
268 return NULL;
269 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
270 if (id3->track_string) {
271 if (intval)
272 *intval = atoi(id3->track_string);
273 return id3->track_string;
275 if (id3->tracknum) {
276 if (intval)
277 *intval = id3->tracknum;
278 snprintf(buf, buf_size, "%d", id3->tracknum);
279 return buf;
281 return NULL;
282 case SKIN_TOKEN_METADATA_TRACK_TITLE:
283 return id3->title;
284 case SKIN_TOKEN_METADATA_VERSION:
285 switch (id3->id3version)
287 case ID3_VER_1_0:
288 return "1";
289 case ID3_VER_1_1:
290 return "1.1";
291 case ID3_VER_2_2:
292 return "2.2";
293 case ID3_VER_2_3:
294 return "2.3";
295 case ID3_VER_2_4:
296 return "2.4";
297 default:
298 break;
300 return NULL;
301 case SKIN_TOKEN_METADATA_YEAR:
302 if( id3->year_string )
303 return id3->year_string;
304 if (id3->year) {
305 snprintf(buf, buf_size, "%d", id3->year);
306 return buf;
308 return NULL;
309 case SKIN_TOKEN_METADATA_COMMENT:
310 return id3->comment;
311 case SKIN_TOKEN_FILE_BITRATE:
312 if(id3->bitrate)
313 snprintf(buf, buf_size, "%d", id3->bitrate);
314 else
315 return "?";
316 return buf;
317 case SKIN_TOKEN_TRACK_TIME_ELAPSED:
318 if (intval && limit == TOKEN_VALUE_ONLY)
319 *intval = elapsed/1000;
320 format_time(buf, buf_size, elapsed);
321 return buf;
323 case SKIN_TOKEN_TRACK_TIME_REMAINING:
324 if (intval && limit == TOKEN_VALUE_ONLY)
325 *intval = (length - elapsed)/1000;
326 format_time(buf, buf_size, length - elapsed);
327 return buf;
329 case SKIN_TOKEN_TRACK_LENGTH:
330 if (intval && limit == TOKEN_VALUE_ONLY)
331 *intval = length/1000;
332 format_time(buf, buf_size, length);
333 return buf;
335 case SKIN_TOKEN_TRACK_ELAPSED_PERCENT:
336 if (length <= 0)
337 return NULL;
339 if (intval)
341 if (limit == TOKEN_VALUE_ONLY)
342 limit = 100; /* make it a percentage */
343 *intval = limit * elapsed / length + 1;
345 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
346 return buf;
348 case SKIN_TOKEN_TRACK_STARTING:
350 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
351 if (elapsed < time)
352 return "starting";
354 return NULL;
355 case SKIN_TOKEN_TRACK_ENDING:
357 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
358 if (length - elapsed < time)
359 return "ending";
361 return NULL;
363 case SKIN_TOKEN_FILE_CODEC:
364 if (intval)
366 if(id3->codectype == AFMT_UNKNOWN)
367 *intval = AFMT_NUM_CODECS;
368 else
369 *intval = id3->codectype;
371 return get_codectype(id3);
373 case SKIN_TOKEN_FILE_FREQUENCY:
374 snprintf(buf, buf_size, "%ld", id3->frequency);
375 return buf;
376 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
377 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
378 if ((id3->frequency % 1000) < 100)
379 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
380 else
381 snprintf(buf, buf_size, "%ld.%lu",
382 id3->frequency / 1000,
383 (id3->frequency % 1000) / 100);
384 return buf;
385 case SKIN_TOKEN_FILE_VBR:
386 return (id3->vbr) ? "(avg)" : NULL;
387 case SKIN_TOKEN_FILE_SIZE:
388 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
389 return buf;
391 #ifdef HAVE_TAGCACHE
392 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
393 if (intval)
394 *intval = id3->playcount + 1;
395 snprintf(buf, buf_size, "%ld", id3->playcount);
396 return buf;
397 case SKIN_TOKEN_DATABASE_RATING:
398 if (intval)
399 *intval = id3->rating + 1;
400 snprintf(buf, buf_size, "%d", id3->rating);
401 return buf;
402 case SKIN_TOKEN_DATABASE_AUTOSCORE:
403 if (intval)
404 *intval = id3->score + 1;
405 snprintf(buf, buf_size, "%d", id3->score);
406 return buf;
407 #endif
409 default:
410 return get_filename_token(token, id3->path, buf, buf_size);
413 else /* id3 == NULL, handle the error based on the expected return type */
415 switch (token->type)
417 /* Most tokens expect NULL on error so leave that for the default case,
418 * The ones that expect "0" need to be handled */
419 case SKIN_TOKEN_FILE_FREQUENCY:
420 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
421 case SKIN_TOKEN_FILE_SIZE:
422 #ifdef HAVE_TAGCACHE
423 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
424 case SKIN_TOKEN_DATABASE_RATING:
425 case SKIN_TOKEN_DATABASE_AUTOSCORE:
426 #endif
427 if (intval)
428 *intval = 0;
429 return "0";
430 default:
431 return get_filename_token(token, filename, buf, buf_size);
434 return buf;
437 #if CONFIG_TUNER
439 /* Formats the frequency (specified in Hz) in MHz, */
440 /* with one or two digits after the decimal point -- */
441 /* depending on the frequency changing step. */
442 /* Returns buf */
443 static char *format_freq_MHz(int freq, int freq_step, char *buf, int buf_size)
445 int scale, div;
446 char *fmt;
447 if (freq_step < 100000)
449 /* Format with two digits after decimal point */
450 scale = 10000;
451 fmt = "%d.%02d";
453 else
455 /* Format with one digit after decimal point */
456 scale = 100000;
457 fmt = "%d.%d";
459 div = 1000000 / scale;
460 freq = freq / scale;
461 snprintf(buf, buf_size, fmt, freq/div, freq%div);
462 return buf;
466 /* Tokens which are really only used by the radio screen go in here */
467 const char *get_radio_token(struct wps_token *token, int preset_offset,
468 char *buf, int buf_size, int limit, int *intval)
470 const struct fm_region_data *region_data =
471 &(fm_region_data[global_settings.fm_region]);
472 (void)limit;
473 switch (token->type)
475 /* Radio/tuner tokens */
476 case SKIN_TOKEN_TUNER_TUNED:
477 if (tuner_get(RADIO_TUNED))
478 return "t";
479 return NULL;
480 case SKIN_TOKEN_TUNER_SCANMODE:
481 if (radio_scan_mode())
482 return "s";
483 return NULL;
484 case SKIN_TOKEN_TUNER_STEREO:
485 if (radio_is_stereo())
486 return "s";
487 return NULL;
488 case SKIN_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
489 return format_freq_MHz(region_data->freq_min,
490 region_data->freq_step, buf, buf_size);
491 case SKIN_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
492 return format_freq_MHz(region_data->freq_max,
493 region_data->freq_step, buf, buf_size);
494 case SKIN_TOKEN_TUNER_CURFREQ:
495 return format_freq_MHz(radio_current_frequency(),
496 region_data->freq_step, buf, buf_size);
497 #ifdef HAVE_RADIO_RSSI
498 case SKIN_TOKEN_TUNER_RSSI:
499 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI));
500 if (intval)
502 int val = tuner_get(RADIO_RSSI);
503 int min = tuner_get(RADIO_RSSI_MIN);
504 int max = tuner_get(RADIO_RSSI_MAX);
505 if (limit == TOKEN_VALUE_ONLY)
507 *intval = val;
509 else
511 *intval = 1+(limit-1)*(val-min)/(max-1-min);
514 return buf;
515 case SKIN_TOKEN_TUNER_RSSI_MIN:
516 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MIN));
517 return buf;
518 case SKIN_TOKEN_TUNER_RSSI_MAX:
519 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MAX));
520 return buf;
521 #endif
522 case SKIN_TOKEN_PRESET_NAME:
523 case SKIN_TOKEN_PRESET_FREQ:
524 case SKIN_TOKEN_PRESET_ID:
526 int preset_count = radio_preset_count();
527 int cur_preset = radio_current_preset();
528 if (preset_count == 0 || cur_preset < 0)
529 return NULL;
530 int preset = cur_preset + preset_offset;
531 /* make sure it's in the valid range */
532 preset %= preset_count;
533 if (preset < 0)
534 preset += preset_count;
535 if (token->type == SKIN_TOKEN_PRESET_NAME)
536 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
537 else if (token->type == SKIN_TOKEN_PRESET_FREQ)
538 format_freq_MHz(radio_get_preset(preset)->frequency,
539 region_data->freq_step, buf, buf_size);
540 else
541 snprintf(buf, buf_size, "%d", preset + 1);
542 return buf;
544 case SKIN_TOKEN_PRESET_COUNT:
545 snprintf(buf, buf_size, "%d", radio_preset_count());
546 if (intval)
547 *intval = radio_preset_count();
548 return buf;
549 case SKIN_TOKEN_HAVE_RDS:
550 #ifdef HAVE_RDS_CAP
551 return "rds";
552 case SKIN_TOKEN_RDS_NAME:
553 return tuner_get_rds_info(RADIO_RDS_NAME);
554 case SKIN_TOKEN_RDS_TEXT:
555 return tuner_get_rds_info(RADIO_RDS_TEXT);
556 #else
557 return NULL; /* end of the SKIN_TOKEN_HAVE_RDS case */
558 #endif /* HAVE_RDS_CAP */
559 default:
560 return NULL;
562 return NULL;
564 #endif
566 static struct mp3entry* get_mp3entry_from_offset(int offset, char **filename)
568 struct mp3entry* pid3 = NULL;
569 struct wps_state *state = skin_get_global_state();
570 struct cuesheet *cue = state->id3 ? state->id3->cuesheet : NULL;
571 const char *fname = NULL;
572 if (cue && cue->curr_track_idx + offset < cue->track_count)
573 pid3 = state->id3;
574 else if (offset == 0)
575 pid3 = state->id3;
576 else if (offset == 1)
577 pid3 = state->nid3;
578 else
580 static char filename_buf[MAX_PATH + 1];
581 fname = playlist_peek(offset, filename_buf, sizeof(filename_buf));
582 *filename = (char*)fname;
583 #if CONFIG_CODEC == SWCODEC
584 static struct mp3entry tempid3;
585 if (
586 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
587 tagcache_fill_tags(&tempid3, fname) ||
588 #endif
589 audio_peek_track(&tempid3, offset)
592 pid3 = &tempid3;
594 #endif
596 return pid3;
599 #ifdef HAVE_LCD_CHARCELLS
600 static void format_player_progress(struct gui_wps *gwps)
602 struct wps_state *state = skin_get_global_state();
603 struct screen *display = gwps->display;
604 unsigned char progress_pattern[7];
605 int pos = 0;
606 int i;
608 int elapsed, length;
609 if (LIKELY(state->id3))
611 elapsed = state->id3->elapsed;
612 length = state->id3->length;
614 else
616 elapsed = 0;
617 length = 0;
620 if (length)
621 pos = 36 * (elapsed + state->ff_rewind_count) / length;
623 for (i = 0; i < 7; i++, pos -= 5)
625 if (pos <= 0)
626 progress_pattern[i] = 0x1fu;
627 else if (pos >= 5)
628 progress_pattern[i] = 0x00u;
629 else
630 progress_pattern[i] = 0x1fu >> pos;
633 display->define_pattern(gwps->data->wps_progress_pat[0], progress_pattern);
636 static void format_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
638 static const unsigned char numbers[10][4] = {
639 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
640 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
641 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
642 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
643 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
644 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
645 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
646 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
647 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
648 {0x0e, 0x0e, 0x02, 0x0e} /* 9 */
651 struct wps_state *state = skin_get_global_state();
652 struct screen *display = gwps->display;
653 struct wps_data *data = gwps->data;
654 unsigned char progress_pattern[7];
655 char timestr[10];
656 int time;
657 int time_idx = 0;
658 int pos = 0;
659 int pat_idx = 1;
660 int digit, i, j;
661 bool softchar;
663 int elapsed, length;
664 if (LIKELY(state->id3))
666 elapsed = state->id3->elapsed;
667 length = state->id3->length;
669 else
671 elapsed = 0;
672 length = 0;
675 if (buf_size < 34) /* worst case: 11x UTF-8 char + \0 */
676 return;
678 time = elapsed + state->ff_rewind_count;
679 if (length)
680 pos = 55 * time / length;
682 memset(timestr, 0, sizeof(timestr));
683 format_time(timestr, sizeof(timestr)-2, time);
684 timestr[strlen(timestr)] = ':'; /* always safe */
686 for (i = 0; i < 11; i++, pos -= 5)
688 softchar = false;
689 memset(progress_pattern, 0, sizeof(progress_pattern));
691 if ((digit = timestr[time_idx]))
693 softchar = true;
694 digit -= '0';
696 if (timestr[time_idx + 1] == ':') /* ones, left aligned */
698 memcpy(progress_pattern, numbers[digit], 4);
699 time_idx += 2;
701 else /* tens, shifted right */
703 for (j = 0; j < 4; j++)
704 progress_pattern[j] = numbers[digit][j] >> 1;
706 if (time_idx > 0) /* not the first group, add colon in front */
708 progress_pattern[1] |= 0x10u;
709 progress_pattern[3] |= 0x10u;
711 time_idx++;
714 if (pos >= 5)
715 progress_pattern[5] = progress_pattern[6] = 0x1fu;
718 if (pos > 0 && pos < 5)
720 softchar = true;
721 progress_pattern[5] = progress_pattern[6] = (~0x1fu >> pos) & 0x1fu;
724 if (softchar && pat_idx < 8)
726 display->define_pattern(data->wps_progress_pat[pat_idx],
727 progress_pattern);
728 buf = utf8encode(data->wps_progress_pat[pat_idx], buf);
729 pat_idx++;
731 else if (pos <= 0)
732 buf = utf8encode(' ', buf);
733 else
734 buf = utf8encode(0xe115, buf); /* 2/7 _ */
736 *buf = '\0';
739 #endif /* HAVE_LCD_CHARCELLS */
741 /* Don't inline this; it was broken out of get_token_value to reduce stack
742 * usage.
744 static const char* NOINLINE get_lif_token_value(struct gui_wps *gwps,
745 struct logical_if *lif,
746 int offset, char *buf,
747 int buf_size)
749 int a = lif->num_options;
750 int b;
751 bool number_set = true;
752 struct wps_token *liftoken = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->token);
753 const char* out_text = get_token_value(gwps, liftoken, offset, buf, buf_size, &a);
754 if (a == -1 && liftoken->type != SKIN_TOKEN_VOLUME)
756 a = (out_text && *out_text) ? 1 : 0;
757 number_set = false;
759 switch (lif->operand.type)
761 case STRING:
763 char *cmp = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->operand.data.text);
764 if (out_text == NULL)
765 return NULL;
766 a = strcmp(out_text, cmp);
767 b = 0;
768 break;
770 case INTEGER:
771 if (!number_set && out_text && *out_text >= '0' && *out_text <= '9')
772 a = atoi(out_text);
773 /* fall through */
774 case PERCENT:
775 case DECIMAL:
776 b = lif->operand.data.number;
777 break;
778 case CODE:
780 char temp_buf[MAX_PATH];
781 const char *outb;
782 struct skin_element *element = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->operand.data.code);
783 struct wps_token *token = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), element->data);
784 b = lif->num_options;
785 outb = get_token_value(gwps, token, offset, temp_buf,
786 sizeof(temp_buf), &b);
787 if (b == -1 && liftoken->type != SKIN_TOKEN_VOLUME)
789 if (!out_text || !outb)
790 return (lif->op == IF_EQUALS) ? NULL : "neq";
791 bool equal = strcmp(out_text, outb) == 0;
792 if (lif->op == IF_EQUALS)
793 return equal ? "eq" : NULL;
794 else if (lif->op == IF_NOTEQUALS)
795 return !equal ? "neq" : NULL;
796 else
797 b = (outb && *outb) ? 1 : 0;
800 break;
801 case DEFAULT:
802 break;
805 switch (lif->op)
807 case IF_EQUALS:
808 return a == b ? "eq" : NULL;
809 case IF_NOTEQUALS:
810 return a != b ? "neq" : NULL;
811 case IF_LESSTHAN:
812 return a < b ? "lt" : NULL;
813 case IF_LESSTHAN_EQ:
814 return a <= b ? "lte" : NULL;
815 case IF_GREATERTHAN:
816 return a > b ? "gt" : NULL;
817 case IF_GREATERTHAN_EQ:
818 return a >= b ? "gte" : NULL;
820 return NULL;
823 /* Return the tags value as text. buf should be used as temp storage if needed.
825 intval is used with conditionals/enums: when this function is called,
826 intval should contain the number of options in the conditional/enum.
827 When this function returns, intval is -1 if the tag is non numeric or,
828 if the tag is numeric, *intval is the enum case we want to go to (between 1
829 and the original value of *intval, inclusive).
830 When not treating a conditional/enum, intval should be NULL.
832 const char *get_token_value(struct gui_wps *gwps,
833 struct wps_token *token, int offset,
834 char *buf, int buf_size,
835 int *intval)
837 if (!gwps)
838 return NULL;
840 struct wps_data *data = gwps->data;
841 struct wps_state *state = skin_get_global_state();
842 struct mp3entry *id3; /* Think very carefully about using this.
843 maybe get_id3_token() is the better place? */
844 const char *out_text = NULL;
845 char *filename = NULL;
847 if (!data || !state)
848 return NULL;
850 id3 = get_mp3entry_from_offset(token->next? 1: offset, &filename);
851 if (id3)
852 filename = id3->path;
854 #if CONFIG_RTC
855 struct tm* tm = NULL;
857 /* if the token is an RTC one, update the time
858 and do the necessary checks */
859 if (token->type >= SKIN_TOKENS_RTC_BEGIN
860 && token->type <= SKIN_TOKENS_RTC_END)
862 tm = get_time();
864 if (!valid_time(tm))
865 return NULL;
867 #endif
869 int limit = 1;
870 if (intval)
872 limit = *intval;
873 *intval = -1;
876 if (id3 && id3 == state->id3 && id3->cuesheet )
878 out_text = get_cuesheetid3_token(token, id3,
879 token->next?1:offset, buf, buf_size);
880 if (out_text)
881 return out_text;
883 out_text = get_id3_token(token, id3, filename, buf, buf_size, limit, intval);
884 if (out_text)
885 return out_text;
886 #if CONFIG_TUNER
887 out_text = get_radio_token(token, offset, buf, buf_size, limit, intval);
888 if (out_text)
889 return out_text;
890 #endif
892 switch (token->type)
894 case SKIN_TOKEN_LOGICAL_IF:
896 struct logical_if *lif = SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
897 return get_lif_token_value(gwps, lif, offset, buf, buf_size);
899 break;
900 case SKIN_TOKEN_LOGICAL_AND:
901 case SKIN_TOKEN_LOGICAL_OR:
903 int i = 0, truecount = 0;
904 char *skinbuffer = get_skin_buffer(data);
905 struct skin_element *element =
906 SKINOFFSETTOPTR(skinbuffer, token->value.data);
907 struct skin_tag_parameter* params =
908 SKINOFFSETTOPTR(skinbuffer, element->params);
909 struct skin_tag_parameter* thistag;
910 for (i=0; i<element->params_count; i++)
912 thistag = &params[i];
913 struct skin_element *tokenelement =
914 SKINOFFSETTOPTR(skinbuffer, thistag->data.code);
915 out_text = get_token_value(gwps,
916 SKINOFFSETTOPTR(skinbuffer, tokenelement->data),
917 offset, buf, buf_size, intval);
918 if (out_text && *out_text)
919 truecount++;
920 else if (token->type == SKIN_TOKEN_LOGICAL_AND)
921 return NULL;
923 return truecount ? "true" : NULL;
925 break;
926 case SKIN_TOKEN_SUBSTRING:
928 struct substring *ss = SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
929 const char *token_val = get_token_value(gwps,
930 SKINOFFSETTOPTR(get_skin_buffer(data), ss->token), offset,
931 buf, buf_size, intval);
932 if (token_val)
934 int start_byte, end_byte, byte_len;
935 int utf8_len = utf8length(token_val);
937 if (utf8_len < ss->start)
938 return NULL;
940 if (ss->start < 0)
941 start_byte = utf8seek(token_val, ss->start + utf8_len);
942 else
943 start_byte = utf8seek(token_val, ss->start);
945 if (ss->length < 0 || (ss->start + ss->length) > utf8_len)
946 end_byte = strlen(token_val);
947 else
948 end_byte = utf8seek(token_val, ss->start + ss->length);
950 byte_len = end_byte - start_byte;
952 if (token_val != buf)
953 memcpy(buf, &token_val[start_byte], byte_len);
954 else
955 buf = &buf[start_byte];
957 buf[byte_len] = '\0';
958 if (ss->expect_number &&
959 intval && (buf[0] >= '0' && buf[0] <= '9'))
960 *intval = atoi(buf) + 1; /* so 0 is the first item */
962 return buf;
964 return NULL;
966 break;
968 case SKIN_TOKEN_CHARACTER:
969 if (token->value.c == '\n')
970 return NULL;
971 return &(token->value.c);
973 case SKIN_TOKEN_STRING:
974 return (char*)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
976 case SKIN_TOKEN_TRANSLATEDSTRING:
977 return (char*)P2STR(ID2P(token->value.i));
979 case SKIN_TOKEN_PLAYLIST_ENTRIES:
980 snprintf(buf, buf_size, "%d", playlist_amount());
981 if (intval)
982 *intval = playlist_amount();
983 return buf;
984 #ifdef HAVE_LCD_BITMAP
985 case SKIN_TOKEN_LIST_TITLE_TEXT:
986 return sb_get_title(gwps->display->screen_type);
987 case SKIN_TOKEN_LIST_TITLE_ICON:
988 if (intval)
989 *intval = sb_get_icon(gwps->display->screen_type);
990 snprintf(buf, buf_size, "%d",sb_get_icon(gwps->display->screen_type));
991 return buf;
992 case SKIN_TOKEN_LIST_ITEM_TEXT:
994 struct listitem *li = (struct listitem *)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
995 return skinlist_get_item_text(li->offset, li->wrap, buf, buf_size);
997 case SKIN_TOKEN_LIST_ITEM_ROW:
998 if (intval)
999 *intval = skinlist_get_item_row() + 1;
1000 snprintf(buf, buf_size, "%d",skinlist_get_item_row() + 1);
1001 return buf;
1002 case SKIN_TOKEN_LIST_ITEM_COLUMN:
1003 if (intval)
1004 *intval = skinlist_get_item_column() + 1;
1005 snprintf(buf, buf_size, "%d",skinlist_get_item_column() + 1);
1006 return buf;
1007 case SKIN_TOKEN_LIST_ITEM_NUMBER:
1008 if (intval)
1009 *intval = skinlist_get_item_number() + 1;
1010 snprintf(buf, buf_size, "%d",skinlist_get_item_number() + 1);
1011 return buf;
1012 case SKIN_TOKEN_LIST_ITEM_IS_SELECTED:
1013 return skinlist_is_selected_item()?"s":"";
1014 case SKIN_TOKEN_LIST_ITEM_ICON:
1016 struct listitem *li = (struct listitem *)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
1017 int icon = skinlist_get_item_icon(li->offset, li->wrap);
1018 if (intval)
1019 *intval = icon;
1020 snprintf(buf, buf_size, "%d", icon);
1021 return buf;
1023 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR:
1024 return skinlist_needs_scrollbar(gwps->display->screen_type) ? "s" : "";
1025 #endif
1026 case SKIN_TOKEN_PLAYLIST_NAME:
1027 return playlist_name(NULL, buf, buf_size);
1029 case SKIN_TOKEN_PLAYLIST_POSITION:
1030 snprintf(buf, buf_size, "%d", playlist_get_display_index()+offset);
1031 if (intval)
1032 *intval = playlist_get_display_index()+offset;
1033 return buf;
1035 case SKIN_TOKEN_PLAYLIST_SHUFFLE:
1036 if ( global_settings.playlist_shuffle )
1037 return "s";
1038 else
1039 return NULL;
1040 break;
1042 case SKIN_TOKEN_VOLUME:
1043 snprintf(buf, buf_size, "%d", global_settings.volume);
1044 if (intval)
1046 int minvol = sound_min(SOUND_VOLUME);
1047 if (limit == TOKEN_VALUE_ONLY)
1049 *intval = global_settings.volume;
1051 else if (global_settings.volume == minvol)
1053 *intval = 1;
1055 else if (global_settings.volume == 0)
1057 *intval = limit - 1;
1059 else if (global_settings.volume > 0)
1061 *intval = limit;
1063 else
1065 *intval = (limit-3) * (global_settings.volume - minvol - 1)
1066 / (-1 - minvol) + 2;
1069 return buf;
1070 #ifdef HAVE_ALBUMART
1071 case SKIN_TOKEN_ALBUMART_FOUND:
1072 if (SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart))
1074 int handle = -1;
1075 handle = playback_current_aa_hid(data->playback_aa_slot);
1076 #if CONFIG_TUNER
1077 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
1079 struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart);
1080 struct dim dim = {aa->width, aa->height};
1081 handle = radio_get_art_hid(&dim);
1083 #endif
1084 if (handle >= 0)
1085 return "C";
1087 return NULL;
1088 #endif
1090 case SKIN_TOKEN_BATTERY_PERCENT:
1092 int l = battery_level();
1094 if (intval)
1096 if (limit == TOKEN_VALUE_ONLY)
1098 *intval = l;
1100 else
1102 limit = MAX(limit, 3);
1103 if (l > -1) {
1104 /* First enum is used for "unknown level",
1105 * last enum is used for 100%.
1107 *intval = (limit - 2) * l / 100 + 2;
1108 } else {
1109 *intval = 1;
1114 if (l > -1) {
1115 snprintf(buf, buf_size, "%d", l);
1116 return buf;
1117 } else {
1118 return "?";
1122 case SKIN_TOKEN_BATTERY_VOLTS:
1124 int v = battery_voltage();
1125 if (v >= 0) {
1126 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
1127 return buf;
1128 } else {
1129 return "?";
1133 case SKIN_TOKEN_BATTERY_TIME:
1135 int t = battery_time();
1136 if (t >= 0)
1137 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
1138 else
1139 return "?h ?m";
1140 return buf;
1143 #if CONFIG_CHARGING
1144 case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED:
1146 if(charger_input_state==CHARGER)
1147 return "p";
1148 else
1149 return NULL;
1151 #endif
1152 #if CONFIG_CHARGING >= CHARGING_MONITOR
1153 case SKIN_TOKEN_BATTERY_CHARGING:
1155 if (charge_state == CHARGING || charge_state == TOPOFF) {
1156 return "c";
1157 } else {
1158 return NULL;
1161 #endif
1162 #ifdef HAVE_USB_POWER
1163 case SKIN_TOKEN_USB_POWERED:
1164 if (usb_powered())
1165 return "u";
1166 return NULL;
1167 #endif
1168 case SKIN_TOKEN_BATTERY_SLEEPTIME:
1170 if (get_sleep_timer() == 0)
1171 return NULL;
1172 else
1174 format_time(buf, buf_size, get_sleep_timer() * 1000);
1175 return buf;
1179 case SKIN_TOKEN_PLAYBACK_STATUS:
1181 int status = current_playmode();
1182 /* music */
1183 int mode = 1; /* stop */
1184 if (status == STATUS_PLAY)
1185 mode = 2; /* play */
1186 if (state->is_fading ||
1187 (status == STATUS_PAUSE && !status_get_ffmode()))
1188 mode = 3; /* pause */
1189 else
1190 { /* ff / rwd */
1191 if (status_get_ffmode() == STATUS_FASTFORWARD)
1192 mode = 4;
1193 if (status_get_ffmode() == STATUS_FASTBACKWARD)
1194 mode = 5;
1196 #ifdef HAVE_RECORDING
1197 /* recording */
1198 if (status == STATUS_RECORD)
1199 mode = 6;
1200 else if (status == STATUS_RECORD_PAUSE)
1201 mode = 7;
1202 #endif
1203 #if CONFIG_TUNER
1204 /* radio */
1205 if (status == STATUS_RADIO)
1206 mode = 8;
1207 else if (status == STATUS_RADIO_PAUSE)
1208 mode = 9;
1209 #endif
1211 if (intval) {
1212 *intval = mode;
1215 snprintf(buf, buf_size, "%d", mode-1);
1216 return buf;
1219 case SKIN_TOKEN_REPEAT_MODE:
1220 if (intval)
1221 *intval = global_settings.repeat_mode + 1;
1222 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
1223 return buf;
1225 case SKIN_TOKEN_RTC_PRESENT:
1226 #if CONFIG_RTC
1227 return "c";
1228 #else
1229 return NULL;
1230 #endif
1232 #if CONFIG_RTC
1233 case SKIN_TOKEN_RTC_12HOUR_CFG:
1234 if (intval)
1235 *intval = global_settings.timeformat + 1;
1236 snprintf(buf, buf_size, "%d", global_settings.timeformat);
1237 return buf;
1239 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1240 /* d: day of month (01..31) */
1241 snprintf(buf, buf_size, "%02d", tm->tm_mday);
1242 if (intval)
1243 *intval = tm->tm_mday - 1;
1244 return buf;
1246 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1247 /* e: day of month, blank padded ( 1..31) */
1248 snprintf(buf, buf_size, "%2d", tm->tm_mday);
1249 if (intval)
1250 *intval = tm->tm_mday - 1;
1251 return buf;
1253 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1254 /* H: hour (00..23) */
1255 snprintf(buf, buf_size, "%02d", tm->tm_hour);
1256 if (intval)
1257 *intval = tm->tm_hour;
1258 return buf;
1260 case SKIN_TOKEN_RTC_HOUR_24:
1261 /* k: hour ( 0..23) */
1262 snprintf(buf, buf_size, "%2d", tm->tm_hour);
1263 if (intval)
1264 *intval = tm->tm_hour;
1265 return buf;
1267 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1268 /* I: hour (01..12) */
1269 snprintf(buf, buf_size, "%02d",
1270 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1271 if (intval)
1272 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1273 return buf;
1275 case SKIN_TOKEN_RTC_HOUR_12:
1276 /* l: hour ( 1..12) */
1277 snprintf(buf, buf_size, "%2d",
1278 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1279 if (intval)
1280 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1281 return buf;
1283 case SKIN_TOKEN_RTC_MONTH:
1284 /* m: month (01..12) */
1285 if (intval)
1286 *intval = tm->tm_mon + 1;
1287 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
1288 return buf;
1290 case SKIN_TOKEN_RTC_MINUTE:
1291 /* M: minute (00..59) */
1292 snprintf(buf, buf_size, "%02d", tm->tm_min);
1293 if (intval)
1294 *intval = tm->tm_min;
1295 return buf;
1297 case SKIN_TOKEN_RTC_SECOND:
1298 /* S: second (00..59) */
1299 snprintf(buf, buf_size, "%02d", tm->tm_sec);
1300 if (intval)
1301 *intval = tm->tm_sec;
1302 return buf;
1304 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1305 /* y: last two digits of year (00..99) */
1306 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
1307 if (intval)
1308 *intval = tm->tm_year % 100;
1309 return buf;
1311 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1312 /* Y: year (1970...) */
1313 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
1314 if (intval)
1315 *intval = tm->tm_year + 1900;
1316 return buf;
1318 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1319 /* p: upper case AM or PM indicator */
1320 if (intval)
1321 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1322 return tm->tm_hour/12 == 0 ? "AM" : "PM";
1324 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1325 /* P: lower case am or pm indicator */
1326 if (intval)
1327 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1328 return tm->tm_hour/12 == 0 ? "am" : "pm";
1330 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1331 /* a: abbreviated weekday name (Sun..Sat) */
1332 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
1334 case SKIN_TOKEN_RTC_MONTH_NAME:
1335 /* b: abbreviated month name (Jan..Dec) */
1336 return str(LANG_MONTH_JANUARY + tm->tm_mon);
1338 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1339 /* u: day of week (1..7); 1 is Monday */
1340 if (intval)
1341 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
1342 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
1343 return buf;
1345 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1346 /* w: day of week (0..6); 0 is Sunday */
1347 if (intval)
1348 *intval = tm->tm_wday + 1;
1349 snprintf(buf, buf_size, "%1d", tm->tm_wday);
1350 return buf;
1351 #else
1352 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1353 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1354 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1355 case SKIN_TOKEN_RTC_HOUR_24:
1356 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1357 case SKIN_TOKEN_RTC_HOUR_12:
1358 case SKIN_TOKEN_RTC_MONTH:
1359 case SKIN_TOKEN_RTC_MINUTE:
1360 case SKIN_TOKEN_RTC_SECOND:
1361 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1362 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1363 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1364 return "--";
1365 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1366 return "----";
1367 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1368 case SKIN_TOKEN_RTC_MONTH_NAME:
1369 return "---";
1370 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1371 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1372 return "-";
1373 #endif
1375 #ifdef HAVE_LCD_CHARCELLS
1376 case SKIN_TOKEN_PROGRESSBAR:
1378 char *end;
1379 format_player_progress(gwps);
1380 end = utf8encode(data->wps_progress_pat[0], buf);
1381 *end = '\0';
1382 return buf;
1385 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1386 if(is_new_player())
1388 /* we need 11 characters (full line) for
1389 progress-bar */
1390 strlcpy(buf, " ", buf_size);
1391 format_player_fullbar(gwps,buf,buf_size);
1392 DEBUGF("bar='%s'\n",buf);
1394 else
1396 /* Tell the user if we have an OldPlayer */
1397 strlcpy(buf, " <Old LCD> ", buf_size);
1399 return buf;
1400 #endif
1403 #ifdef HAVE_LCD_BITMAP
1404 /* peakmeter */
1405 case SKIN_TOKEN_PEAKMETER_LEFT:
1406 case SKIN_TOKEN_PEAKMETER_RIGHT:
1408 int left, right, val;
1409 peak_meter_current_vals(&left, &right);
1410 val = token->type == SKIN_TOKEN_PEAKMETER_LEFT ?
1411 left : right;
1412 val = peak_meter_scale_value(val, limit==1 ? MAX_PEAK : limit);
1413 if (intval)
1414 *intval = val;
1415 snprintf(buf, buf_size, "%d", val);
1416 data->peak_meter_enabled = true;
1417 return buf;
1419 #endif
1421 #if (CONFIG_CODEC == SWCODEC)
1422 case SKIN_TOKEN_CROSSFADE:
1423 #ifdef HAVE_CROSSFADE
1424 if (intval)
1425 *intval = global_settings.crossfade + 1;
1426 snprintf(buf, buf_size, "%d", global_settings.crossfade);
1427 #else
1428 snprintf(buf, buf_size, "%d", 0);
1429 #endif
1430 return buf;
1432 case SKIN_TOKEN_REPLAYGAIN:
1434 int globtype = global_settings.replaygain_settings.type;
1435 int val;
1438 if (globtype == REPLAYGAIN_OFF)
1439 val = 1; /* off */
1440 else
1442 int type = id3_get_replaygain_mode(id3);
1444 if (type < 0)
1445 val = 6; /* no tag */
1446 else
1447 val = type + 2;
1449 if (globtype == REPLAYGAIN_SHUFFLE)
1450 val += 2;
1453 if (intval)
1454 *intval = val;
1456 switch (val)
1458 case 1:
1459 case 6:
1460 return "+0.00 dB";
1461 break;
1462 /* due to above, coming here with !id3 shouldn't be possible */
1463 case 2:
1464 case 4:
1465 replaygain_itoa(buf, buf_size, id3->track_level);
1466 break;
1467 case 3:
1468 case 5:
1469 replaygain_itoa(buf, buf_size, id3->album_level);
1470 break;
1472 return buf;
1474 #endif /* (CONFIG_CODEC == SWCODEC) */
1476 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHCONTROL)
1477 case SKIN_TOKEN_SOUND_PITCH:
1479 int32_t pitch = sound_get_pitch();
1480 snprintf(buf, buf_size, "%ld.%ld",
1481 pitch / PITCH_SPEED_PRECISION,
1482 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1484 if (intval)
1485 *intval = pitch_speed_enum(limit, pitch,
1486 PITCH_SPEED_PRECISION * 100);
1487 return buf;
1489 #endif
1491 #if (CONFIG_CODEC == SWCODEC) && defined (HAVE_PITCHCONTROL)
1492 case SKIN_TOKEN_SOUND_SPEED:
1494 int32_t pitch = sound_get_pitch();
1495 int32_t speed;
1496 if (dsp_timestretch_available())
1497 speed = GET_SPEED(pitch, dsp_get_timestretch());
1498 else
1499 speed = pitch;
1500 snprintf(buf, buf_size, "%ld.%ld",
1501 speed / PITCH_SPEED_PRECISION,
1502 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1503 if (intval)
1504 *intval = pitch_speed_enum(limit, speed,
1505 PITCH_SPEED_PRECISION * 100);
1506 return buf;
1508 #endif
1510 case SKIN_TOKEN_MAIN_HOLD:
1511 #ifdef HAVE_TOUCHSCREEN
1512 if (data->touchscreen_locked)
1513 return "t";
1514 #endif
1515 #ifdef HAS_BUTTON_HOLD
1516 if (button_hold())
1517 #else
1518 if (is_keys_locked())
1519 #endif /*hold switch or softlock*/
1520 return "h";
1521 else
1522 return NULL;
1524 #ifdef HAS_REMOTE_BUTTON_HOLD
1525 case SKIN_TOKEN_REMOTE_HOLD:
1526 if (remote_button_hold())
1527 return "r";
1528 else
1529 return NULL;
1530 #endif
1532 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1533 case SKIN_TOKEN_VLED_HDD:
1534 if(led_read(HZ/2))
1535 return "h";
1536 else
1537 return NULL;
1538 #endif
1539 case SKIN_TOKEN_BUTTON_VOLUME:
1540 if (global_status.last_volume_change &&
1541 TIME_BEFORE(current_tick, global_status.last_volume_change +
1542 token->value.i))
1543 return "v";
1544 return NULL;
1546 case SKIN_TOKEN_LASTTOUCH:
1548 #ifdef HAVE_TOUCHSCREEN
1549 unsigned int last_touch = touchscreen_last_touch();
1550 char *skin_base = get_skin_buffer(data);
1551 struct touchregion_lastpress *data = SKINOFFSETTOPTR(skin_base, token->value.data);
1552 struct touchregion *region = SKINOFFSETTOPTR(skin_base, data->region);
1553 if (region)
1554 last_touch = region->last_press;
1556 if (last_touch != 0xffff &&
1557 TIME_BEFORE(current_tick, data->timeout + last_touch))
1558 return "t";
1559 #endif
1561 return NULL;
1562 case SKIN_TOKEN_HAVE_TOUCH:
1563 #ifdef HAVE_TOUCHSCREEN
1564 return "t";
1565 #else
1566 return NULL;
1567 #endif
1569 case SKIN_TOKEN_SETTING:
1571 const struct settings_list *s = settings+token->value.i;
1572 if (intval)
1574 /* Handle contionals */
1575 switch (s->flags&F_T_MASK)
1577 case F_T_INT:
1578 case F_T_UINT:
1579 if (s->flags&F_T_SOUND)
1581 /* %?St|name|<min|min+1|...|max-1|max> */
1582 int sound_setting = s->sound_setting->setting;
1583 /* settings with decimals can't be used in conditionals */
1584 if (sound_numdecimals(sound_setting) == 0)
1586 *intval = (*(int*)s->setting-sound_min(sound_setting))
1587 /sound_steps(sound_setting) + 1;
1589 else
1590 *intval = -1;
1592 else if (s->flags&F_RGB)
1593 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1594 /* shouldn't overflow since colors are stored
1595 * on 16 bits ...
1596 * but this is pretty useless anyway */
1597 *intval = *(int*)s->setting + 1;
1598 else if (s->cfg_vals == NULL)
1599 /* %?St|name|<1st choice|2nd choice|...> */
1600 *intval = (*(int*)s->setting-s->int_setting->min)
1601 /s->int_setting->step + 1;
1602 else
1603 /* %?St|name|<1st choice|2nd choice|...> */
1604 /* Not sure about this one. cfg_name/vals are
1605 * indexed from 0 right? */
1606 *intval = *(int*)s->setting + 1;
1607 break;
1608 case F_T_BOOL:
1609 /* %?St|name|<if true|if false> */
1610 *intval = *(bool*)s->setting?1:2;
1611 break;
1612 case F_T_CHARPTR:
1613 case F_T_UCHARPTR:
1614 /* %?St|name|<if non empty string|if empty>
1615 * The string's emptyness discards the setting's
1616 * prefix and suffix */
1617 *intval = ((char*)s->setting)[0]?1:2;
1618 /* if there is a prefix we should ignore it here */
1619 if (s->filename_setting->prefix)
1620 return (char*)s->setting;
1621 break;
1622 default:
1623 /* This shouldn't happen ... but you never know */
1624 *intval = -1;
1625 break;
1628 /* Special handlng for filenames because we dont want to show the prefix */
1629 if ((s->flags&F_T_MASK) == F_T_CHARPTR ||
1630 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1632 if (s->filename_setting->prefix)
1633 return (char*)s->setting;
1635 cfg_to_string(token->value.i,buf,buf_size);
1636 return buf;
1638 case SKIN_TOKEN_HAVE_TUNER:
1639 #if CONFIG_TUNER
1640 if (radio_hardware_present())
1641 return "r";
1642 #endif
1643 return NULL;
1644 /* Recording tokens */
1645 case SKIN_TOKEN_HAVE_RECORDING:
1646 #ifdef HAVE_RECORDING
1647 return "r";
1648 #else
1649 return NULL;
1650 #endif
1652 #ifdef HAVE_RECORDING
1653 case SKIN_TOKEN_IS_RECORDING:
1654 if (audio_status() == AUDIO_STATUS_RECORD)
1655 return "r";
1656 return NULL;
1657 case SKIN_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1659 #if CONFIG_CODEC == SWCODEC
1660 unsigned long samprk;
1661 int rec_freq = global_settings.rec_frequency;
1663 #ifdef SIMULATOR
1664 samprk = 44100;
1665 #else
1666 #if defined(HAVE_SPDIF_REC)
1667 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1669 /* Use rate in use, not current measured rate if it changed */
1670 samprk = pcm_rec_sample_rate();
1671 rec_freq = 0;
1672 while (rec_freq < SAMPR_NUM_FREQ &&
1673 audio_master_sampr_list[rec_freq] != samprk)
1675 rec_freq++;
1678 else
1679 #endif
1680 samprk = rec_freq_sampr[rec_freq];
1681 #endif /* SIMULATOR */
1682 if (intval)
1684 switch (rec_freq)
1686 REC_HAVE_96_(case REC_FREQ_96:
1687 *intval = 1;
1688 break;)
1689 REC_HAVE_88_(case REC_FREQ_88:
1690 *intval = 2;
1691 break;)
1692 REC_HAVE_64_(case REC_FREQ_64:
1693 *intval = 3;
1694 break;)
1695 REC_HAVE_48_(case REC_FREQ_48:
1696 *intval = 4;
1697 break;)
1698 REC_HAVE_44_(case REC_FREQ_44:
1699 *intval = 5;
1700 break;)
1701 REC_HAVE_32_(case REC_FREQ_32:
1702 *intval = 6;
1703 break;)
1704 REC_HAVE_24_(case REC_FREQ_24:
1705 *intval = 7;
1706 break;)
1707 REC_HAVE_22_(case REC_FREQ_22:
1708 *intval = 8;
1709 break;)
1710 REC_HAVE_16_(case REC_FREQ_16:
1711 *intval = 9;
1712 break;)
1713 REC_HAVE_12_(case REC_FREQ_12:
1714 *intval = 10;
1715 break;)
1716 REC_HAVE_11_(case REC_FREQ_11:
1717 *intval = 11;
1718 break;)
1719 REC_HAVE_8_(case REC_FREQ_8:
1720 *intval = 12;
1721 break;)
1724 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1725 #else /* HWCODEC */
1727 static const char * const freq_strings[] =
1728 {"--", "44", "48", "32", "22", "24", "16"};
1729 int freq = 1 + global_settings.rec_frequency;
1730 #ifdef HAVE_SPDIF_REC
1731 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1733 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1734 freq = 0;
1736 #endif /* HAVE_SPDIF_IN */
1737 if (intval)
1738 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1739 snprintf(buf, buf_size, "%s\n",
1740 freq_strings[global_settings.rec_frequency]);
1741 #endif
1742 return buf;
1744 #if CONFIG_CODEC == SWCODEC
1745 case SKIN_TOKEN_REC_ENCODER:
1747 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1748 if (intval)
1749 *intval = rec_format;
1750 switch (rec_format)
1752 case REC_FORMAT_PCM_WAV:
1753 return "wav";
1754 case REC_FORMAT_AIFF:
1755 return "aiff";
1756 case REC_FORMAT_WAVPACK:
1757 return "wv";
1758 case REC_FORMAT_MPA_L3:
1759 return "MP3";
1760 default:
1761 return NULL;
1763 break;
1765 #endif
1766 case SKIN_TOKEN_REC_BITRATE:
1767 #if CONFIG_CODEC == SWCODEC
1768 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1770 if (intval)
1772 #if 0 /* FIXME: I dont know if this is needed? */
1773 switch (1<<global_settings.mp3_enc_config.bitrate)
1775 case MP3_BITR_CAP_8:
1776 *intval = 1;
1777 break;
1778 case MP3_BITR_CAP_16:
1779 *intval = 2;
1780 break;
1781 case MP3_BITR_CAP_24:
1782 *intval = 3;
1783 break;
1784 case MP3_BITR_CAP_32:
1785 *intval = 4;
1786 break;
1787 case MP3_BITR_CAP_40:
1788 *intval = 5;
1789 break;
1790 case MP3_BITR_CAP_48:
1791 *intval = 6;
1792 break;
1793 case MP3_BITR_CAP_56:
1794 *intval = 7;
1795 break;
1796 case MP3_BITR_CAP_64:
1797 *intval = 8;
1798 break;
1799 case MP3_BITR_CAP_80:
1800 *intval = 9;
1801 break;
1802 case MP3_BITR_CAP_96:
1803 *intval = 10;
1804 break;
1805 case MP3_BITR_CAP_112:
1806 *intval = 11;
1807 break;
1808 case MP3_BITR_CAP_128:
1809 *intval = 12;
1810 break;
1811 case MP3_BITR_CAP_144:
1812 *intval = 13;
1813 break;
1814 case MP3_BITR_CAP_160:
1815 *intval = 14;
1816 break;
1817 case MP3_BITR_CAP_192:
1818 *intval = 15;
1819 break;
1821 #endif
1822 *intval = global_settings.mp3_enc_config.bitrate+1;
1824 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1825 return buf;
1827 else
1828 return NULL; /* Fixme later */
1829 #else /* CONFIG_CODEC == HWCODEC */
1830 if (intval)
1831 *intval = global_settings.rec_quality+1;
1832 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1833 return buf;
1834 #endif
1835 case SKIN_TOKEN_REC_MONO:
1836 if (!global_settings.rec_channels)
1837 return "m";
1838 return NULL;
1840 case SKIN_TOKEN_REC_SECONDS:
1842 int time = (audio_recorded_time() / HZ) % 60;
1843 if (intval)
1844 *intval = time;
1845 snprintf(buf, buf_size, "%02d", time);
1846 return buf;
1848 case SKIN_TOKEN_REC_MINUTES:
1850 int time = (audio_recorded_time() / HZ) / 60;
1851 if (intval)
1852 *intval = time;
1853 snprintf(buf, buf_size, "%02d", time);
1854 return buf;
1856 case SKIN_TOKEN_REC_HOURS:
1858 int time = (audio_recorded_time() / HZ) / 3600;
1859 if (intval)
1860 *intval = time;
1861 snprintf(buf, buf_size, "%02d", time);
1862 return buf;
1865 #endif /* HAVE_RECORDING */
1867 case SKIN_TOKEN_CURRENT_SCREEN:
1869 int curr_screen = get_current_activity();
1870 if (intval)
1872 *intval = curr_screen;
1874 snprintf(buf, buf_size, "%d", curr_screen);
1875 return buf;
1878 case SKIN_TOKEN_LANG_IS_RTL:
1879 return lang_is_rtl() ? "r" : NULL;
1881 #ifdef HAVE_SKIN_VARIABLES
1882 case SKIN_TOKEN_VAR_GETVAL:
1884 char *skin_base = get_skin_buffer(data);
1885 struct skin_var* var = SKINOFFSETTOPTR(skin_base, token->value.data);
1886 if (intval)
1887 *intval = var->value;
1888 snprintf(buf, buf_size, "%d", var->value);
1889 return buf;
1891 break;
1892 case SKIN_TOKEN_VAR_TIMEOUT:
1894 char *skin_base = get_skin_buffer(data);
1895 struct skin_var_lastchange *data = SKINOFFSETTOPTR(skin_base, token->value.data);
1896 struct skin_var* var = SKINOFFSETTOPTR(skin_base, data->var);
1897 unsigned int last_change = var->last_changed;
1899 if (last_change != 0xffff &&
1900 TIME_BEFORE(current_tick, data->timeout + last_change))
1901 return "t";
1903 return NULL;
1904 #endif
1906 default:
1907 return NULL;