skin engine: New logical 'and' and 'or' tags to evaluate multiple tags in a single...
[maemo-rb.git] / apps / gui / skin_engine / skin_tokens.c
blob82d96f6993c9b59a73769bab36a6f2e27d2224aa
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 "dsp.h"
53 #include "playlist.h"
54 #if CONFIG_CODEC == SWCODEC
55 #include "playback.h"
56 #include "tdspeed.h"
57 #endif
58 #include "viewport.h"
59 #include "tagcache.h"
61 #include "wps_internals.h"
62 #include "skin_engine.h"
63 #include "statusbar-skinned.h"
64 #include "root_menu.h"
65 #ifdef HAVE_RECORDING
66 #include "recording.h"
67 #include "pcm_record.h"
68 #endif
69 #include "language.h"
70 #include "usb.h"
71 #if CONFIG_TUNER
72 #include "radio.h"
73 #include "tuner.h"
74 #endif
75 #include "list.h"
77 #define NOINLINE __attribute__ ((noinline))
79 extern struct wps_state wps_state;
81 static const char* get_codectype(const struct mp3entry* id3)
83 if (id3 && id3->codectype < AFMT_NUM_CODECS) {
84 return audio_formats[id3->codectype].label;
85 } else {
86 return NULL;
90 /* Extract a part from a path.
92 * buf - buffer extract part to.
93 * buf_size - size of buffer.
94 * path - path to extract from.
95 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
96 * parent of parent, etc.
98 * Returns buf if the desired level was found, NULL otherwise.
100 char* get_dir(char* buf, int buf_size, const char* path, int level)
102 const char* sep;
103 const char* last_sep;
104 int len;
106 sep = path + strlen(path);
107 last_sep = sep;
109 while (sep > path)
111 if ('/' == *(--sep))
113 if (!level)
114 break;
116 level--;
117 last_sep = sep - 1;
121 if (level || (last_sep <= sep))
122 return NULL;
124 len = MIN(last_sep - sep, buf_size - 1);
125 strlcpy(buf, sep + 1, len + 1);
126 return buf;
129 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHSCREEN)
130 /* A helper to determine the enum value for pitch/speed.
132 When there are two choices (i.e. boolean), return 1 if the value is
133 different from normal value and 2 if the value is the same as the
134 normal value. E.g. "%?Sp<%Sp>" would show the pitch only when
135 playing at a modified pitch.
137 When there are more than two choices (i.e. enum), the left half of
138 the choices are to show 0..normal range, and the right half of the
139 choices are to show values over that. The last entry is used when
140 it is set to the normal setting, following the rockbox convention
141 to use the last entry for special values.
143 E.g.
145 2 items: %?Sp<0..99 or 101..infinity|100>
146 3 items: %?Sp<0..99|101..infinity|100>
147 4 items: %?Sp<0..49|50..99|101..infinity|100>
148 5 items: %?Sp<0..49|50..99|101..149|150..infinity|100>
149 6 items: %?Sp<0..33|34..66|67..99|101..133|134..infinity|100>
150 7 items: %?Sp<0..33|34..66|67..99|101..133|134..167|167..infinity|100>
152 static int pitch_speed_enum(int range, int32_t val, int32_t normval)
154 int center;
155 int n;
157 if (range < 3)
158 return (val == normval) + 1;
159 if (val == normval)
160 return range;
161 center = range / 2;
162 n = (center * val) / normval + 1;
163 return (range <= n) ? (range - 1) : n;
165 #endif
167 const char *get_cuesheetid3_token(struct wps_token *token, struct mp3entry *id3,
168 int offset_tracks, char *buf, int buf_size)
170 struct cuesheet *cue = id3?id3->cuesheet:NULL;
171 if (!cue || !cue->curr_track)
172 return NULL;
174 struct cue_track_info *track = cue->curr_track;
175 if (offset_tracks)
177 if (cue->curr_track_idx+offset_tracks < cue->track_count)
178 track+=offset_tracks;
179 else
180 return NULL;
182 switch (token->type)
184 case SKIN_TOKEN_METADATA_ARTIST:
185 return *track->performer ? track->performer : NULL;
186 case SKIN_TOKEN_METADATA_COMPOSER:
187 return *track->songwriter ? track->songwriter : NULL;
188 case SKIN_TOKEN_METADATA_ALBUM:
189 return *cue->title ? cue->title : NULL;
190 case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
191 return *cue->performer ? cue->performer : NULL;
192 case SKIN_TOKEN_METADATA_TRACK_TITLE:
193 return *track->title ? track->title : NULL;
194 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
195 snprintf(buf, buf_size, "%d/%d",
196 cue->curr_track_idx+offset_tracks+1, cue->track_count);
197 return buf;
198 default:
199 return NULL;
201 return NULL;
204 static const char* get_filename_token(struct wps_token *token, char* filename,
205 char *buf, int buf_size)
207 if (filename)
209 switch (token->type)
211 case SKIN_TOKEN_FILE_PATH:
212 return filename;
213 case SKIN_TOKEN_FILE_NAME:
214 if (get_dir(buf, buf_size, filename, 0)) {
215 /* Remove extension */
216 char* sep = strrchr(buf, '.');
217 if (NULL != sep) {
218 *sep = 0;
220 return buf;
222 return NULL;
223 case SKIN_TOKEN_FILE_NAME_WITH_EXTENSION:
224 return get_dir(buf, buf_size, filename, 0);
225 case SKIN_TOKEN_FILE_DIRECTORY:
226 return get_dir(buf, buf_size, filename, token->value.i);
227 default:
228 return NULL;
231 return NULL;
234 /* All tokens which only need the info to return a value go in here */
235 const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
236 char *filename, char *buf, int buf_size, int limit, int *intval)
238 struct wps_state *state = &wps_state;
239 if (id3)
241 unsigned long length = id3->length;
242 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
243 switch (token->type)
245 case SKIN_TOKEN_METADATA_ARTIST:
246 return id3->artist;
247 case SKIN_TOKEN_METADATA_COMPOSER:
248 return id3->composer;
249 case SKIN_TOKEN_METADATA_ALBUM:
250 return id3->album;
251 case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
252 return id3->albumartist;
253 case SKIN_TOKEN_METADATA_GROUPING:
254 return id3->grouping;
255 case SKIN_TOKEN_METADATA_GENRE:
256 return id3->genre_string;
257 case SKIN_TOKEN_METADATA_DISC_NUMBER:
258 if (id3->disc_string)
259 return id3->disc_string;
260 if (id3->discnum) {
261 snprintf(buf, buf_size, "%d", id3->discnum);
262 return buf;
264 return NULL;
265 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
266 if (id3->track_string)
267 return id3->track_string;
268 if (id3->tracknum) {
269 snprintf(buf, buf_size, "%d", id3->tracknum);
270 return buf;
272 return NULL;
273 case SKIN_TOKEN_METADATA_TRACK_TITLE:
274 return id3->title;
275 case SKIN_TOKEN_METADATA_VERSION:
276 switch (id3->id3version)
278 case ID3_VER_1_0:
279 return "1";
280 case ID3_VER_1_1:
281 return "1.1";
282 case ID3_VER_2_2:
283 return "2.2";
284 case ID3_VER_2_3:
285 return "2.3";
286 case ID3_VER_2_4:
287 return "2.4";
288 default:
289 break;
291 return NULL;
292 case SKIN_TOKEN_METADATA_YEAR:
293 if( id3->year_string )
294 return id3->year_string;
295 if (id3->year) {
296 snprintf(buf, buf_size, "%d", id3->year);
297 return buf;
299 return NULL;
300 case SKIN_TOKEN_METADATA_COMMENT:
301 return id3->comment;
302 case SKIN_TOKEN_FILE_BITRATE:
303 if(id3->bitrate)
304 snprintf(buf, buf_size, "%d", id3->bitrate);
305 else
306 return "?";
307 return buf;
308 case SKIN_TOKEN_TRACK_TIME_ELAPSED:
309 if (intval && limit == TOKEN_VALUE_ONLY)
310 *intval = elapsed/1000;
311 format_time(buf, buf_size, elapsed);
312 return buf;
314 case SKIN_TOKEN_TRACK_TIME_REMAINING:
315 if (intval && limit == TOKEN_VALUE_ONLY)
316 *intval = (length - elapsed)/1000;
317 format_time(buf, buf_size, length - elapsed);
318 return buf;
320 case SKIN_TOKEN_TRACK_LENGTH:
321 if (intval && limit == TOKEN_VALUE_ONLY)
322 *intval = length/1000;
323 format_time(buf, buf_size, length);
324 return buf;
326 case SKIN_TOKEN_TRACK_ELAPSED_PERCENT:
327 if (length <= 0)
328 return NULL;
330 if (intval)
332 if (limit == TOKEN_VALUE_ONLY)
333 limit = 100; /* make it a percentage */
334 *intval = limit * elapsed / length + 1;
336 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
337 return buf;
339 case SKIN_TOKEN_TRACK_STARTING:
341 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
342 if (elapsed < time)
343 return "starting";
345 return NULL;
346 case SKIN_TOKEN_TRACK_ENDING:
348 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
349 if (length - elapsed < time)
350 return "ending";
352 return NULL;
354 case SKIN_TOKEN_FILE_CODEC:
355 if (intval)
357 if(id3->codectype == AFMT_UNKNOWN)
358 *intval = AFMT_NUM_CODECS;
359 else
360 *intval = id3->codectype;
362 return get_codectype(id3);
364 case SKIN_TOKEN_FILE_FREQUENCY:
365 snprintf(buf, buf_size, "%ld", id3->frequency);
366 return buf;
367 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
368 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
369 if ((id3->frequency % 1000) < 100)
370 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
371 else
372 snprintf(buf, buf_size, "%ld.%lu",
373 id3->frequency / 1000,
374 (id3->frequency % 1000) / 100);
375 return buf;
376 case SKIN_TOKEN_FILE_VBR:
377 return (id3->vbr) ? "(avg)" : NULL;
378 case SKIN_TOKEN_FILE_SIZE:
379 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
380 return buf;
382 #ifdef HAVE_TAGCACHE
383 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
384 if (intval)
385 *intval = id3->playcount + 1;
386 snprintf(buf, buf_size, "%ld", id3->playcount);
387 return buf;
388 case SKIN_TOKEN_DATABASE_RATING:
389 if (intval)
390 *intval = id3->rating + 1;
391 snprintf(buf, buf_size, "%d", id3->rating);
392 return buf;
393 case SKIN_TOKEN_DATABASE_AUTOSCORE:
394 if (intval)
395 *intval = id3->score + 1;
396 snprintf(buf, buf_size, "%d", id3->score);
397 return buf;
398 #endif
400 default:
401 return get_filename_token(token, id3->path, buf, buf_size);
404 else /* id3 == NULL, handle the error based on the expected return type */
406 switch (token->type)
408 /* Most tokens expect NULL on error so leave that for the default case,
409 * The ones that expect "0" need to be handled */
410 case SKIN_TOKEN_FILE_FREQUENCY:
411 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
412 case SKIN_TOKEN_FILE_SIZE:
413 #ifdef HAVE_TAGCACHE
414 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
415 case SKIN_TOKEN_DATABASE_RATING:
416 case SKIN_TOKEN_DATABASE_AUTOSCORE:
417 #endif
418 if (intval)
419 *intval = 0;
420 return "0";
421 default:
422 return get_filename_token(token, filename, buf, buf_size);
425 return buf;
428 #if CONFIG_TUNER
430 /* Formats the frequency (specified in Hz) in MHz, */
431 /* with one or two digits after the decimal point -- */
432 /* depending on the frequency changing step. */
433 /* Returns buf */
434 static char *format_freq_MHz(int freq, int freq_step, char *buf, int buf_size)
436 int scale, div;
437 char *fmt;
438 if (freq_step < 100000)
440 /* Format with two digits after decimal point */
441 scale = 10000;
442 fmt = "%d.%02d";
444 else
446 /* Format with one digit after decimal point */
447 scale = 100000;
448 fmt = "%d.%d";
450 div = 1000000 / scale;
451 freq = freq / scale;
452 snprintf(buf, buf_size, fmt, freq/div, freq%div);
453 return buf;
457 /* Tokens which are really only used by the radio screen go in here */
458 const char *get_radio_token(struct wps_token *token, int preset_offset,
459 char *buf, int buf_size, int limit, int *intval)
461 const struct fm_region_data *region_data =
462 &(fm_region_data[global_settings.fm_region]);
463 (void)limit;
464 switch (token->type)
466 /* Radio/tuner tokens */
467 case SKIN_TOKEN_TUNER_TUNED:
468 if (tuner_get(RADIO_TUNED))
469 return "t";
470 return NULL;
471 case SKIN_TOKEN_TUNER_SCANMODE:
472 if (radio_scan_mode())
473 return "s";
474 return NULL;
475 case SKIN_TOKEN_TUNER_STEREO:
476 if (radio_is_stereo())
477 return "s";
478 return NULL;
479 case SKIN_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
480 return format_freq_MHz(region_data->freq_min,
481 region_data->freq_step, buf, buf_size);
482 case SKIN_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
483 return format_freq_MHz(region_data->freq_max,
484 region_data->freq_step, buf, buf_size);
485 case SKIN_TOKEN_TUNER_CURFREQ:
486 return format_freq_MHz(radio_current_frequency(),
487 region_data->freq_step, buf, buf_size);
488 #ifdef HAVE_RADIO_RSSI
489 case SKIN_TOKEN_TUNER_RSSI:
490 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI));
491 if (intval)
493 int val = tuner_get(RADIO_RSSI);
494 int min = tuner_get(RADIO_RSSI_MIN);
495 int max = tuner_get(RADIO_RSSI_MAX);
496 if (limit == TOKEN_VALUE_ONLY)
498 *intval = val;
500 else
502 *intval = 1+(limit-1)*(val-min)/(max-1-min);
505 return buf;
506 case SKIN_TOKEN_TUNER_RSSI_MIN:
507 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MIN));
508 return buf;
509 case SKIN_TOKEN_TUNER_RSSI_MAX:
510 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MAX));
511 return buf;
512 #endif
513 case SKIN_TOKEN_PRESET_NAME:
514 case SKIN_TOKEN_PRESET_FREQ:
515 case SKIN_TOKEN_PRESET_ID:
517 int preset_count = radio_preset_count();
518 int cur_preset = radio_current_preset();
519 if (preset_count == 0 || cur_preset < 0)
520 return NULL;
521 int preset = cur_preset + preset_offset;
522 /* make sure it's in the valid range */
523 preset %= preset_count;
524 if (preset < 0)
525 preset += preset_count;
526 if (token->type == SKIN_TOKEN_PRESET_NAME)
527 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
528 else if (token->type == SKIN_TOKEN_PRESET_FREQ)
529 format_freq_MHz(radio_get_preset(preset)->frequency,
530 region_data->freq_step, buf, buf_size);
531 else
532 snprintf(buf, buf_size, "%d", preset + 1);
533 return buf;
535 case SKIN_TOKEN_PRESET_COUNT:
536 snprintf(buf, buf_size, "%d", radio_preset_count());
537 if (intval)
538 *intval = radio_preset_count();
539 return buf;
540 case SKIN_TOKEN_HAVE_RDS:
541 #ifdef HAVE_RDS_CAP
542 return "rds";
543 case SKIN_TOKEN_RDS_NAME:
544 return tuner_get_rds_info(RADIO_RDS_NAME);
545 case SKIN_TOKEN_RDS_TEXT:
546 return tuner_get_rds_info(RADIO_RDS_TEXT);
547 #else
548 return NULL; /* end of the SKIN_TOKEN_HAVE_RDS case */
549 #endif /* HAVE_RDS_CAP */
550 default:
551 return NULL;
553 return NULL;
555 #endif
557 static struct mp3entry* get_mp3entry_from_offset(int offset, char **filename)
559 struct mp3entry* pid3 = NULL;
560 struct wps_state *state = skin_get_global_state();
561 struct cuesheet *cue = state->id3 ? state->id3->cuesheet : NULL;
562 const char *fname = NULL;
563 if (cue && cue->curr_track_idx + offset < cue->track_count)
564 pid3 = state->id3;
565 else if (offset == 0)
566 pid3 = state->id3;
567 else if (offset == 1)
568 pid3 = state->nid3;
569 else
571 static char filename_buf[MAX_PATH + 1];
572 fname = playlist_peek(offset, filename_buf, sizeof(filename_buf));
573 *filename = (char*)fname;
574 #if CONFIG_CODEC == SWCODEC
575 static struct mp3entry tempid3;
576 if (
577 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
578 tagcache_fill_tags(&tempid3, fname) ||
579 #endif
580 audio_peek_track(&tempid3, offset)
583 pid3 = &tempid3;
585 #endif
587 return pid3;
590 #ifdef HAVE_LCD_CHARCELLS
591 static void format_player_progress(struct gui_wps *gwps)
593 struct wps_state *state = skin_get_global_state();
594 struct screen *display = gwps->display;
595 unsigned char progress_pattern[7];
596 int pos = 0;
597 int i;
599 int elapsed, length;
600 if (LIKELY(state->id3))
602 elapsed = state->id3->elapsed;
603 length = state->id3->length;
605 else
607 elapsed = 0;
608 length = 0;
611 if (length)
612 pos = 36 * (elapsed + state->ff_rewind_count) / length;
614 for (i = 0; i < 7; i++, pos -= 5)
616 if (pos <= 0)
617 progress_pattern[i] = 0x1fu;
618 else if (pos >= 5)
619 progress_pattern[i] = 0x00u;
620 else
621 progress_pattern[i] = 0x1fu >> pos;
624 display->define_pattern(gwps->data->wps_progress_pat[0], progress_pattern);
627 static void format_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
629 static const unsigned char numbers[10][4] = {
630 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
631 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
632 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
633 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
634 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
635 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
636 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
637 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
638 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
639 {0x0e, 0x0e, 0x02, 0x0e} /* 9 */
642 struct wps_state *state = skin_get_global_state();
643 struct screen *display = gwps->display;
644 struct wps_data *data = gwps->data;
645 unsigned char progress_pattern[7];
646 char timestr[10];
647 int time;
648 int time_idx = 0;
649 int pos = 0;
650 int pat_idx = 1;
651 int digit, i, j;
652 bool softchar;
654 int elapsed, length;
655 if (LIKELY(state->id3))
657 elapsed = state->id3->elapsed;
658 length = state->id3->length;
660 else
662 elapsed = 0;
663 length = 0;
666 if (buf_size < 34) /* worst case: 11x UTF-8 char + \0 */
667 return;
669 time = elapsed + state->ff_rewind_count;
670 if (length)
671 pos = 55 * time / length;
673 memset(timestr, 0, sizeof(timestr));
674 format_time(timestr, sizeof(timestr)-2, time);
675 timestr[strlen(timestr)] = ':'; /* always safe */
677 for (i = 0; i < 11; i++, pos -= 5)
679 softchar = false;
680 memset(progress_pattern, 0, sizeof(progress_pattern));
682 if ((digit = timestr[time_idx]))
684 softchar = true;
685 digit -= '0';
687 if (timestr[time_idx + 1] == ':') /* ones, left aligned */
689 memcpy(progress_pattern, numbers[digit], 4);
690 time_idx += 2;
692 else /* tens, shifted right */
694 for (j = 0; j < 4; j++)
695 progress_pattern[j] = numbers[digit][j] >> 1;
697 if (time_idx > 0) /* not the first group, add colon in front */
699 progress_pattern[1] |= 0x10u;
700 progress_pattern[3] |= 0x10u;
702 time_idx++;
705 if (pos >= 5)
706 progress_pattern[5] = progress_pattern[6] = 0x1fu;
709 if (pos > 0 && pos < 5)
711 softchar = true;
712 progress_pattern[5] = progress_pattern[6] = (~0x1fu >> pos) & 0x1fu;
715 if (softchar && pat_idx < 8)
717 display->define_pattern(data->wps_progress_pat[pat_idx],
718 progress_pattern);
719 buf = utf8encode(data->wps_progress_pat[pat_idx], buf);
720 pat_idx++;
722 else if (pos <= 0)
723 buf = utf8encode(' ', buf);
724 else
725 buf = utf8encode(0xe115, buf); /* 2/7 _ */
727 *buf = '\0';
730 #endif /* HAVE_LCD_CHARCELLS */
732 /* Don't inline this; it was broken out of get_token_value to reduce stack
733 * usage.
735 static const char* NOINLINE get_lif_token_value(struct gui_wps *gwps,
736 struct logical_if *lif,
737 int offset, char *buf,
738 int buf_size)
740 int a = lif->num_options;
741 int b;
742 bool number_set = true;
743 struct wps_token *liftoken = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->token);
744 const char* out_text = get_token_value(gwps, liftoken, offset, buf, buf_size, &a);
745 if (a == -1 && liftoken->type != SKIN_TOKEN_VOLUME)
747 a = (out_text && *out_text) ? 1 : 0;
748 number_set = false;
750 switch (lif->operand.type)
752 case STRING:
754 char *cmp = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->operand.data.text);
755 if (out_text == NULL)
756 return NULL;
757 a = strcmp(out_text, cmp);
758 b = 0;
759 break;
761 case INTEGER:
762 if (!number_set && out_text && *out_text >= '0' && *out_text <= '9')
763 a = atoi(out_text);
764 /* fall through */
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 start_byte = utf8seek(token_val, ss->start);
932 if (ss->length < 0 || (ss->start + ss->length) > utf8_len)
933 end_byte = strlen(token_val);
934 else
935 end_byte = utf8seek(token_val, ss->start + ss->length);
937 byte_len = end_byte - start_byte;
939 if (token_val != buf)
940 memcpy(buf, &token_val[start_byte], byte_len);
941 else
942 buf = &buf[start_byte];
944 buf[byte_len] = '\0';
945 return buf;
947 return NULL;
949 break;
951 case SKIN_TOKEN_CHARACTER:
952 if (token->value.c == '\n')
953 return NULL;
954 return &(token->value.c);
956 case SKIN_TOKEN_STRING:
957 return (char*)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
959 case SKIN_TOKEN_TRANSLATEDSTRING:
960 return (char*)P2STR(ID2P(token->value.i));
962 case SKIN_TOKEN_PLAYLIST_ENTRIES:
963 snprintf(buf, buf_size, "%d", playlist_amount());
964 if (intval)
965 *intval = playlist_amount();
966 return buf;
967 #ifdef HAVE_LCD_BITMAP
968 case SKIN_TOKEN_LIST_TITLE_TEXT:
969 return sb_get_title(gwps->display->screen_type);
970 case SKIN_TOKEN_LIST_TITLE_ICON:
971 if (intval)
972 *intval = sb_get_icon(gwps->display->screen_type);
973 snprintf(buf, buf_size, "%d",sb_get_icon(gwps->display->screen_type));
974 return buf;
975 case SKIN_TOKEN_LIST_ITEM_TEXT:
977 struct listitem *li = (struct listitem *)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
978 return skinlist_get_item_text(li->offset, li->wrap, buf, buf_size);
980 case SKIN_TOKEN_LIST_ITEM_NUMBER:
981 if (intval)
982 *intval = skinlist_get_item_number() + 1;
983 snprintf(buf, buf_size, "%d",skinlist_get_item_number() + 1);
984 return buf;
985 case SKIN_TOKEN_LIST_ITEM_IS_SELECTED:
986 return skinlist_is_selected_item()?"s":"";
987 case SKIN_TOKEN_LIST_ITEM_ICON:
989 struct listitem *li = (struct listitem *)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
990 int icon = skinlist_get_item_icon(li->offset, li->wrap);
991 if (intval)
992 *intval = icon;
993 snprintf(buf, buf_size, "%d", icon);
994 return buf;
996 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR:
997 return skinlist_needs_scrollbar(gwps->display->screen_type) ? "s" : "";
998 #endif
999 case SKIN_TOKEN_PLAYLIST_NAME:
1000 return playlist_name(NULL, buf, buf_size);
1002 case SKIN_TOKEN_PLAYLIST_POSITION:
1003 snprintf(buf, buf_size, "%d", playlist_get_display_index()+offset);
1004 if (intval)
1005 *intval = playlist_get_display_index()+offset;
1006 return buf;
1008 case SKIN_TOKEN_PLAYLIST_SHUFFLE:
1009 if ( global_settings.playlist_shuffle )
1010 return "s";
1011 else
1012 return NULL;
1013 break;
1015 case SKIN_TOKEN_VOLUME:
1016 snprintf(buf, buf_size, "%d", global_settings.volume);
1017 if (intval)
1019 int minvol = sound_min(SOUND_VOLUME);
1020 if (limit == TOKEN_VALUE_ONLY)
1022 *intval = global_settings.volume;
1024 else if (global_settings.volume == minvol)
1026 *intval = 1;
1028 else if (global_settings.volume == 0)
1030 *intval = limit - 1;
1032 else if (global_settings.volume > 0)
1034 *intval = limit;
1036 else
1038 *intval = (limit-3) * (global_settings.volume - minvol - 1)
1039 / (-1 - minvol) + 2;
1042 return buf;
1043 #ifdef HAVE_ALBUMART
1044 case SKIN_TOKEN_ALBUMART_FOUND:
1045 if (SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart))
1047 int handle = -1;
1048 handle = playback_current_aa_hid(data->playback_aa_slot);
1049 #if CONFIG_TUNER
1050 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
1052 struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart);
1053 struct dim dim = {aa->width, aa->height};
1054 handle = radio_get_art_hid(&dim);
1056 #endif
1057 if (handle >= 0)
1058 return "C";
1060 return NULL;
1061 #endif
1063 case SKIN_TOKEN_BATTERY_PERCENT:
1065 int l = battery_level();
1067 if (intval)
1069 if (limit == TOKEN_VALUE_ONLY)
1071 *intval = l;
1073 else
1075 limit = MAX(limit, 3);
1076 if (l > -1) {
1077 /* First enum is used for "unknown level",
1078 * last enum is used for 100%.
1080 *intval = (limit - 2) * l / 100 + 2;
1081 } else {
1082 *intval = 1;
1087 if (l > -1) {
1088 snprintf(buf, buf_size, "%d", l);
1089 return buf;
1090 } else {
1091 return "?";
1095 case SKIN_TOKEN_BATTERY_VOLTS:
1097 int v = battery_voltage();
1098 if (v >= 0) {
1099 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
1100 return buf;
1101 } else {
1102 return "?";
1106 case SKIN_TOKEN_BATTERY_TIME:
1108 int t = battery_time();
1109 if (t >= 0)
1110 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
1111 else
1112 return "?h ?m";
1113 return buf;
1116 #if CONFIG_CHARGING
1117 case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED:
1119 if(charger_input_state==CHARGER)
1120 return "p";
1121 else
1122 return NULL;
1124 #endif
1125 #if CONFIG_CHARGING >= CHARGING_MONITOR
1126 case SKIN_TOKEN_BATTERY_CHARGING:
1128 if (charge_state == CHARGING || charge_state == TOPOFF) {
1129 return "c";
1130 } else {
1131 return NULL;
1134 #endif
1135 #ifdef HAVE_USB_POWER
1136 case SKIN_TOKEN_USB_POWERED:
1137 if (usb_powered())
1138 return "u";
1139 return NULL;
1140 #endif
1141 case SKIN_TOKEN_BATTERY_SLEEPTIME:
1143 if (get_sleep_timer() == 0)
1144 return NULL;
1145 else
1147 format_time(buf, buf_size, get_sleep_timer() * 1000);
1148 return buf;
1152 case SKIN_TOKEN_PLAYBACK_STATUS:
1154 int status = current_playmode();
1155 /* music */
1156 int mode = 1; /* stop */
1157 if (status == STATUS_PLAY)
1158 mode = 2; /* play */
1159 if (state->is_fading ||
1160 (status == STATUS_PAUSE && !status_get_ffmode()))
1161 mode = 3; /* pause */
1162 else
1163 { /* ff / rwd */
1164 if (status_get_ffmode() == STATUS_FASTFORWARD)
1165 mode = 4;
1166 if (status_get_ffmode() == STATUS_FASTBACKWARD)
1167 mode = 5;
1169 #ifdef HAVE_RECORDING
1170 /* recording */
1171 if (status == STATUS_RECORD)
1172 mode = 6;
1173 else if (status == STATUS_RECORD_PAUSE)
1174 mode = 7;
1175 #endif
1176 #if CONFIG_TUNER
1177 /* radio */
1178 if (status == STATUS_RADIO)
1179 mode = 8;
1180 else if (status == STATUS_RADIO_PAUSE)
1181 mode = 9;
1182 #endif
1184 if (intval) {
1185 *intval = mode;
1188 snprintf(buf, buf_size, "%d", mode-1);
1189 return buf;
1192 case SKIN_TOKEN_REPEAT_MODE:
1193 if (intval)
1194 *intval = global_settings.repeat_mode + 1;
1195 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
1196 return buf;
1198 case SKIN_TOKEN_RTC_PRESENT:
1199 #if CONFIG_RTC
1200 return "c";
1201 #else
1202 return NULL;
1203 #endif
1205 #if CONFIG_RTC
1206 case SKIN_TOKEN_RTC_12HOUR_CFG:
1207 if (intval)
1208 *intval = global_settings.timeformat + 1;
1209 snprintf(buf, buf_size, "%d", global_settings.timeformat);
1210 return buf;
1212 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1213 /* d: day of month (01..31) */
1214 snprintf(buf, buf_size, "%02d", tm->tm_mday);
1215 if (intval)
1216 *intval = tm->tm_mday - 1;
1217 return buf;
1219 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1220 /* e: day of month, blank padded ( 1..31) */
1221 snprintf(buf, buf_size, "%2d", tm->tm_mday);
1222 if (intval)
1223 *intval = tm->tm_mday - 1;
1224 return buf;
1226 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1227 /* H: hour (00..23) */
1228 snprintf(buf, buf_size, "%02d", tm->tm_hour);
1229 if (intval)
1230 *intval = tm->tm_hour;
1231 return buf;
1233 case SKIN_TOKEN_RTC_HOUR_24:
1234 /* k: hour ( 0..23) */
1235 snprintf(buf, buf_size, "%2d", tm->tm_hour);
1236 if (intval)
1237 *intval = tm->tm_hour;
1238 return buf;
1240 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1241 /* I: hour (01..12) */
1242 snprintf(buf, buf_size, "%02d",
1243 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1244 if (intval)
1245 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1246 return buf;
1248 case SKIN_TOKEN_RTC_HOUR_12:
1249 /* l: hour ( 1..12) */
1250 snprintf(buf, buf_size, "%2d",
1251 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1252 if (intval)
1253 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1254 return buf;
1256 case SKIN_TOKEN_RTC_MONTH:
1257 /* m: month (01..12) */
1258 if (intval)
1259 *intval = tm->tm_mon + 1;
1260 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
1261 return buf;
1263 case SKIN_TOKEN_RTC_MINUTE:
1264 /* M: minute (00..59) */
1265 snprintf(buf, buf_size, "%02d", tm->tm_min);
1266 if (intval)
1267 *intval = tm->tm_min;
1268 return buf;
1270 case SKIN_TOKEN_RTC_SECOND:
1271 /* S: second (00..59) */
1272 snprintf(buf, buf_size, "%02d", tm->tm_sec);
1273 if (intval)
1274 *intval = tm->tm_sec;
1275 return buf;
1277 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1278 /* y: last two digits of year (00..99) */
1279 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
1280 if (intval)
1281 *intval = tm->tm_year % 100;
1282 return buf;
1284 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1285 /* Y: year (1970...) */
1286 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
1287 if (intval)
1288 *intval = tm->tm_year + 1900;
1289 return buf;
1291 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1292 /* p: upper case AM or PM indicator */
1293 if (intval)
1294 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1295 return tm->tm_hour/12 == 0 ? "AM" : "PM";
1297 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1298 /* P: lower case am or pm indicator */
1299 if (intval)
1300 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1301 return tm->tm_hour/12 == 0 ? "am" : "pm";
1303 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1304 /* a: abbreviated weekday name (Sun..Sat) */
1305 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
1307 case SKIN_TOKEN_RTC_MONTH_NAME:
1308 /* b: abbreviated month name (Jan..Dec) */
1309 return str(LANG_MONTH_JANUARY + tm->tm_mon);
1311 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1312 /* u: day of week (1..7); 1 is Monday */
1313 if (intval)
1314 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
1315 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
1316 return buf;
1318 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1319 /* w: day of week (0..6); 0 is Sunday */
1320 if (intval)
1321 *intval = tm->tm_wday + 1;
1322 snprintf(buf, buf_size, "%1d", tm->tm_wday);
1323 return buf;
1324 #else
1325 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1326 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1327 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1328 case SKIN_TOKEN_RTC_HOUR_24:
1329 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1330 case SKIN_TOKEN_RTC_HOUR_12:
1331 case SKIN_TOKEN_RTC_MONTH:
1332 case SKIN_TOKEN_RTC_MINUTE:
1333 case SKIN_TOKEN_RTC_SECOND:
1334 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1335 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1336 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1337 return "--";
1338 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1339 return "----";
1340 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1341 case SKIN_TOKEN_RTC_MONTH_NAME:
1342 return "---";
1343 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1344 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1345 return "-";
1346 #endif
1348 #ifdef HAVE_LCD_CHARCELLS
1349 case SKIN_TOKEN_PROGRESSBAR:
1351 char *end;
1352 format_player_progress(gwps);
1353 end = utf8encode(data->wps_progress_pat[0], buf);
1354 *end = '\0';
1355 return buf;
1358 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1359 if(is_new_player())
1361 /* we need 11 characters (full line) for
1362 progress-bar */
1363 strlcpy(buf, " ", buf_size);
1364 format_player_fullbar(gwps,buf,buf_size);
1365 DEBUGF("bar='%s'\n",buf);
1367 else
1369 /* Tell the user if we have an OldPlayer */
1370 strlcpy(buf, " <Old LCD> ", buf_size);
1372 return buf;
1373 #endif
1376 #ifdef HAVE_LCD_BITMAP
1377 /* peakmeter */
1378 case SKIN_TOKEN_PEAKMETER_LEFT:
1379 case SKIN_TOKEN_PEAKMETER_RIGHT:
1381 int left, right, val;
1382 peak_meter_current_vals(&left, &right);
1383 val = token->type == SKIN_TOKEN_PEAKMETER_LEFT ?
1384 left : right;
1385 val = peak_meter_scale_value(val, limit==1 ? MAX_PEAK : limit);
1386 if (intval)
1387 *intval = val;
1388 snprintf(buf, buf_size, "%d", val);
1389 data->peak_meter_enabled = true;
1390 return buf;
1392 #endif
1394 #if (CONFIG_CODEC == SWCODEC)
1395 case SKIN_TOKEN_CROSSFADE:
1396 #ifdef HAVE_CROSSFADE
1397 if (intval)
1398 *intval = global_settings.crossfade + 1;
1399 snprintf(buf, buf_size, "%d", global_settings.crossfade);
1400 #else
1401 snprintf(buf, buf_size, "%d", 0);
1402 #endif
1403 return buf;
1405 case SKIN_TOKEN_REPLAYGAIN:
1407 int val;
1409 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
1410 val = 1; /* off */
1411 else
1413 int type;
1414 if (LIKELY(id3))
1415 type = get_replaygain_mode(id3->track_gain != 0,
1416 id3->album_gain != 0);
1417 else
1418 type = -1;
1420 if (type < 0)
1421 val = 6; /* no tag */
1422 else
1423 val = type + 2;
1425 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
1426 val += 2;
1429 if (intval)
1430 *intval = val;
1432 switch (val)
1434 case 1:
1435 case 6:
1436 return "+0.00 dB";
1437 break;
1438 /* due to above, coming here with !id3 shouldn't be possible */
1439 case 2:
1440 case 4:
1441 replaygain_itoa(buf, buf_size, id3->track_level);
1442 break;
1443 case 3:
1444 case 5:
1445 replaygain_itoa(buf, buf_size, id3->album_level);
1446 break;
1448 return buf;
1450 #endif /* (CONFIG_CODEC == SWCODEC) */
1452 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHSCREEN)
1453 case SKIN_TOKEN_SOUND_PITCH:
1455 int32_t pitch = sound_get_pitch();
1456 snprintf(buf, buf_size, "%ld.%ld",
1457 pitch / PITCH_SPEED_PRECISION,
1458 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1460 if (intval)
1461 *intval = pitch_speed_enum(limit, pitch,
1462 PITCH_SPEED_PRECISION * 100);
1463 return buf;
1465 #endif
1467 #if (CONFIG_CODEC == SWCODEC) && defined (HAVE_PITCHSCREEN)
1468 case SKIN_TOKEN_SOUND_SPEED:
1470 int32_t pitch = sound_get_pitch();
1471 int32_t speed;
1472 if (dsp_timestretch_available())
1473 speed = GET_SPEED(pitch, dsp_get_timestretch());
1474 else
1475 speed = pitch;
1476 snprintf(buf, buf_size, "%ld.%ld",
1477 speed / PITCH_SPEED_PRECISION,
1478 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1479 if (intval)
1480 *intval = pitch_speed_enum(limit, speed,
1481 PITCH_SPEED_PRECISION * 100);
1482 return buf;
1484 #endif
1486 case SKIN_TOKEN_MAIN_HOLD:
1487 #ifdef HAVE_TOUCHSCREEN
1488 if (data->touchscreen_locked)
1489 return "t";
1490 #endif
1491 #ifdef HAS_BUTTON_HOLD
1492 if (button_hold())
1493 #else
1494 if (is_keys_locked())
1495 #endif /*hold switch or softlock*/
1496 return "h";
1497 else
1498 return NULL;
1500 #ifdef HAS_REMOTE_BUTTON_HOLD
1501 case SKIN_TOKEN_REMOTE_HOLD:
1502 if (remote_button_hold())
1503 return "r";
1504 else
1505 return NULL;
1506 #endif
1508 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1509 case SKIN_TOKEN_VLED_HDD:
1510 if(led_read(HZ/2))
1511 return "h";
1512 else
1513 return NULL;
1514 #endif
1515 case SKIN_TOKEN_BUTTON_VOLUME:
1516 if (global_status.last_volume_change &&
1517 TIME_BEFORE(current_tick, global_status.last_volume_change +
1518 token->value.i))
1519 return "v";
1520 return NULL;
1522 case SKIN_TOKEN_LASTTOUCH:
1524 #ifdef HAVE_TOUCHSCREEN
1525 unsigned int last_touch = touchscreen_last_touch();
1526 char *skin_base = get_skin_buffer(data);
1527 struct touchregion_lastpress *data = SKINOFFSETTOPTR(skin_base, token->value.data);
1528 struct touchregion *region = SKINOFFSETTOPTR(skin_base, data->region);
1529 if (region)
1530 last_touch = region->last_press;
1532 if (last_touch != 0xffff &&
1533 TIME_BEFORE(current_tick, data->timeout + last_touch))
1534 return "t";
1535 #endif
1537 return NULL;
1538 case SKIN_TOKEN_HAVE_TOUCH:
1539 #ifdef HAVE_TOUCHSCREEN
1540 return "t";
1541 #else
1542 return NULL;
1543 #endif
1545 case SKIN_TOKEN_SETTING:
1547 const struct settings_list *s = settings+token->value.i;
1548 if (intval)
1550 /* Handle contionals */
1551 switch (s->flags&F_T_MASK)
1553 case F_T_INT:
1554 case F_T_UINT:
1555 if (s->flags&F_T_SOUND)
1557 /* %?St|name|<min|min+1|...|max-1|max> */
1558 int sound_setting = s->sound_setting->setting;
1559 /* settings with decimals can't be used in conditionals */
1560 if (sound_numdecimals(sound_setting) == 0)
1562 *intval = (*(int*)s->setting-sound_min(sound_setting))
1563 /sound_steps(sound_setting) + 1;
1565 else
1566 *intval = -1;
1568 else if (s->flags&F_RGB)
1569 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1570 /* shouldn't overflow since colors are stored
1571 * on 16 bits ...
1572 * but this is pretty useless anyway */
1573 *intval = *(int*)s->setting + 1;
1574 else if (s->cfg_vals == NULL)
1575 /* %?St|name|<1st choice|2nd choice|...> */
1576 *intval = (*(int*)s->setting-s->int_setting->min)
1577 /s->int_setting->step + 1;
1578 else
1579 /* %?St|name|<1st choice|2nd choice|...> */
1580 /* Not sure about this one. cfg_name/vals are
1581 * indexed from 0 right? */
1582 *intval = *(int*)s->setting + 1;
1583 break;
1584 case F_T_BOOL:
1585 /* %?St|name|<if true|if false> */
1586 *intval = *(bool*)s->setting?1:2;
1587 break;
1588 case F_T_CHARPTR:
1589 case F_T_UCHARPTR:
1590 /* %?St|name|<if non empty string|if empty>
1591 * The string's emptyness discards the setting's
1592 * prefix and suffix */
1593 *intval = ((char*)s->setting)[0]?1:2;
1594 /* if there is a prefix we should ignore it here */
1595 if (s->filename_setting->prefix)
1596 return (char*)s->setting;
1597 break;
1598 default:
1599 /* This shouldn't happen ... but you never know */
1600 *intval = -1;
1601 break;
1604 /* Special handlng for filenames because we dont want to show the prefix */
1605 if ((s->flags&F_T_MASK) == F_T_CHARPTR ||
1606 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1608 if (s->filename_setting->prefix)
1609 return (char*)s->setting;
1611 cfg_to_string(token->value.i,buf,buf_size);
1612 return buf;
1614 case SKIN_TOKEN_HAVE_TUNER:
1615 #if CONFIG_TUNER
1616 if (radio_hardware_present())
1617 return "r";
1618 #endif
1619 return NULL;
1620 /* Recording tokens */
1621 case SKIN_TOKEN_HAVE_RECORDING:
1622 #ifdef HAVE_RECORDING
1623 return "r";
1624 #else
1625 return NULL;
1626 #endif
1628 #ifdef HAVE_RECORDING
1629 case SKIN_TOKEN_IS_RECORDING:
1630 if (audio_status() == AUDIO_STATUS_RECORD)
1631 return "r";
1632 return NULL;
1633 case SKIN_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1635 #if CONFIG_CODEC == SWCODEC
1636 unsigned long samprk;
1637 int rec_freq = global_settings.rec_frequency;
1639 #ifdef SIMULATOR
1640 samprk = 44100;
1641 #else
1642 #if defined(HAVE_SPDIF_REC)
1643 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1645 /* Use rate in use, not current measured rate if it changed */
1646 samprk = pcm_rec_sample_rate();
1647 rec_freq = 0;
1648 while (rec_freq < SAMPR_NUM_FREQ &&
1649 audio_master_sampr_list[rec_freq] != samprk)
1651 rec_freq++;
1654 else
1655 #endif
1656 samprk = rec_freq_sampr[rec_freq];
1657 #endif /* SIMULATOR */
1658 if (intval)
1660 switch (rec_freq)
1662 REC_HAVE_96_(case REC_FREQ_96:
1663 *intval = 1;
1664 break;)
1665 REC_HAVE_88_(case REC_FREQ_88:
1666 *intval = 2;
1667 break;)
1668 REC_HAVE_64_(case REC_FREQ_64:
1669 *intval = 3;
1670 break;)
1671 REC_HAVE_48_(case REC_FREQ_48:
1672 *intval = 4;
1673 break;)
1674 REC_HAVE_44_(case REC_FREQ_44:
1675 *intval = 5;
1676 break;)
1677 REC_HAVE_32_(case REC_FREQ_32:
1678 *intval = 6;
1679 break;)
1680 REC_HAVE_24_(case REC_FREQ_24:
1681 *intval = 7;
1682 break;)
1683 REC_HAVE_22_(case REC_FREQ_22:
1684 *intval = 8;
1685 break;)
1686 REC_HAVE_16_(case REC_FREQ_16:
1687 *intval = 9;
1688 break;)
1689 REC_HAVE_12_(case REC_FREQ_12:
1690 *intval = 10;
1691 break;)
1692 REC_HAVE_11_(case REC_FREQ_11:
1693 *intval = 11;
1694 break;)
1695 REC_HAVE_8_(case REC_FREQ_8:
1696 *intval = 12;
1697 break;)
1700 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1701 #else /* HWCODEC */
1703 static const char * const freq_strings[] =
1704 {"--", "44", "48", "32", "22", "24", "16"};
1705 int freq = 1 + global_settings.rec_frequency;
1706 #ifdef HAVE_SPDIF_REC
1707 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1709 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1710 freq = 0;
1712 #endif /* HAVE_SPDIF_IN */
1713 if (intval)
1714 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1715 snprintf(buf, buf_size, "%s\n",
1716 freq_strings[global_settings.rec_frequency]);
1717 #endif
1718 return buf;
1720 #if CONFIG_CODEC == SWCODEC
1721 case SKIN_TOKEN_REC_ENCODER:
1723 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1724 if (intval)
1725 *intval = rec_format;
1726 switch (rec_format)
1728 case REC_FORMAT_PCM_WAV:
1729 return "wav";
1730 case REC_FORMAT_AIFF:
1731 return "aiff";
1732 case REC_FORMAT_WAVPACK:
1733 return "wv";
1734 case REC_FORMAT_MPA_L3:
1735 return "MP3";
1736 default:
1737 return NULL;
1739 break;
1741 #endif
1742 case SKIN_TOKEN_REC_BITRATE:
1743 #if CONFIG_CODEC == SWCODEC
1744 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1746 if (intval)
1748 #if 0 /* FIXME: I dont know if this is needed? */
1749 switch (1<<global_settings.mp3_enc_config.bitrate)
1751 case MP3_BITR_CAP_8:
1752 *intval = 1;
1753 break;
1754 case MP3_BITR_CAP_16:
1755 *intval = 2;
1756 break;
1757 case MP3_BITR_CAP_24:
1758 *intval = 3;
1759 break;
1760 case MP3_BITR_CAP_32:
1761 *intval = 4;
1762 break;
1763 case MP3_BITR_CAP_40:
1764 *intval = 5;
1765 break;
1766 case MP3_BITR_CAP_48:
1767 *intval = 6;
1768 break;
1769 case MP3_BITR_CAP_56:
1770 *intval = 7;
1771 break;
1772 case MP3_BITR_CAP_64:
1773 *intval = 8;
1774 break;
1775 case MP3_BITR_CAP_80:
1776 *intval = 9;
1777 break;
1778 case MP3_BITR_CAP_96:
1779 *intval = 10;
1780 break;
1781 case MP3_BITR_CAP_112:
1782 *intval = 11;
1783 break;
1784 case MP3_BITR_CAP_128:
1785 *intval = 12;
1786 break;
1787 case MP3_BITR_CAP_144:
1788 *intval = 13;
1789 break;
1790 case MP3_BITR_CAP_160:
1791 *intval = 14;
1792 break;
1793 case MP3_BITR_CAP_192:
1794 *intval = 15;
1795 break;
1797 #endif
1798 *intval = global_settings.mp3_enc_config.bitrate+1;
1800 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1801 return buf;
1803 else
1804 return NULL; /* Fixme later */
1805 #else /* CONFIG_CODEC == HWCODEC */
1806 if (intval)
1807 *intval = global_settings.rec_quality+1;
1808 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1809 return buf;
1810 #endif
1811 case SKIN_TOKEN_REC_MONO:
1812 if (!global_settings.rec_channels)
1813 return "m";
1814 return NULL;
1816 case SKIN_TOKEN_REC_SECONDS:
1818 int time = (audio_recorded_time() / HZ) % 60;
1819 if (intval)
1820 *intval = time;
1821 snprintf(buf, buf_size, "%02d", time);
1822 return buf;
1824 case SKIN_TOKEN_REC_MINUTES:
1826 int time = (audio_recorded_time() / HZ) / 60;
1827 if (intval)
1828 *intval = time;
1829 snprintf(buf, buf_size, "%02d", time);
1830 return buf;
1832 case SKIN_TOKEN_REC_HOURS:
1834 int time = (audio_recorded_time() / HZ) / 3600;
1835 if (intval)
1836 *intval = time;
1837 snprintf(buf, buf_size, "%02d", time);
1838 return buf;
1841 #endif /* HAVE_RECORDING */
1843 case SKIN_TOKEN_CURRENT_SCREEN:
1845 int curr_screen = get_current_activity();
1846 if (intval)
1848 *intval = curr_screen;
1850 snprintf(buf, buf_size, "%d", curr_screen);
1851 return buf;
1854 case SKIN_TOKEN_LANG_IS_RTL:
1855 return lang_is_rtl() ? "r" : NULL;
1857 #ifdef HAVE_SKIN_VARIABLES
1858 case SKIN_TOKEN_VAR_GETVAL:
1860 char *skin_base = get_skin_buffer(data);
1861 struct skin_var* var = SKINOFFSETTOPTR(skin_base, token->value.data);
1862 if (intval)
1863 *intval = var->value;
1864 snprintf(buf, buf_size, "%d", var->value);
1865 return buf;
1867 break;
1868 case SKIN_TOKEN_VAR_TIMEOUT:
1870 char *skin_base = get_skin_buffer(data);
1871 struct skin_var_lastchange *data = SKINOFFSETTOPTR(skin_base, token->value.data);
1872 struct skin_var* var = SKINOFFSETTOPTR(skin_base, data->var);
1873 unsigned int last_change = var->last_changed;
1875 if (last_change != 0xffff &&
1876 TIME_BEFORE(current_tick, data->timeout + last_change))
1877 return "t";
1879 return NULL;
1880 #endif
1882 default:
1883 return NULL;