Revert "skin tags: fix the id3 track/disc numbers in conditionals"
[maemo-rb.git] / apps / gui / skin_engine / skin_tokens.c
blobe58393e19c0097cec0820374bce6238fddc560a2
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 return id3->disc_string;
259 if (id3->discnum) {
260 snprintf(buf, buf_size, "%d", id3->discnum);
261 return buf;
263 return NULL;
264 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
265 if (id3->track_string)
266 return id3->track_string;
267 if (id3->tracknum) {
268 snprintf(buf, buf_size, "%d", id3->tracknum);
269 return buf;
271 return NULL;
272 case SKIN_TOKEN_METADATA_TRACK_TITLE:
273 return id3->title;
274 case SKIN_TOKEN_METADATA_VERSION:
275 switch (id3->id3version)
277 case ID3_VER_1_0:
278 return "1";
279 case ID3_VER_1_1:
280 return "1.1";
281 case ID3_VER_2_2:
282 return "2.2";
283 case ID3_VER_2_3:
284 return "2.3";
285 case ID3_VER_2_4:
286 return "2.4";
287 default:
288 break;
290 return NULL;
291 case SKIN_TOKEN_METADATA_YEAR:
292 if( id3->year_string )
293 return id3->year_string;
294 if (id3->year) {
295 snprintf(buf, buf_size, "%d", id3->year);
296 return buf;
298 return NULL;
299 case SKIN_TOKEN_METADATA_COMMENT:
300 return id3->comment;
301 case SKIN_TOKEN_FILE_BITRATE:
302 if(id3->bitrate)
303 snprintf(buf, buf_size, "%d", id3->bitrate);
304 else
305 return "?";
306 return buf;
307 case SKIN_TOKEN_TRACK_TIME_ELAPSED:
308 if (intval && limit == TOKEN_VALUE_ONLY)
309 *intval = elapsed/1000;
310 format_time(buf, buf_size, elapsed);
311 return buf;
313 case SKIN_TOKEN_TRACK_TIME_REMAINING:
314 if (intval && limit == TOKEN_VALUE_ONLY)
315 *intval = (length - elapsed)/1000;
316 format_time(buf, buf_size, length - elapsed);
317 return buf;
319 case SKIN_TOKEN_TRACK_LENGTH:
320 if (intval && limit == TOKEN_VALUE_ONLY)
321 *intval = length/1000;
322 format_time(buf, buf_size, length);
323 return buf;
325 case SKIN_TOKEN_TRACK_ELAPSED_PERCENT:
326 if (length <= 0)
327 return NULL;
329 if (intval)
331 if (limit == TOKEN_VALUE_ONLY)
332 limit = 100; /* make it a percentage */
333 *intval = limit * elapsed / length + 1;
335 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
336 return buf;
338 case SKIN_TOKEN_TRACK_STARTING:
340 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
341 if (elapsed < time)
342 return "starting";
344 return NULL;
345 case SKIN_TOKEN_TRACK_ENDING:
347 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
348 if (length - elapsed < time)
349 return "ending";
351 return NULL;
353 case SKIN_TOKEN_FILE_CODEC:
354 if (intval)
356 if(id3->codectype == AFMT_UNKNOWN)
357 *intval = AFMT_NUM_CODECS;
358 else
359 *intval = id3->codectype;
361 return get_codectype(id3);
363 case SKIN_TOKEN_FILE_FREQUENCY:
364 snprintf(buf, buf_size, "%ld", id3->frequency);
365 return buf;
366 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
367 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
368 if ((id3->frequency % 1000) < 100)
369 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
370 else
371 snprintf(buf, buf_size, "%ld.%lu",
372 id3->frequency / 1000,
373 (id3->frequency % 1000) / 100);
374 return buf;
375 case SKIN_TOKEN_FILE_VBR:
376 return (id3->vbr) ? "(avg)" : NULL;
377 case SKIN_TOKEN_FILE_SIZE:
378 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
379 return buf;
381 #ifdef HAVE_TAGCACHE
382 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
383 if (intval)
384 *intval = id3->playcount + 1;
385 snprintf(buf, buf_size, "%ld", id3->playcount);
386 return buf;
387 case SKIN_TOKEN_DATABASE_RATING:
388 if (intval)
389 *intval = id3->rating + 1;
390 snprintf(buf, buf_size, "%d", id3->rating);
391 return buf;
392 case SKIN_TOKEN_DATABASE_AUTOSCORE:
393 if (intval)
394 *intval = id3->score + 1;
395 snprintf(buf, buf_size, "%d", id3->score);
396 return buf;
397 #endif
399 default:
400 return get_filename_token(token, id3->path, buf, buf_size);
403 else /* id3 == NULL, handle the error based on the expected return type */
405 switch (token->type)
407 /* Most tokens expect NULL on error so leave that for the default case,
408 * The ones that expect "0" need to be handled */
409 case SKIN_TOKEN_FILE_FREQUENCY:
410 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
411 case SKIN_TOKEN_FILE_SIZE:
412 #ifdef HAVE_TAGCACHE
413 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
414 case SKIN_TOKEN_DATABASE_RATING:
415 case SKIN_TOKEN_DATABASE_AUTOSCORE:
416 #endif
417 if (intval)
418 *intval = 0;
419 return "0";
420 default:
421 return get_filename_token(token, filename, buf, buf_size);
424 return buf;
427 #if CONFIG_TUNER
429 /* Formats the frequency (specified in Hz) in MHz, */
430 /* with one or two digits after the decimal point -- */
431 /* depending on the frequency changing step. */
432 /* Returns buf */
433 static char *format_freq_MHz(int freq, int freq_step, char *buf, int buf_size)
435 int scale, div;
436 char *fmt;
437 if (freq_step < 100000)
439 /* Format with two digits after decimal point */
440 scale = 10000;
441 fmt = "%d.%02d";
443 else
445 /* Format with one digit after decimal point */
446 scale = 100000;
447 fmt = "%d.%d";
449 div = 1000000 / scale;
450 freq = freq / scale;
451 snprintf(buf, buf_size, fmt, freq/div, freq%div);
452 return buf;
456 /* Tokens which are really only used by the radio screen go in here */
457 const char *get_radio_token(struct wps_token *token, int preset_offset,
458 char *buf, int buf_size, int limit, int *intval)
460 const struct fm_region_data *region_data =
461 &(fm_region_data[global_settings.fm_region]);
462 (void)limit;
463 switch (token->type)
465 /* Radio/tuner tokens */
466 case SKIN_TOKEN_TUNER_TUNED:
467 if (tuner_get(RADIO_TUNED))
468 return "t";
469 return NULL;
470 case SKIN_TOKEN_TUNER_SCANMODE:
471 if (radio_scan_mode())
472 return "s";
473 return NULL;
474 case SKIN_TOKEN_TUNER_STEREO:
475 if (radio_is_stereo())
476 return "s";
477 return NULL;
478 case SKIN_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
479 return format_freq_MHz(region_data->freq_min,
480 region_data->freq_step, buf, buf_size);
481 case SKIN_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
482 return format_freq_MHz(region_data->freq_max,
483 region_data->freq_step, buf, buf_size);
484 case SKIN_TOKEN_TUNER_CURFREQ:
485 return format_freq_MHz(radio_current_frequency(),
486 region_data->freq_step, buf, buf_size);
487 #ifdef HAVE_RADIO_RSSI
488 case SKIN_TOKEN_TUNER_RSSI:
489 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI));
490 if (intval)
492 int val = tuner_get(RADIO_RSSI);
493 int min = tuner_get(RADIO_RSSI_MIN);
494 int max = tuner_get(RADIO_RSSI_MAX);
495 if (limit == TOKEN_VALUE_ONLY)
497 *intval = val;
499 else
501 *intval = 1+(limit-1)*(val-min)/(max-1-min);
504 return buf;
505 case SKIN_TOKEN_TUNER_RSSI_MIN:
506 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MIN));
507 return buf;
508 case SKIN_TOKEN_TUNER_RSSI_MAX:
509 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MAX));
510 return buf;
511 #endif
512 case SKIN_TOKEN_PRESET_NAME:
513 case SKIN_TOKEN_PRESET_FREQ:
514 case SKIN_TOKEN_PRESET_ID:
516 int preset_count = radio_preset_count();
517 int cur_preset = radio_current_preset();
518 if (preset_count == 0 || cur_preset < 0)
519 return NULL;
520 int preset = cur_preset + preset_offset;
521 /* make sure it's in the valid range */
522 preset %= preset_count;
523 if (preset < 0)
524 preset += preset_count;
525 if (token->type == SKIN_TOKEN_PRESET_NAME)
526 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
527 else if (token->type == SKIN_TOKEN_PRESET_FREQ)
528 format_freq_MHz(radio_get_preset(preset)->frequency,
529 region_data->freq_step, buf, buf_size);
530 else
531 snprintf(buf, buf_size, "%d", preset + 1);
532 return buf;
534 case SKIN_TOKEN_PRESET_COUNT:
535 snprintf(buf, buf_size, "%d", radio_preset_count());
536 if (intval)
537 *intval = radio_preset_count();
538 return buf;
539 case SKIN_TOKEN_HAVE_RDS:
540 #ifdef HAVE_RDS_CAP
541 return "rds";
542 case SKIN_TOKEN_RDS_NAME:
543 return tuner_get_rds_info(RADIO_RDS_NAME);
544 case SKIN_TOKEN_RDS_TEXT:
545 return tuner_get_rds_info(RADIO_RDS_TEXT);
546 #else
547 return NULL; /* end of the SKIN_TOKEN_HAVE_RDS case */
548 #endif /* HAVE_RDS_CAP */
549 default:
550 return NULL;
552 return NULL;
554 #endif
556 static struct mp3entry* get_mp3entry_from_offset(int offset, char **filename)
558 struct mp3entry* pid3 = NULL;
559 struct wps_state *state = skin_get_global_state();
560 struct cuesheet *cue = state->id3 ? state->id3->cuesheet : NULL;
561 const char *fname = NULL;
562 if (cue && cue->curr_track_idx + offset < cue->track_count)
563 pid3 = state->id3;
564 else if (offset == 0)
565 pid3 = state->id3;
566 else if (offset == 1)
567 pid3 = state->nid3;
568 else
570 static char filename_buf[MAX_PATH + 1];
571 fname = playlist_peek(offset, filename_buf, sizeof(filename_buf));
572 *filename = (char*)fname;
573 #if CONFIG_CODEC == SWCODEC
574 static struct mp3entry tempid3;
575 if (
576 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
577 tagcache_fill_tags(&tempid3, fname) ||
578 #endif
579 audio_peek_track(&tempid3, offset)
582 pid3 = &tempid3;
584 #endif
586 return pid3;
589 #ifdef HAVE_LCD_CHARCELLS
590 static void format_player_progress(struct gui_wps *gwps)
592 struct wps_state *state = skin_get_global_state();
593 struct screen *display = gwps->display;
594 unsigned char progress_pattern[7];
595 int pos = 0;
596 int i;
598 int elapsed, length;
599 if (LIKELY(state->id3))
601 elapsed = state->id3->elapsed;
602 length = state->id3->length;
604 else
606 elapsed = 0;
607 length = 0;
610 if (length)
611 pos = 36 * (elapsed + state->ff_rewind_count) / length;
613 for (i = 0; i < 7; i++, pos -= 5)
615 if (pos <= 0)
616 progress_pattern[i] = 0x1fu;
617 else if (pos >= 5)
618 progress_pattern[i] = 0x00u;
619 else
620 progress_pattern[i] = 0x1fu >> pos;
623 display->define_pattern(gwps->data->wps_progress_pat[0], progress_pattern);
626 static void format_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
628 static const unsigned char numbers[10][4] = {
629 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
630 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
631 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
632 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
633 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
634 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
635 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
636 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
637 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
638 {0x0e, 0x0e, 0x02, 0x0e} /* 9 */
641 struct wps_state *state = skin_get_global_state();
642 struct screen *display = gwps->display;
643 struct wps_data *data = gwps->data;
644 unsigned char progress_pattern[7];
645 char timestr[10];
646 int time;
647 int time_idx = 0;
648 int pos = 0;
649 int pat_idx = 1;
650 int digit, i, j;
651 bool softchar;
653 int elapsed, length;
654 if (LIKELY(state->id3))
656 elapsed = state->id3->elapsed;
657 length = state->id3->length;
659 else
661 elapsed = 0;
662 length = 0;
665 if (buf_size < 34) /* worst case: 11x UTF-8 char + \0 */
666 return;
668 time = elapsed + state->ff_rewind_count;
669 if (length)
670 pos = 55 * time / length;
672 memset(timestr, 0, sizeof(timestr));
673 format_time(timestr, sizeof(timestr)-2, time);
674 timestr[strlen(timestr)] = ':'; /* always safe */
676 for (i = 0; i < 11; i++, pos -= 5)
678 softchar = false;
679 memset(progress_pattern, 0, sizeof(progress_pattern));
681 if ((digit = timestr[time_idx]))
683 softchar = true;
684 digit -= '0';
686 if (timestr[time_idx + 1] == ':') /* ones, left aligned */
688 memcpy(progress_pattern, numbers[digit], 4);
689 time_idx += 2;
691 else /* tens, shifted right */
693 for (j = 0; j < 4; j++)
694 progress_pattern[j] = numbers[digit][j] >> 1;
696 if (time_idx > 0) /* not the first group, add colon in front */
698 progress_pattern[1] |= 0x10u;
699 progress_pattern[3] |= 0x10u;
701 time_idx++;
704 if (pos >= 5)
705 progress_pattern[5] = progress_pattern[6] = 0x1fu;
708 if (pos > 0 && pos < 5)
710 softchar = true;
711 progress_pattern[5] = progress_pattern[6] = (~0x1fu >> pos) & 0x1fu;
714 if (softchar && pat_idx < 8)
716 display->define_pattern(data->wps_progress_pat[pat_idx],
717 progress_pattern);
718 buf = utf8encode(data->wps_progress_pat[pat_idx], buf);
719 pat_idx++;
721 else if (pos <= 0)
722 buf = utf8encode(' ', buf);
723 else
724 buf = utf8encode(0xe115, buf); /* 2/7 _ */
726 *buf = '\0';
729 #endif /* HAVE_LCD_CHARCELLS */
731 /* Don't inline this; it was broken out of get_token_value to reduce stack
732 * usage.
734 static const char* NOINLINE get_lif_token_value(struct gui_wps *gwps,
735 struct logical_if *lif,
736 int offset, char *buf,
737 int buf_size)
739 int a = lif->num_options;
740 int b;
741 bool number_set = true;
742 struct wps_token *liftoken = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->token);
743 const char* out_text = get_token_value(gwps, liftoken, offset, buf, buf_size, &a);
744 if (a == -1 && liftoken->type != SKIN_TOKEN_VOLUME)
746 a = (out_text && *out_text) ? 1 : 0;
747 number_set = false;
749 switch (lif->operand.type)
751 case STRING:
753 char *cmp = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->operand.data.text);
754 if (out_text == NULL)
755 return NULL;
756 a = strcmp(out_text, cmp);
757 b = 0;
758 break;
760 case INTEGER:
761 if (!number_set && out_text && *out_text >= '0' && *out_text <= '9')
762 a = atoi(out_text);
763 /* fall through */
764 case PERCENT:
765 case DECIMAL:
766 b = lif->operand.data.number;
767 break;
768 case CODE:
770 char temp_buf[MAX_PATH];
771 const char *outb;
772 struct skin_element *element = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->operand.data.code);
773 struct wps_token *token = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), element->data);
774 b = lif->num_options;
775 outb = get_token_value(gwps, token, offset, temp_buf,
776 sizeof(temp_buf), &b);
777 if (b == -1 && liftoken->type != SKIN_TOKEN_VOLUME)
779 if (!out_text || !outb)
780 return (lif->op == IF_EQUALS) ? NULL : "neq";
781 bool equal = strcmp(out_text, outb) == 0;
782 if (lif->op == IF_EQUALS)
783 return equal ? "eq" : NULL;
784 else if (lif->op == IF_NOTEQUALS)
785 return !equal ? "neq" : NULL;
786 else
787 b = (outb && *outb) ? 1 : 0;
790 break;
791 case DEFAULT:
792 break;
795 switch (lif->op)
797 case IF_EQUALS:
798 return a == b ? "eq" : NULL;
799 case IF_NOTEQUALS:
800 return a != b ? "neq" : NULL;
801 case IF_LESSTHAN:
802 return a < b ? "lt" : NULL;
803 case IF_LESSTHAN_EQ:
804 return a <= b ? "lte" : NULL;
805 case IF_GREATERTHAN:
806 return a > b ? "gt" : NULL;
807 case IF_GREATERTHAN_EQ:
808 return a >= b ? "gte" : NULL;
810 return NULL;
813 /* Return the tags value as text. buf should be used as temp storage if needed.
815 intval is used with conditionals/enums: when this function is called,
816 intval should contain the number of options in the conditional/enum.
817 When this function returns, intval is -1 if the tag is non numeric or,
818 if the tag is numeric, *intval is the enum case we want to go to (between 1
819 and the original value of *intval, inclusive).
820 When not treating a conditional/enum, intval should be NULL.
822 const char *get_token_value(struct gui_wps *gwps,
823 struct wps_token *token, int offset,
824 char *buf, int buf_size,
825 int *intval)
827 if (!gwps)
828 return NULL;
830 struct wps_data *data = gwps->data;
831 struct wps_state *state = skin_get_global_state();
832 struct mp3entry *id3; /* Think very carefully about using this.
833 maybe get_id3_token() is the better place? */
834 const char *out_text = NULL;
835 char *filename = NULL;
837 if (!data || !state)
838 return NULL;
840 id3 = get_mp3entry_from_offset(token->next? 1: offset, &filename);
841 if (id3)
842 filename = id3->path;
844 #if CONFIG_RTC
845 struct tm* tm = NULL;
847 /* if the token is an RTC one, update the time
848 and do the necessary checks */
849 if (token->type >= SKIN_TOKENS_RTC_BEGIN
850 && token->type <= SKIN_TOKENS_RTC_END)
852 tm = get_time();
854 if (!valid_time(tm))
855 return NULL;
857 #endif
859 int limit = 1;
860 if (intval)
862 limit = *intval;
863 *intval = -1;
866 if (id3 && id3 == state->id3 && id3->cuesheet )
868 out_text = get_cuesheetid3_token(token, id3,
869 token->next?1:offset, buf, buf_size);
870 if (out_text)
871 return out_text;
873 out_text = get_id3_token(token, id3, filename, buf, buf_size, limit, intval);
874 if (out_text)
875 return out_text;
876 #if CONFIG_TUNER
877 out_text = get_radio_token(token, offset, buf, buf_size, limit, intval);
878 if (out_text)
879 return out_text;
880 #endif
882 switch (token->type)
884 case SKIN_TOKEN_LOGICAL_IF:
886 struct logical_if *lif = SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
887 return get_lif_token_value(gwps, lif, offset, buf, buf_size);
889 break;
890 case SKIN_TOKEN_LOGICAL_AND:
891 case SKIN_TOKEN_LOGICAL_OR:
893 int i = 0, truecount = 0;
894 char *skinbuffer = get_skin_buffer(data);
895 struct skin_element *element =
896 SKINOFFSETTOPTR(skinbuffer, token->value.data);
897 struct skin_tag_parameter* params =
898 SKINOFFSETTOPTR(skinbuffer, element->params);
899 struct skin_tag_parameter* thistag;
900 for (i=0; i<element->params_count; i++)
902 thistag = &params[i];
903 struct skin_element *tokenelement =
904 SKINOFFSETTOPTR(skinbuffer, thistag->data.code);
905 out_text = get_token_value(gwps,
906 SKINOFFSETTOPTR(skinbuffer, tokenelement->data),
907 offset, buf, buf_size, intval);
908 if (out_text && *out_text)
909 truecount++;
910 else if (token->type == SKIN_TOKEN_LOGICAL_AND)
911 return NULL;
913 return truecount ? "true" : NULL;
915 break;
916 case SKIN_TOKEN_SUBSTRING:
918 struct substring *ss = SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
919 const char *token_val = get_token_value(gwps,
920 SKINOFFSETTOPTR(get_skin_buffer(data), ss->token), offset,
921 buf, buf_size, intval);
922 if (token_val)
924 int start_byte, end_byte, byte_len;
925 int utf8_len = utf8length(token_val);
927 if (utf8_len < ss->start)
928 return NULL;
930 if (ss->start < 0)
931 start_byte = utf8seek(token_val, ss->start + utf8_len);
932 else
933 start_byte = utf8seek(token_val, ss->start);
935 if (ss->length < 0 || (ss->start + ss->length) > utf8_len)
936 end_byte = strlen(token_val);
937 else
938 end_byte = utf8seek(token_val, ss->start + ss->length);
940 byte_len = end_byte - start_byte;
942 if (token_val != buf)
943 memcpy(buf, &token_val[start_byte], byte_len);
944 else
945 buf = &buf[start_byte];
947 buf[byte_len] = '\0';
948 if (ss->expect_number &&
949 intval && (buf[0] >= '0' && buf[0] <= '9'))
950 *intval = atoi(buf) + 1; /* so 0 is the first item */
952 return buf;
954 return NULL;
956 break;
958 case SKIN_TOKEN_CHARACTER:
959 if (token->value.c == '\n')
960 return NULL;
961 return &(token->value.c);
963 case SKIN_TOKEN_STRING:
964 return (char*)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
966 case SKIN_TOKEN_TRANSLATEDSTRING:
967 return (char*)P2STR(ID2P(token->value.i));
969 case SKIN_TOKEN_PLAYLIST_ENTRIES:
970 snprintf(buf, buf_size, "%d", playlist_amount());
971 if (intval)
972 *intval = playlist_amount();
973 return buf;
974 #ifdef HAVE_LCD_BITMAP
975 case SKIN_TOKEN_LIST_TITLE_TEXT:
976 return sb_get_title(gwps->display->screen_type);
977 case SKIN_TOKEN_LIST_TITLE_ICON:
978 if (intval)
979 *intval = sb_get_icon(gwps->display->screen_type);
980 snprintf(buf, buf_size, "%d",sb_get_icon(gwps->display->screen_type));
981 return buf;
982 case SKIN_TOKEN_LIST_ITEM_TEXT:
984 struct listitem *li = (struct listitem *)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
985 return skinlist_get_item_text(li->offset, li->wrap, buf, buf_size);
987 case SKIN_TOKEN_LIST_ITEM_ROW:
988 if (intval)
989 *intval = skinlist_get_item_row() + 1;
990 snprintf(buf, buf_size, "%d",skinlist_get_item_row() + 1);
991 return buf;
992 case SKIN_TOKEN_LIST_ITEM_COLUMN:
993 if (intval)
994 *intval = skinlist_get_item_column() + 1;
995 snprintf(buf, buf_size, "%d",skinlist_get_item_column() + 1);
996 return buf;
997 case SKIN_TOKEN_LIST_ITEM_NUMBER:
998 if (intval)
999 *intval = skinlist_get_item_number() + 1;
1000 snprintf(buf, buf_size, "%d",skinlist_get_item_number() + 1);
1001 return buf;
1002 case SKIN_TOKEN_LIST_ITEM_IS_SELECTED:
1003 return skinlist_is_selected_item()?"s":"";
1004 case SKIN_TOKEN_LIST_ITEM_ICON:
1006 struct listitem *li = (struct listitem *)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
1007 int icon = skinlist_get_item_icon(li->offset, li->wrap);
1008 if (intval)
1009 *intval = icon;
1010 snprintf(buf, buf_size, "%d", icon);
1011 return buf;
1013 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR:
1014 return skinlist_needs_scrollbar(gwps->display->screen_type) ? "s" : "";
1015 #endif
1016 case SKIN_TOKEN_PLAYLIST_NAME:
1017 return playlist_name(NULL, buf, buf_size);
1019 case SKIN_TOKEN_PLAYLIST_POSITION:
1020 snprintf(buf, buf_size, "%d", playlist_get_display_index()+offset);
1021 if (intval)
1022 *intval = playlist_get_display_index()+offset;
1023 return buf;
1025 case SKIN_TOKEN_PLAYLIST_SHUFFLE:
1026 if ( global_settings.playlist_shuffle )
1027 return "s";
1028 else
1029 return NULL;
1030 break;
1032 case SKIN_TOKEN_VOLUME:
1033 snprintf(buf, buf_size, "%d", global_settings.volume);
1034 if (intval)
1036 int minvol = sound_min(SOUND_VOLUME);
1037 if (limit == TOKEN_VALUE_ONLY)
1039 *intval = global_settings.volume;
1041 else if (global_settings.volume == minvol)
1043 *intval = 1;
1045 else if (global_settings.volume == 0)
1047 *intval = limit - 1;
1049 else if (global_settings.volume > 0)
1051 *intval = limit;
1053 else
1055 *intval = (limit-3) * (global_settings.volume - minvol - 1)
1056 / (-1 - minvol) + 2;
1059 return buf;
1060 #ifdef HAVE_ALBUMART
1061 case SKIN_TOKEN_ALBUMART_FOUND:
1062 if (SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart))
1064 int handle = -1;
1065 handle = playback_current_aa_hid(data->playback_aa_slot);
1066 #if CONFIG_TUNER
1067 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
1069 struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart);
1070 struct dim dim = {aa->width, aa->height};
1071 handle = radio_get_art_hid(&dim);
1073 #endif
1074 if (handle >= 0)
1075 return "C";
1077 return NULL;
1078 #endif
1080 case SKIN_TOKEN_BATTERY_PERCENT:
1082 int l = battery_level();
1084 if (intval)
1086 if (limit == TOKEN_VALUE_ONLY)
1088 *intval = l;
1090 else
1092 limit = MAX(limit, 3);
1093 if (l > -1) {
1094 /* First enum is used for "unknown level",
1095 * last enum is used for 100%.
1097 *intval = (limit - 2) * l / 100 + 2;
1098 } else {
1099 *intval = 1;
1104 if (l > -1) {
1105 snprintf(buf, buf_size, "%d", l);
1106 return buf;
1107 } else {
1108 return "?";
1112 case SKIN_TOKEN_BATTERY_VOLTS:
1114 int v = battery_voltage();
1115 if (v >= 0) {
1116 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
1117 return buf;
1118 } else {
1119 return "?";
1123 case SKIN_TOKEN_BATTERY_TIME:
1125 int t = battery_time();
1126 if (t >= 0)
1127 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
1128 else
1129 return "?h ?m";
1130 return buf;
1133 #if CONFIG_CHARGING
1134 case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED:
1136 if(charger_input_state==CHARGER)
1137 return "p";
1138 else
1139 return NULL;
1141 #endif
1142 #if CONFIG_CHARGING >= CHARGING_MONITOR
1143 case SKIN_TOKEN_BATTERY_CHARGING:
1145 if (charge_state == CHARGING || charge_state == TOPOFF) {
1146 return "c";
1147 } else {
1148 return NULL;
1151 #endif
1152 #ifdef HAVE_USB_POWER
1153 case SKIN_TOKEN_USB_POWERED:
1154 if (usb_powered())
1155 return "u";
1156 return NULL;
1157 #endif
1158 case SKIN_TOKEN_BATTERY_SLEEPTIME:
1160 if (get_sleep_timer() == 0)
1161 return NULL;
1162 else
1164 format_time(buf, buf_size, get_sleep_timer() * 1000);
1165 return buf;
1169 case SKIN_TOKEN_PLAYBACK_STATUS:
1171 int status = current_playmode();
1172 /* music */
1173 int mode = 1; /* stop */
1174 if (status == STATUS_PLAY)
1175 mode = 2; /* play */
1176 if (state->is_fading ||
1177 (status == STATUS_PAUSE && !status_get_ffmode()))
1178 mode = 3; /* pause */
1179 else
1180 { /* ff / rwd */
1181 if (status_get_ffmode() == STATUS_FASTFORWARD)
1182 mode = 4;
1183 if (status_get_ffmode() == STATUS_FASTBACKWARD)
1184 mode = 5;
1186 #ifdef HAVE_RECORDING
1187 /* recording */
1188 if (status == STATUS_RECORD)
1189 mode = 6;
1190 else if (status == STATUS_RECORD_PAUSE)
1191 mode = 7;
1192 #endif
1193 #if CONFIG_TUNER
1194 /* radio */
1195 if (status == STATUS_RADIO)
1196 mode = 8;
1197 else if (status == STATUS_RADIO_PAUSE)
1198 mode = 9;
1199 #endif
1201 if (intval) {
1202 *intval = mode;
1205 snprintf(buf, buf_size, "%d", mode-1);
1206 return buf;
1209 case SKIN_TOKEN_REPEAT_MODE:
1210 if (intval)
1211 *intval = global_settings.repeat_mode + 1;
1212 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
1213 return buf;
1215 case SKIN_TOKEN_RTC_PRESENT:
1216 #if CONFIG_RTC
1217 return "c";
1218 #else
1219 return NULL;
1220 #endif
1222 #if CONFIG_RTC
1223 case SKIN_TOKEN_RTC_12HOUR_CFG:
1224 if (intval)
1225 *intval = global_settings.timeformat + 1;
1226 snprintf(buf, buf_size, "%d", global_settings.timeformat);
1227 return buf;
1229 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1230 /* d: day of month (01..31) */
1231 snprintf(buf, buf_size, "%02d", tm->tm_mday);
1232 if (intval)
1233 *intval = tm->tm_mday - 1;
1234 return buf;
1236 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1237 /* e: day of month, blank padded ( 1..31) */
1238 snprintf(buf, buf_size, "%2d", tm->tm_mday);
1239 if (intval)
1240 *intval = tm->tm_mday - 1;
1241 return buf;
1243 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1244 /* H: hour (00..23) */
1245 snprintf(buf, buf_size, "%02d", tm->tm_hour);
1246 if (intval)
1247 *intval = tm->tm_hour;
1248 return buf;
1250 case SKIN_TOKEN_RTC_HOUR_24:
1251 /* k: hour ( 0..23) */
1252 snprintf(buf, buf_size, "%2d", tm->tm_hour);
1253 if (intval)
1254 *intval = tm->tm_hour;
1255 return buf;
1257 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1258 /* I: hour (01..12) */
1259 snprintf(buf, buf_size, "%02d",
1260 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1261 if (intval)
1262 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1263 return buf;
1265 case SKIN_TOKEN_RTC_HOUR_12:
1266 /* l: hour ( 1..12) */
1267 snprintf(buf, buf_size, "%2d",
1268 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1269 if (intval)
1270 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1271 return buf;
1273 case SKIN_TOKEN_RTC_MONTH:
1274 /* m: month (01..12) */
1275 if (intval)
1276 *intval = tm->tm_mon + 1;
1277 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
1278 return buf;
1280 case SKIN_TOKEN_RTC_MINUTE:
1281 /* M: minute (00..59) */
1282 snprintf(buf, buf_size, "%02d", tm->tm_min);
1283 if (intval)
1284 *intval = tm->tm_min;
1285 return buf;
1287 case SKIN_TOKEN_RTC_SECOND:
1288 /* S: second (00..59) */
1289 snprintf(buf, buf_size, "%02d", tm->tm_sec);
1290 if (intval)
1291 *intval = tm->tm_sec;
1292 return buf;
1294 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1295 /* y: last two digits of year (00..99) */
1296 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
1297 if (intval)
1298 *intval = tm->tm_year % 100;
1299 return buf;
1301 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1302 /* Y: year (1970...) */
1303 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
1304 if (intval)
1305 *intval = tm->tm_year + 1900;
1306 return buf;
1308 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1309 /* p: upper case AM or PM indicator */
1310 if (intval)
1311 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1312 return tm->tm_hour/12 == 0 ? "AM" : "PM";
1314 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1315 /* P: lower case am or pm indicator */
1316 if (intval)
1317 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1318 return tm->tm_hour/12 == 0 ? "am" : "pm";
1320 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1321 /* a: abbreviated weekday name (Sun..Sat) */
1322 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
1324 case SKIN_TOKEN_RTC_MONTH_NAME:
1325 /* b: abbreviated month name (Jan..Dec) */
1326 return str(LANG_MONTH_JANUARY + tm->tm_mon);
1328 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1329 /* u: day of week (1..7); 1 is Monday */
1330 if (intval)
1331 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
1332 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
1333 return buf;
1335 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1336 /* w: day of week (0..6); 0 is Sunday */
1337 if (intval)
1338 *intval = tm->tm_wday + 1;
1339 snprintf(buf, buf_size, "%1d", tm->tm_wday);
1340 return buf;
1341 #else
1342 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1343 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1344 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1345 case SKIN_TOKEN_RTC_HOUR_24:
1346 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1347 case SKIN_TOKEN_RTC_HOUR_12:
1348 case SKIN_TOKEN_RTC_MONTH:
1349 case SKIN_TOKEN_RTC_MINUTE:
1350 case SKIN_TOKEN_RTC_SECOND:
1351 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1352 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1353 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1354 return "--";
1355 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1356 return "----";
1357 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1358 case SKIN_TOKEN_RTC_MONTH_NAME:
1359 return "---";
1360 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1361 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1362 return "-";
1363 #endif
1365 #ifdef HAVE_LCD_CHARCELLS
1366 case SKIN_TOKEN_PROGRESSBAR:
1368 char *end;
1369 format_player_progress(gwps);
1370 end = utf8encode(data->wps_progress_pat[0], buf);
1371 *end = '\0';
1372 return buf;
1375 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1376 if(is_new_player())
1378 /* we need 11 characters (full line) for
1379 progress-bar */
1380 strlcpy(buf, " ", buf_size);
1381 format_player_fullbar(gwps,buf,buf_size);
1382 DEBUGF("bar='%s'\n",buf);
1384 else
1386 /* Tell the user if we have an OldPlayer */
1387 strlcpy(buf, " <Old LCD> ", buf_size);
1389 return buf;
1390 #endif
1393 #ifdef HAVE_LCD_BITMAP
1394 /* peakmeter */
1395 case SKIN_TOKEN_PEAKMETER_LEFT:
1396 case SKIN_TOKEN_PEAKMETER_RIGHT:
1398 int left, right, val;
1399 peak_meter_current_vals(&left, &right);
1400 val = token->type == SKIN_TOKEN_PEAKMETER_LEFT ?
1401 left : right;
1402 val = peak_meter_scale_value(val, limit==1 ? MAX_PEAK : limit);
1403 if (intval)
1404 *intval = val;
1405 snprintf(buf, buf_size, "%d", val);
1406 data->peak_meter_enabled = true;
1407 return buf;
1409 #endif
1411 #if (CONFIG_CODEC == SWCODEC)
1412 case SKIN_TOKEN_CROSSFADE:
1413 #ifdef HAVE_CROSSFADE
1414 if (intval)
1415 *intval = global_settings.crossfade + 1;
1416 snprintf(buf, buf_size, "%d", global_settings.crossfade);
1417 #else
1418 snprintf(buf, buf_size, "%d", 0);
1419 #endif
1420 return buf;
1422 case SKIN_TOKEN_REPLAYGAIN:
1424 int globtype = global_settings.replaygain_settings.type;
1425 int val;
1428 if (globtype == REPLAYGAIN_OFF)
1429 val = 1; /* off */
1430 else
1432 int type = id3_get_replaygain_mode(id3);
1434 if (type < 0)
1435 val = 6; /* no tag */
1436 else
1437 val = type + 2;
1439 if (globtype == REPLAYGAIN_SHUFFLE)
1440 val += 2;
1443 if (intval)
1444 *intval = val;
1446 switch (val)
1448 case 1:
1449 case 6:
1450 return "+0.00 dB";
1451 break;
1452 /* due to above, coming here with !id3 shouldn't be possible */
1453 case 2:
1454 case 4:
1455 replaygain_itoa(buf, buf_size, id3->track_level);
1456 break;
1457 case 3:
1458 case 5:
1459 replaygain_itoa(buf, buf_size, id3->album_level);
1460 break;
1462 return buf;
1464 #endif /* (CONFIG_CODEC == SWCODEC) */
1466 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHCONTROL)
1467 case SKIN_TOKEN_SOUND_PITCH:
1469 int32_t pitch = sound_get_pitch();
1470 snprintf(buf, buf_size, "%ld.%ld",
1471 pitch / PITCH_SPEED_PRECISION,
1472 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1474 if (intval)
1475 *intval = pitch_speed_enum(limit, pitch,
1476 PITCH_SPEED_PRECISION * 100);
1477 return buf;
1479 #endif
1481 #if (CONFIG_CODEC == SWCODEC) && defined (HAVE_PITCHCONTROL)
1482 case SKIN_TOKEN_SOUND_SPEED:
1484 int32_t pitch = sound_get_pitch();
1485 int32_t speed;
1486 if (dsp_timestretch_available())
1487 speed = GET_SPEED(pitch, dsp_get_timestretch());
1488 else
1489 speed = pitch;
1490 snprintf(buf, buf_size, "%ld.%ld",
1491 speed / PITCH_SPEED_PRECISION,
1492 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1493 if (intval)
1494 *intval = pitch_speed_enum(limit, speed,
1495 PITCH_SPEED_PRECISION * 100);
1496 return buf;
1498 #endif
1500 case SKIN_TOKEN_MAIN_HOLD:
1501 #ifdef HAVE_TOUCHSCREEN
1502 if (data->touchscreen_locked)
1503 return "t";
1504 #endif
1505 #ifdef HAS_BUTTON_HOLD
1506 if (button_hold())
1507 #else
1508 if (is_keys_locked())
1509 #endif /*hold switch or softlock*/
1510 return "h";
1511 else
1512 return NULL;
1514 #ifdef HAS_REMOTE_BUTTON_HOLD
1515 case SKIN_TOKEN_REMOTE_HOLD:
1516 if (remote_button_hold())
1517 return "r";
1518 else
1519 return NULL;
1520 #endif
1522 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1523 case SKIN_TOKEN_VLED_HDD:
1524 if(led_read(HZ/2))
1525 return "h";
1526 else
1527 return NULL;
1528 #endif
1529 case SKIN_TOKEN_BUTTON_VOLUME:
1530 if (global_status.last_volume_change &&
1531 TIME_BEFORE(current_tick, global_status.last_volume_change +
1532 token->value.i))
1533 return "v";
1534 return NULL;
1536 case SKIN_TOKEN_LASTTOUCH:
1538 #ifdef HAVE_TOUCHSCREEN
1539 unsigned int last_touch = touchscreen_last_touch();
1540 char *skin_base = get_skin_buffer(data);
1541 struct touchregion_lastpress *data = SKINOFFSETTOPTR(skin_base, token->value.data);
1542 struct touchregion *region = SKINOFFSETTOPTR(skin_base, data->region);
1543 if (region)
1544 last_touch = region->last_press;
1546 if (last_touch != 0xffff &&
1547 TIME_BEFORE(current_tick, data->timeout + last_touch))
1548 return "t";
1549 #endif
1551 return NULL;
1552 case SKIN_TOKEN_HAVE_TOUCH:
1553 #ifdef HAVE_TOUCHSCREEN
1554 return "t";
1555 #else
1556 return NULL;
1557 #endif
1559 case SKIN_TOKEN_SETTING:
1561 const struct settings_list *s = settings+token->value.i;
1562 if (intval)
1564 /* Handle contionals */
1565 switch (s->flags&F_T_MASK)
1567 case F_T_INT:
1568 case F_T_UINT:
1569 if (s->flags&F_T_SOUND)
1571 /* %?St|name|<min|min+1|...|max-1|max> */
1572 int sound_setting = s->sound_setting->setting;
1573 /* settings with decimals can't be used in conditionals */
1574 if (sound_numdecimals(sound_setting) == 0)
1576 *intval = (*(int*)s->setting-sound_min(sound_setting))
1577 /sound_steps(sound_setting) + 1;
1579 else
1580 *intval = -1;
1582 else if (s->flags&F_RGB)
1583 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1584 /* shouldn't overflow since colors are stored
1585 * on 16 bits ...
1586 * but this is pretty useless anyway */
1587 *intval = *(int*)s->setting + 1;
1588 else if (s->cfg_vals == NULL)
1589 /* %?St|name|<1st choice|2nd choice|...> */
1590 *intval = (*(int*)s->setting-s->int_setting->min)
1591 /s->int_setting->step + 1;
1592 else
1593 /* %?St|name|<1st choice|2nd choice|...> */
1594 /* Not sure about this one. cfg_name/vals are
1595 * indexed from 0 right? */
1596 *intval = *(int*)s->setting + 1;
1597 break;
1598 case F_T_BOOL:
1599 /* %?St|name|<if true|if false> */
1600 *intval = *(bool*)s->setting?1:2;
1601 break;
1602 case F_T_CHARPTR:
1603 case F_T_UCHARPTR:
1604 /* %?St|name|<if non empty string|if empty>
1605 * The string's emptyness discards the setting's
1606 * prefix and suffix */
1607 *intval = ((char*)s->setting)[0]?1:2;
1608 /* if there is a prefix we should ignore it here */
1609 if (s->filename_setting->prefix)
1610 return (char*)s->setting;
1611 break;
1612 default:
1613 /* This shouldn't happen ... but you never know */
1614 *intval = -1;
1615 break;
1618 /* Special handlng for filenames because we dont want to show the prefix */
1619 if ((s->flags&F_T_MASK) == F_T_CHARPTR ||
1620 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1622 if (s->filename_setting->prefix)
1623 return (char*)s->setting;
1625 cfg_to_string(token->value.i,buf,buf_size);
1626 return buf;
1628 case SKIN_TOKEN_HAVE_TUNER:
1629 #if CONFIG_TUNER
1630 if (radio_hardware_present())
1631 return "r";
1632 #endif
1633 return NULL;
1634 /* Recording tokens */
1635 case SKIN_TOKEN_HAVE_RECORDING:
1636 #ifdef HAVE_RECORDING
1637 return "r";
1638 #else
1639 return NULL;
1640 #endif
1642 #ifdef HAVE_RECORDING
1643 case SKIN_TOKEN_IS_RECORDING:
1644 if (audio_status() == AUDIO_STATUS_RECORD)
1645 return "r";
1646 return NULL;
1647 case SKIN_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1649 #if CONFIG_CODEC == SWCODEC
1650 unsigned long samprk;
1651 int rec_freq = global_settings.rec_frequency;
1653 #ifdef SIMULATOR
1654 samprk = 44100;
1655 #else
1656 #if defined(HAVE_SPDIF_REC)
1657 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1659 /* Use rate in use, not current measured rate if it changed */
1660 samprk = pcm_rec_sample_rate();
1661 rec_freq = 0;
1662 while (rec_freq < SAMPR_NUM_FREQ &&
1663 audio_master_sampr_list[rec_freq] != samprk)
1665 rec_freq++;
1668 else
1669 #endif
1670 samprk = rec_freq_sampr[rec_freq];
1671 #endif /* SIMULATOR */
1672 if (intval)
1674 switch (rec_freq)
1676 REC_HAVE_96_(case REC_FREQ_96:
1677 *intval = 1;
1678 break;)
1679 REC_HAVE_88_(case REC_FREQ_88:
1680 *intval = 2;
1681 break;)
1682 REC_HAVE_64_(case REC_FREQ_64:
1683 *intval = 3;
1684 break;)
1685 REC_HAVE_48_(case REC_FREQ_48:
1686 *intval = 4;
1687 break;)
1688 REC_HAVE_44_(case REC_FREQ_44:
1689 *intval = 5;
1690 break;)
1691 REC_HAVE_32_(case REC_FREQ_32:
1692 *intval = 6;
1693 break;)
1694 REC_HAVE_24_(case REC_FREQ_24:
1695 *intval = 7;
1696 break;)
1697 REC_HAVE_22_(case REC_FREQ_22:
1698 *intval = 8;
1699 break;)
1700 REC_HAVE_16_(case REC_FREQ_16:
1701 *intval = 9;
1702 break;)
1703 REC_HAVE_12_(case REC_FREQ_12:
1704 *intval = 10;
1705 break;)
1706 REC_HAVE_11_(case REC_FREQ_11:
1707 *intval = 11;
1708 break;)
1709 REC_HAVE_8_(case REC_FREQ_8:
1710 *intval = 12;
1711 break;)
1714 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1715 #else /* HWCODEC */
1717 static const char * const freq_strings[] =
1718 {"--", "44", "48", "32", "22", "24", "16"};
1719 int freq = 1 + global_settings.rec_frequency;
1720 #ifdef HAVE_SPDIF_REC
1721 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1723 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1724 freq = 0;
1726 #endif /* HAVE_SPDIF_IN */
1727 if (intval)
1728 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1729 snprintf(buf, buf_size, "%s\n",
1730 freq_strings[global_settings.rec_frequency]);
1731 #endif
1732 return buf;
1734 #if CONFIG_CODEC == SWCODEC
1735 case SKIN_TOKEN_REC_ENCODER:
1737 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1738 if (intval)
1739 *intval = rec_format;
1740 switch (rec_format)
1742 case REC_FORMAT_PCM_WAV:
1743 return "wav";
1744 case REC_FORMAT_AIFF:
1745 return "aiff";
1746 case REC_FORMAT_WAVPACK:
1747 return "wv";
1748 case REC_FORMAT_MPA_L3:
1749 return "MP3";
1750 default:
1751 return NULL;
1753 break;
1755 #endif
1756 case SKIN_TOKEN_REC_BITRATE:
1757 #if CONFIG_CODEC == SWCODEC
1758 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1760 if (intval)
1762 #if 0 /* FIXME: I dont know if this is needed? */
1763 switch (1<<global_settings.mp3_enc_config.bitrate)
1765 case MP3_BITR_CAP_8:
1766 *intval = 1;
1767 break;
1768 case MP3_BITR_CAP_16:
1769 *intval = 2;
1770 break;
1771 case MP3_BITR_CAP_24:
1772 *intval = 3;
1773 break;
1774 case MP3_BITR_CAP_32:
1775 *intval = 4;
1776 break;
1777 case MP3_BITR_CAP_40:
1778 *intval = 5;
1779 break;
1780 case MP3_BITR_CAP_48:
1781 *intval = 6;
1782 break;
1783 case MP3_BITR_CAP_56:
1784 *intval = 7;
1785 break;
1786 case MP3_BITR_CAP_64:
1787 *intval = 8;
1788 break;
1789 case MP3_BITR_CAP_80:
1790 *intval = 9;
1791 break;
1792 case MP3_BITR_CAP_96:
1793 *intval = 10;
1794 break;
1795 case MP3_BITR_CAP_112:
1796 *intval = 11;
1797 break;
1798 case MP3_BITR_CAP_128:
1799 *intval = 12;
1800 break;
1801 case MP3_BITR_CAP_144:
1802 *intval = 13;
1803 break;
1804 case MP3_BITR_CAP_160:
1805 *intval = 14;
1806 break;
1807 case MP3_BITR_CAP_192:
1808 *intval = 15;
1809 break;
1811 #endif
1812 *intval = global_settings.mp3_enc_config.bitrate+1;
1814 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1815 return buf;
1817 else
1818 return NULL; /* Fixme later */
1819 #else /* CONFIG_CODEC == HWCODEC */
1820 if (intval)
1821 *intval = global_settings.rec_quality+1;
1822 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1823 return buf;
1824 #endif
1825 case SKIN_TOKEN_REC_MONO:
1826 if (!global_settings.rec_channels)
1827 return "m";
1828 return NULL;
1830 case SKIN_TOKEN_REC_SECONDS:
1832 int time = (audio_recorded_time() / HZ) % 60;
1833 if (intval)
1834 *intval = time;
1835 snprintf(buf, buf_size, "%02d", time);
1836 return buf;
1838 case SKIN_TOKEN_REC_MINUTES:
1840 int time = (audio_recorded_time() / HZ) / 60;
1841 if (intval)
1842 *intval = time;
1843 snprintf(buf, buf_size, "%02d", time);
1844 return buf;
1846 case SKIN_TOKEN_REC_HOURS:
1848 int time = (audio_recorded_time() / HZ) / 3600;
1849 if (intval)
1850 *intval = time;
1851 snprintf(buf, buf_size, "%02d", time);
1852 return buf;
1855 #endif /* HAVE_RECORDING */
1857 case SKIN_TOKEN_CURRENT_SCREEN:
1859 int curr_screen = get_current_activity();
1860 if (intval)
1862 *intval = curr_screen;
1864 snprintf(buf, buf_size, "%d", curr_screen);
1865 return buf;
1868 case SKIN_TOKEN_LANG_IS_RTL:
1869 return lang_is_rtl() ? "r" : NULL;
1871 #ifdef HAVE_SKIN_VARIABLES
1872 case SKIN_TOKEN_VAR_GETVAL:
1874 char *skin_base = get_skin_buffer(data);
1875 struct skin_var* var = SKINOFFSETTOPTR(skin_base, token->value.data);
1876 if (intval)
1877 *intval = var->value;
1878 snprintf(buf, buf_size, "%d", var->value);
1879 return buf;
1881 break;
1882 case SKIN_TOKEN_VAR_TIMEOUT:
1884 char *skin_base = get_skin_buffer(data);
1885 struct skin_var_lastchange *data = SKINOFFSETTOPTR(skin_base, token->value.data);
1886 struct skin_var* var = SKINOFFSETTOPTR(skin_base, data->var);
1887 unsigned int last_change = var->last_changed;
1889 if (last_change != 0xffff &&
1890 TIME_BEFORE(current_tick, data->timeout + last_change))
1891 return "t";
1893 return NULL;
1894 #endif
1896 default:
1897 return NULL;