Lists can now be completly draw using the skin engine!
[maemo-rb.git] / apps / gui / skin_engine / skin_tokens.c
blob8e15ddc84a0ab1dde6db2166211159851c03091d
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 #ifdef HAVE_LCD_CHARCELLS
40 #include "hwcompat.h"
41 #endif
42 #include "abrepeat.h"
43 #include "lang.h"
44 #include "misc.h"
45 #include "led.h"
46 #ifdef HAVE_LCD_BITMAP
47 #include "peakmeter.h"
48 /* Image stuff */
49 #include "albumart.h"
50 #endif
51 #include "dsp.h"
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_PITCHSCREEN)
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 format_time(buf, buf_size, elapsed);
309 return buf;
311 case SKIN_TOKEN_TRACK_TIME_REMAINING:
312 format_time(buf, buf_size, length - elapsed);
313 return buf;
315 case SKIN_TOKEN_TRACK_LENGTH:
316 format_time(buf, buf_size, length);
317 return buf;
319 case SKIN_TOKEN_TRACK_ELAPSED_PERCENT:
320 if (length <= 0)
321 return NULL;
323 if (intval)
325 if (limit == TOKEN_VALUE_ONLY)
326 limit = 100; /* make it a percentage */
327 *intval = limit * elapsed / length + 1;
329 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
330 return buf;
332 case SKIN_TOKEN_TRACK_STARTING:
334 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
335 if (elapsed < time)
336 return "starting";
338 return NULL;
339 case SKIN_TOKEN_TRACK_ENDING:
341 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
342 if (length - elapsed < time)
343 return "ending";
345 return NULL;
347 case SKIN_TOKEN_FILE_CODEC:
348 if (intval)
350 if(id3->codectype == AFMT_UNKNOWN)
351 *intval = AFMT_NUM_CODECS;
352 else
353 *intval = id3->codectype;
355 return get_codectype(id3);
357 case SKIN_TOKEN_FILE_FREQUENCY:
358 snprintf(buf, buf_size, "%ld", id3->frequency);
359 return buf;
360 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
361 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
362 if ((id3->frequency % 1000) < 100)
363 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
364 else
365 snprintf(buf, buf_size, "%ld.%lu",
366 id3->frequency / 1000,
367 (id3->frequency % 1000) / 100);
368 return buf;
369 case SKIN_TOKEN_FILE_VBR:
370 return (id3->vbr) ? "(avg)" : NULL;
371 case SKIN_TOKEN_FILE_SIZE:
372 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
373 return buf;
375 #ifdef HAVE_TAGCACHE
376 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
377 if (intval)
378 *intval = id3->playcount + 1;
379 snprintf(buf, buf_size, "%ld", id3->playcount);
380 return buf;
381 case SKIN_TOKEN_DATABASE_RATING:
382 if (intval)
383 *intval = id3->rating + 1;
384 snprintf(buf, buf_size, "%d", id3->rating);
385 return buf;
386 case SKIN_TOKEN_DATABASE_AUTOSCORE:
387 if (intval)
388 *intval = id3->score + 1;
389 snprintf(buf, buf_size, "%d", id3->score);
390 return buf;
391 #endif
393 default:
394 return get_filename_token(token, id3->path, buf, buf_size);
397 else /* id3 == NULL, handle the error based on the expected return type */
399 switch (token->type)
401 /* Most tokens expect NULL on error so leave that for the default case,
402 * The ones that expect "0" need to be handled */
403 case SKIN_TOKEN_FILE_FREQUENCY:
404 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
405 case SKIN_TOKEN_FILE_SIZE:
406 #ifdef HAVE_TAGCACHE
407 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
408 case SKIN_TOKEN_DATABASE_RATING:
409 case SKIN_TOKEN_DATABASE_AUTOSCORE:
410 #endif
411 if (intval)
412 *intval = 0;
413 return "0";
414 default:
415 return get_filename_token(token, filename, buf, buf_size);
418 return buf;
421 #if CONFIG_TUNER
423 /* Formats the frequency (specified in Hz) in MHz, */
424 /* with one or two digits after the decimal point -- */
425 /* depending on the frequency changing step. */
426 /* Returns buf */
427 static char *format_freq_MHz(int freq, int freq_step, char *buf, int buf_size)
429 int scale, div;
430 char *fmt;
431 if (freq_step < 100000)
433 /* Format with two digits after decimal point */
434 scale = 10000;
435 fmt = "%d.%02d";
437 else
439 /* Format with one digit after decimal point */
440 scale = 100000;
441 fmt = "%d.%d";
443 div = 1000000 / scale;
444 freq = freq / scale;
445 snprintf(buf, buf_size, fmt, freq/div, freq%div);
446 return buf;
450 /* Tokens which are really only used by the radio screen go in here */
451 const char *get_radio_token(struct wps_token *token, int preset_offset,
452 char *buf, int buf_size, int limit, int *intval)
454 const struct fm_region_data *region_data =
455 &(fm_region_data[global_settings.fm_region]);
456 (void)limit;
457 switch (token->type)
459 /* Radio/tuner tokens */
460 case SKIN_TOKEN_TUNER_TUNED:
461 if (tuner_get(RADIO_TUNED))
462 return "t";
463 return NULL;
464 case SKIN_TOKEN_TUNER_SCANMODE:
465 if (radio_scan_mode())
466 return "s";
467 return NULL;
468 case SKIN_TOKEN_TUNER_STEREO:
469 if (radio_is_stereo())
470 return "s";
471 return NULL;
472 case SKIN_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
473 return format_freq_MHz(region_data->freq_min,
474 region_data->freq_step, buf, buf_size);
475 case SKIN_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
476 return format_freq_MHz(region_data->freq_max,
477 region_data->freq_step, buf, buf_size);
478 case SKIN_TOKEN_TUNER_CURFREQ:
479 return format_freq_MHz(radio_current_frequency(),
480 region_data->freq_step, buf, buf_size);
481 #ifdef HAVE_RADIO_RSSI
482 case SKIN_TOKEN_TUNER_RSSI:
483 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI));
484 if (intval)
486 int val = tuner_get(RADIO_RSSI);
487 int min = tuner_get(RADIO_RSSI_MIN);
488 int max = tuner_get(RADIO_RSSI_MAX);
489 if (limit == TOKEN_VALUE_ONLY)
491 *intval = val;
493 else
495 *intval = 1+(limit-1)*(val-min)/(max-1-min);
498 return buf;
499 case SKIN_TOKEN_TUNER_RSSI_MIN:
500 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MIN));
501 return buf;
502 case SKIN_TOKEN_TUNER_RSSI_MAX:
503 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MAX));
504 return buf;
505 #endif
506 case SKIN_TOKEN_PRESET_NAME:
507 case SKIN_TOKEN_PRESET_FREQ:
508 case SKIN_TOKEN_PRESET_ID:
510 int preset_count = radio_preset_count();
511 int cur_preset = radio_current_preset();
512 if (preset_count == 0 || cur_preset < 0)
513 return NULL;
514 int preset = cur_preset + preset_offset;
515 /* make sure it's in the valid range */
516 preset %= preset_count;
517 if (preset < 0)
518 preset += preset_count;
519 if (token->type == SKIN_TOKEN_PRESET_NAME)
520 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
521 else if (token->type == SKIN_TOKEN_PRESET_FREQ)
522 format_freq_MHz(radio_get_preset(preset)->frequency,
523 region_data->freq_step, buf, buf_size);
524 else
525 snprintf(buf, buf_size, "%d", preset + 1);
526 return buf;
528 case SKIN_TOKEN_PRESET_COUNT:
529 snprintf(buf, buf_size, "%d", radio_preset_count());
530 if (intval)
531 *intval = radio_preset_count();
532 return buf;
533 case SKIN_TOKEN_HAVE_RDS:
534 #ifdef HAVE_RDS_CAP
535 return "rds";
536 case SKIN_TOKEN_RDS_NAME:
537 return tuner_get_rds_info(RADIO_RDS_NAME);
538 case SKIN_TOKEN_RDS_TEXT:
539 return tuner_get_rds_info(RADIO_RDS_TEXT);
540 #else
541 return NULL; /* end of the SKIN_TOKEN_HAVE_RDS case */
542 #endif /* HAVE_RDS_CAP */
543 default:
544 return NULL;
546 return NULL;
548 #endif
550 static struct mp3entry* get_mp3entry_from_offset(int offset, char **filename)
552 struct mp3entry* pid3 = NULL;
553 struct wps_state *state = skin_get_global_state();
554 struct cuesheet *cue = state->id3 ? state->id3->cuesheet : NULL;
555 const char *fname = NULL;
556 if (cue && cue->curr_track_idx + offset < cue->track_count)
557 pid3 = state->id3;
558 else if (offset == 0)
559 pid3 = state->id3;
560 else if (offset == 1)
561 pid3 = state->nid3;
562 else
564 static char filename_buf[MAX_PATH + 1];
565 fname = playlist_peek(offset, filename_buf, sizeof(filename_buf));
566 *filename = (char*)fname;
567 #if CONFIG_CODEC == SWCODEC
568 static struct mp3entry tempid3;
569 if (
570 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
571 tagcache_fill_tags(&tempid3, fname) ||
572 #endif
573 audio_peek_track(&tempid3, offset)
576 pid3 = &tempid3;
578 #endif
580 return pid3;
583 #ifdef HAVE_LCD_CHARCELLS
584 static void format_player_progress(struct gui_wps *gwps)
586 struct wps_state *state = skin_get_global_state();
587 struct screen *display = gwps->display;
588 unsigned char progress_pattern[7];
589 int pos = 0;
590 int i;
592 int elapsed, length;
593 if (LIKELY(state->id3))
595 elapsed = state->id3->elapsed;
596 length = state->id3->length;
598 else
600 elapsed = 0;
601 length = 0;
604 if (length)
605 pos = 36 * (elapsed + state->ff_rewind_count) / length;
607 for (i = 0; i < 7; i++, pos -= 5)
609 if (pos <= 0)
610 progress_pattern[i] = 0x1fu;
611 else if (pos >= 5)
612 progress_pattern[i] = 0x00u;
613 else
614 progress_pattern[i] = 0x1fu >> pos;
617 display->define_pattern(gwps->data->wps_progress_pat[0], progress_pattern);
620 static void format_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
622 static const unsigned char numbers[10][4] = {
623 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
624 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
625 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
626 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
627 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
628 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
629 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
630 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
631 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
632 {0x0e, 0x0e, 0x02, 0x0e} /* 9 */
635 struct wps_state *state = skin_get_global_state();
636 struct screen *display = gwps->display;
637 struct wps_data *data = gwps->data;
638 unsigned char progress_pattern[7];
639 char timestr[10];
640 int time;
641 int time_idx = 0;
642 int pos = 0;
643 int pat_idx = 1;
644 int digit, i, j;
645 bool softchar;
647 int elapsed, length;
648 if (LIKELY(state->id3))
650 elapsed = state->id3->elapsed;
651 length = state->id3->length;
653 else
655 elapsed = 0;
656 length = 0;
659 if (buf_size < 34) /* worst case: 11x UTF-8 char + \0 */
660 return;
662 time = elapsed + state->ff_rewind_count;
663 if (length)
664 pos = 55 * time / length;
666 memset(timestr, 0, sizeof(timestr));
667 format_time(timestr, sizeof(timestr)-2, time);
668 timestr[strlen(timestr)] = ':'; /* always safe */
670 for (i = 0; i < 11; i++, pos -= 5)
672 softchar = false;
673 memset(progress_pattern, 0, sizeof(progress_pattern));
675 if ((digit = timestr[time_idx]))
677 softchar = true;
678 digit -= '0';
680 if (timestr[time_idx + 1] == ':') /* ones, left aligned */
682 memcpy(progress_pattern, numbers[digit], 4);
683 time_idx += 2;
685 else /* tens, shifted right */
687 for (j = 0; j < 4; j++)
688 progress_pattern[j] = numbers[digit][j] >> 1;
690 if (time_idx > 0) /* not the first group, add colon in front */
692 progress_pattern[1] |= 0x10u;
693 progress_pattern[3] |= 0x10u;
695 time_idx++;
698 if (pos >= 5)
699 progress_pattern[5] = progress_pattern[6] = 0x1fu;
702 if (pos > 0 && pos < 5)
704 softchar = true;
705 progress_pattern[5] = progress_pattern[6] = (~0x1fu >> pos) & 0x1fu;
708 if (softchar && pat_idx < 8)
710 display->define_pattern(data->wps_progress_pat[pat_idx],
711 progress_pattern);
712 buf = utf8encode(data->wps_progress_pat[pat_idx], buf);
713 pat_idx++;
715 else if (pos <= 0)
716 buf = utf8encode(' ', buf);
717 else
718 buf = utf8encode(0xe115, buf); /* 2/7 _ */
720 *buf = '\0';
723 #endif /* HAVE_LCD_CHARCELLS */
725 /* Don't inline this; it was broken out of get_token_value to reduce stack
726 * usage.
728 static const char* NOINLINE get_lif_token_value(struct gui_wps *gwps,
729 struct logical_if *lif,
730 int offset, char *buf,
731 int buf_size)
733 int a = lif->num_options;
734 int b;
735 const char* out_text = get_token_value(gwps, lif->token, offset,
736 buf, buf_size, &a);
737 if (a == -1 && lif->token->type != SKIN_TOKEN_VOLUME)
738 a = (out_text && *out_text) ? 1 : 0;
739 switch (lif->operand.type)
741 case STRING:
742 if (lif->op == IF_EQUALS)
743 return (out_text && strcmp(out_text, lif->operand.data.text) == 0)
744 ? "eq" : NULL;
745 else
746 return NULL;
747 break;
748 case INTEGER:
749 case DECIMAL:
750 b = lif->operand.data.number;
751 break;
752 case CODE:
754 char temp_buf[MAX_PATH];
755 const char *outb;
756 struct wps_token *token = lif->operand.data.code->data;
757 b = lif->num_options;
758 outb = get_token_value(gwps, token, offset, temp_buf,
759 sizeof(temp_buf), &b);
760 if (b == -1 && lif->token->type != SKIN_TOKEN_VOLUME)
762 if (!out_text || !outb)
763 return (lif->op == IF_EQUALS) ? NULL : "neq";
764 bool equal = strcmp(out_text, outb) == 0;
765 if (lif->op == IF_EQUALS)
766 return equal ? "eq" : NULL;
767 else if (lif->op == IF_NOTEQUALS)
768 return !equal ? "neq" : NULL;
769 else
770 b = (outb && *outb) ? 1 : 0;
773 break;
774 case DEFAULT:
775 break;
778 switch (lif->op)
780 case IF_EQUALS:
781 return a == b ? "eq" : NULL;
782 case IF_NOTEQUALS:
783 return a != b ? "neq" : NULL;
784 case IF_LESSTHAN:
785 return a < b ? "lt" : NULL;
786 case IF_LESSTHAN_EQ:
787 return a <= b ? "lte" : NULL;
788 case IF_GREATERTHAN:
789 return a > b ? "gt" : NULL;
790 case IF_GREATERTHAN_EQ:
791 return a >= b ? "gte" : NULL;
793 return NULL;
796 /* Return the tags value as text. buf should be used as temp storage if needed.
798 intval is used with conditionals/enums: when this function is called,
799 intval should contain the number of options in the conditional/enum.
800 When this function returns, intval is -1 if the tag is non numeric or,
801 if the tag is numeric, *intval is the enum case we want to go to (between 1
802 and the original value of *intval, inclusive).
803 When not treating a conditional/enum, intval should be NULL.
805 const char *get_token_value(struct gui_wps *gwps,
806 struct wps_token *token, int offset,
807 char *buf, int buf_size,
808 int *intval)
810 if (!gwps)
811 return NULL;
813 struct wps_data *data = gwps->data;
814 struct wps_state *state = skin_get_global_state();
815 struct mp3entry *id3; /* Think very carefully about using this.
816 maybe get_id3_token() is the better place? */
817 const char *out_text = NULL;
818 char *filename = NULL;
820 if (!data || !state)
821 return NULL;
823 id3 = get_mp3entry_from_offset(token->next? 1: offset, &filename);
824 if (id3)
825 filename = id3->path;
827 #if CONFIG_RTC
828 struct tm* tm = NULL;
830 /* if the token is an RTC one, update the time
831 and do the necessary checks */
832 if (token->type >= SKIN_TOKENS_RTC_BEGIN
833 && token->type <= SKIN_TOKENS_RTC_END)
835 tm = get_time();
837 if (!valid_time(tm))
838 return NULL;
840 #endif
842 int limit = 1;
843 if (intval)
845 limit = *intval;
846 *intval = -1;
849 if (id3 && id3 == state->id3 && id3->cuesheet )
851 out_text = get_cuesheetid3_token(token, id3,
852 token->next?1:offset, buf, buf_size);
853 if (out_text)
854 return out_text;
856 out_text = get_id3_token(token, id3, filename, buf, buf_size, limit, intval);
857 if (out_text)
858 return out_text;
859 #if CONFIG_TUNER
860 out_text = get_radio_token(token, offset, buf, buf_size, limit, intval);
861 if (out_text)
862 return out_text;
863 #endif
865 switch (token->type)
867 case SKIN_TOKEN_LOGICAL_IF:
869 struct logical_if *lif = token->value.data;
870 return get_lif_token_value(gwps, lif, offset, buf, buf_size);
872 break;
874 case SKIN_TOKEN_CHARACTER:
875 if (token->value.c == '\n')
876 return NULL;
877 return &(token->value.c);
879 case SKIN_TOKEN_STRING:
880 return (char*)token->value.data;
882 case SKIN_TOKEN_TRANSLATEDSTRING:
883 return (char*)P2STR(ID2P(token->value.i));
885 case SKIN_TOKEN_PLAYLIST_ENTRIES:
886 snprintf(buf, buf_size, "%d", playlist_amount());
887 if (intval)
888 *intval = playlist_amount();
889 return buf;
890 #ifdef HAVE_LCD_BITMAP
891 case SKIN_TOKEN_LIST_TITLE_TEXT:
892 return sb_get_title(gwps->display->screen_type);
893 case SKIN_TOKEN_LIST_TITLE_ICON:
894 if (intval)
895 *intval = sb_get_icon(gwps->display->screen_type);
896 snprintf(buf, buf_size, "%d",sb_get_icon(gwps->display->screen_type));
897 return buf;
898 case SKIN_TOKEN_LIST_ITEM_TEXT:
899 return skinlist_get_item_text();
900 case SKIN_TOKEN_LIST_ITEM_IS_SELECTED:
901 return skinlist_is_selected_item()?"s":"";
902 case SKIN_TOKEN_LIST_ITEM_ICON:
903 if (intval)
904 *intval = skinlist_get_item_icon();
905 snprintf(buf, buf_size, "%d",skinlist_get_item_icon());
906 return buf;
907 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR:
908 return skinlist_needs_scrollbar(gwps->display->screen_type) ? "s" : "";
909 #endif
910 case SKIN_TOKEN_PLAYLIST_NAME:
911 return playlist_name(NULL, buf, buf_size);
913 case SKIN_TOKEN_PLAYLIST_POSITION:
914 snprintf(buf, buf_size, "%d", playlist_get_display_index()+offset);
915 if (intval)
916 *intval = playlist_get_display_index()+offset;
917 return buf;
919 case SKIN_TOKEN_PLAYLIST_SHUFFLE:
920 if ( global_settings.playlist_shuffle )
921 return "s";
922 else
923 return NULL;
924 break;
926 case SKIN_TOKEN_VOLUME:
927 snprintf(buf, buf_size, "%d", global_settings.volume);
928 if (intval)
930 int minvol = sound_min(SOUND_VOLUME);
931 if (limit == TOKEN_VALUE_ONLY)
933 *intval = global_settings.volume;
935 else if (global_settings.volume == minvol)
937 *intval = 1;
939 else if (global_settings.volume == 0)
941 *intval = limit - 1;
943 else if (global_settings.volume > 0)
945 *intval = limit;
947 else
949 *intval = (limit-3) * (global_settings.volume - minvol - 1)
950 / (-1 - minvol) + 2;
953 return buf;
954 #ifdef HAVE_ALBUMART
955 case SKIN_TOKEN_ALBUMART_FOUND:
956 if (data->albumart)
958 int handle = -1;
959 handle = playback_current_aa_hid(data->playback_aa_slot);
960 #if CONFIG_TUNER
961 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
963 struct dim dim = {data->albumart->width, data->albumart->height};
964 handle = radio_get_art_hid(&dim);
966 #endif
967 if (handle >= 0)
968 return "C";
970 return NULL;
971 #endif
973 case SKIN_TOKEN_BATTERY_PERCENT:
975 int l = battery_level();
977 if (intval)
979 if (limit == TOKEN_VALUE_ONLY)
981 *intval = l;
983 else
985 limit = MAX(limit, 3);
986 if (l > -1) {
987 /* First enum is used for "unknown level",
988 * last enum is used for 100%.
990 *intval = (limit - 2) * l / 100 + 2;
991 } else {
992 *intval = 1;
997 if (l > -1) {
998 snprintf(buf, buf_size, "%d", l);
999 return buf;
1000 } else {
1001 return "?";
1005 case SKIN_TOKEN_BATTERY_VOLTS:
1007 unsigned int v = battery_voltage();
1008 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
1009 return buf;
1012 case SKIN_TOKEN_BATTERY_TIME:
1014 int t = battery_time();
1015 if (t >= 0)
1016 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
1017 else
1018 return "?h ?m";
1019 return buf;
1022 #if CONFIG_CHARGING
1023 case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED:
1025 if(charger_input_state==CHARGER)
1026 return "p";
1027 else
1028 return NULL;
1030 #endif
1031 #if CONFIG_CHARGING >= CHARGING_MONITOR
1032 case SKIN_TOKEN_BATTERY_CHARGING:
1034 if (charge_state == CHARGING || charge_state == TOPOFF) {
1035 return "c";
1036 } else {
1037 return NULL;
1040 #endif
1041 #ifdef HAVE_USB_POWER
1042 case SKIN_TOKEN_USB_POWERED:
1043 if (usb_powered())
1044 return "u";
1045 return NULL;
1046 #endif
1047 case SKIN_TOKEN_BATTERY_SLEEPTIME:
1049 if (get_sleep_timer() == 0)
1050 return NULL;
1051 else
1053 format_time(buf, buf_size, get_sleep_timer() * 1000);
1054 return buf;
1058 case SKIN_TOKEN_PLAYBACK_STATUS:
1060 int status = current_playmode();
1061 /* music */
1062 int mode = 1; /* stop */
1063 if (status == STATUS_PLAY)
1064 mode = 2; /* play */
1065 if (state->is_fading ||
1066 (status == STATUS_PAUSE && !status_get_ffmode()))
1067 mode = 3; /* pause */
1068 else
1069 { /* ff / rwd */
1070 if (status_get_ffmode() == STATUS_FASTFORWARD)
1071 mode = 4;
1072 if (status_get_ffmode() == STATUS_FASTBACKWARD)
1073 mode = 5;
1075 #ifdef HAVE_RECORDING
1076 /* recording */
1077 if (status == STATUS_RECORD)
1078 mode = 6;
1079 else if (status == STATUS_RECORD_PAUSE)
1080 mode = 7;
1081 #endif
1082 #if CONFIG_TUNER
1083 /* radio */
1084 if (status == STATUS_RADIO)
1085 mode = 8;
1086 else if (status == STATUS_RADIO_PAUSE)
1087 mode = 9;
1088 #endif
1090 if (intval) {
1091 *intval = mode;
1094 snprintf(buf, buf_size, "%d", mode-1);
1095 return buf;
1098 case SKIN_TOKEN_REPEAT_MODE:
1099 if (intval)
1100 *intval = global_settings.repeat_mode + 1;
1101 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
1102 return buf;
1104 case SKIN_TOKEN_RTC_PRESENT:
1105 #if CONFIG_RTC
1106 return "c";
1107 #else
1108 return NULL;
1109 #endif
1111 #if CONFIG_RTC
1112 case SKIN_TOKEN_RTC_12HOUR_CFG:
1113 if (intval)
1114 *intval = global_settings.timeformat + 1;
1115 snprintf(buf, buf_size, "%d", global_settings.timeformat);
1116 return buf;
1118 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1119 /* d: day of month (01..31) */
1120 snprintf(buf, buf_size, "%02d", tm->tm_mday);
1121 if (intval)
1122 *intval = tm->tm_mday - 1;
1123 return buf;
1125 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1126 /* e: day of month, blank padded ( 1..31) */
1127 snprintf(buf, buf_size, "%2d", tm->tm_mday);
1128 if (intval)
1129 *intval = tm->tm_mday - 1;
1130 return buf;
1132 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1133 /* H: hour (00..23) */
1134 snprintf(buf, buf_size, "%02d", tm->tm_hour);
1135 if (intval)
1136 *intval = tm->tm_hour;
1137 return buf;
1139 case SKIN_TOKEN_RTC_HOUR_24:
1140 /* k: hour ( 0..23) */
1141 snprintf(buf, buf_size, "%2d", tm->tm_hour);
1142 if (intval)
1143 *intval = tm->tm_hour;
1144 return buf;
1146 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1147 /* I: hour (01..12) */
1148 snprintf(buf, buf_size, "%02d",
1149 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1150 if (intval)
1151 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1152 return buf;
1154 case SKIN_TOKEN_RTC_HOUR_12:
1155 /* l: hour ( 1..12) */
1156 snprintf(buf, buf_size, "%2d",
1157 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1158 if (intval)
1159 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1160 return buf;
1162 case SKIN_TOKEN_RTC_MONTH:
1163 /* m: month (01..12) */
1164 if (intval)
1165 *intval = tm->tm_mon + 1;
1166 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
1167 return buf;
1169 case SKIN_TOKEN_RTC_MINUTE:
1170 /* M: minute (00..59) */
1171 snprintf(buf, buf_size, "%02d", tm->tm_min);
1172 if (intval)
1173 *intval = tm->tm_min;
1174 return buf;
1176 case SKIN_TOKEN_RTC_SECOND:
1177 /* S: second (00..59) */
1178 snprintf(buf, buf_size, "%02d", tm->tm_sec);
1179 if (intval)
1180 *intval = tm->tm_sec;
1181 return buf;
1183 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1184 /* y: last two digits of year (00..99) */
1185 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
1186 if (intval)
1187 *intval = tm->tm_year % 100;
1188 return buf;
1190 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1191 /* Y: year (1970...) */
1192 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
1193 if (intval)
1194 *intval = tm->tm_year + 1900;
1195 return buf;
1197 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1198 /* p: upper case AM or PM indicator */
1199 if (intval)
1200 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1201 return tm->tm_hour/12 == 0 ? "AM" : "PM";
1203 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1204 /* P: lower case am or pm indicator */
1205 if (intval)
1206 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1207 return tm->tm_hour/12 == 0 ? "am" : "pm";
1209 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1210 /* a: abbreviated weekday name (Sun..Sat) */
1211 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
1213 case SKIN_TOKEN_RTC_MONTH_NAME:
1214 /* b: abbreviated month name (Jan..Dec) */
1215 return str(LANG_MONTH_JANUARY + tm->tm_mon);
1217 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1218 /* u: day of week (1..7); 1 is Monday */
1219 if (intval)
1220 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
1221 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
1222 return buf;
1224 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1225 /* w: day of week (0..6); 0 is Sunday */
1226 if (intval)
1227 *intval = tm->tm_wday + 1;
1228 snprintf(buf, buf_size, "%1d", tm->tm_wday);
1229 return buf;
1230 #else
1231 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1232 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1233 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1234 case SKIN_TOKEN_RTC_HOUR_24:
1235 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1236 case SKIN_TOKEN_RTC_HOUR_12:
1237 case SKIN_TOKEN_RTC_MONTH:
1238 case SKIN_TOKEN_RTC_MINUTE:
1239 case SKIN_TOKEN_RTC_SECOND:
1240 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1241 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1242 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1243 return "--";
1244 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1245 return "----";
1246 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1247 case SKIN_TOKEN_RTC_MONTH_NAME:
1248 return "---";
1249 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1250 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1251 return "-";
1252 #endif
1254 #ifdef HAVE_LCD_CHARCELLS
1255 case SKIN_TOKEN_PROGRESSBAR:
1257 char *end;
1258 format_player_progress(gwps);
1259 end = utf8encode(data->wps_progress_pat[0], buf);
1260 *end = '\0';
1261 return buf;
1264 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1265 if(is_new_player())
1267 /* we need 11 characters (full line) for
1268 progress-bar */
1269 strlcpy(buf, " ", buf_size);
1270 format_player_fullbar(gwps,buf,buf_size);
1271 DEBUGF("bar='%s'\n",buf);
1273 else
1275 /* Tell the user if we have an OldPlayer */
1276 strlcpy(buf, " <Old LCD> ", buf_size);
1278 return buf;
1279 #endif
1282 #ifdef HAVE_LCD_BITMAP
1283 /* peakmeter */
1284 case SKIN_TOKEN_PEAKMETER_LEFT:
1285 case SKIN_TOKEN_PEAKMETER_RIGHT:
1287 int left, right, val;
1288 peak_meter_current_vals(&left, &right);
1289 val = token->type == SKIN_TOKEN_PEAKMETER_LEFT ?
1290 left : right;
1291 val = peak_meter_scale_value(val, limit==1 ? MAX_PEAK : limit);
1292 if (intval)
1293 *intval = val;
1294 snprintf(buf, buf_size, "%d", val);
1295 data->peak_meter_enabled = true;
1296 return buf;
1298 #endif
1300 #if (CONFIG_CODEC == SWCODEC)
1301 case SKIN_TOKEN_CROSSFADE:
1302 #ifdef HAVE_CROSSFADE
1303 if (intval)
1304 *intval = global_settings.crossfade + 1;
1305 snprintf(buf, buf_size, "%d", global_settings.crossfade);
1306 #else
1307 snprintf(buf, buf_size, "%d", 0);
1308 #endif
1309 return buf;
1311 case SKIN_TOKEN_REPLAYGAIN:
1313 int val;
1315 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
1316 val = 1; /* off */
1317 else
1319 int type;
1320 if (LIKELY(id3))
1321 type = get_replaygain_mode(id3->track_gain != 0,
1322 id3->album_gain != 0);
1323 else
1324 type = -1;
1326 if (type < 0)
1327 val = 6; /* no tag */
1328 else
1329 val = type + 2;
1331 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
1332 val += 2;
1335 if (intval)
1336 *intval = val;
1338 switch (val)
1340 case 1:
1341 case 6:
1342 return "+0.00 dB";
1343 break;
1344 /* due to above, coming here with !id3 shouldn't be possible */
1345 case 2:
1346 case 4:
1347 replaygain_itoa(buf, buf_size, id3->track_level);
1348 break;
1349 case 3:
1350 case 5:
1351 replaygain_itoa(buf, buf_size, id3->album_level);
1352 break;
1354 return buf;
1356 #endif /* (CONFIG_CODEC == SWCODEC) */
1358 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHSCREEN)
1359 case SKIN_TOKEN_SOUND_PITCH:
1361 int32_t pitch = sound_get_pitch();
1362 snprintf(buf, buf_size, "%ld.%ld",
1363 pitch / PITCH_SPEED_PRECISION,
1364 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1366 if (intval)
1367 *intval = pitch_speed_enum(limit, pitch,
1368 PITCH_SPEED_PRECISION * 100);
1369 return buf;
1371 #endif
1373 #if (CONFIG_CODEC == SWCODEC) && defined (HAVE_PITCHSCREEN)
1374 case SKIN_TOKEN_SOUND_SPEED:
1376 int32_t pitch = sound_get_pitch();
1377 int32_t speed;
1378 if (dsp_timestretch_available())
1379 speed = GET_SPEED(pitch, dsp_get_timestretch());
1380 else
1381 speed = pitch;
1382 snprintf(buf, buf_size, "%ld.%ld",
1383 speed / PITCH_SPEED_PRECISION,
1384 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1385 if (intval)
1386 *intval = pitch_speed_enum(limit, speed,
1387 PITCH_SPEED_PRECISION * 100);
1388 return buf;
1390 #endif
1392 case SKIN_TOKEN_MAIN_HOLD:
1393 #ifdef HAVE_TOUCHSCREEN
1394 if (data->touchscreen_locked)
1395 return "t";
1396 #endif
1397 #ifdef HAS_BUTTON_HOLD
1398 if (button_hold())
1399 #else
1400 if (is_keys_locked())
1401 #endif /*hold switch or softlock*/
1402 return "h";
1403 else
1404 return NULL;
1406 #ifdef HAS_REMOTE_BUTTON_HOLD
1407 case SKIN_TOKEN_REMOTE_HOLD:
1408 if (remote_button_hold())
1409 return "r";
1410 else
1411 return NULL;
1412 #endif
1414 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1415 case SKIN_TOKEN_VLED_HDD:
1416 if(led_read(HZ/2))
1417 return "h";
1418 else
1419 return NULL;
1420 #endif
1421 case SKIN_TOKEN_BUTTON_VOLUME:
1422 if (global_status.last_volume_change &&
1423 TIME_BEFORE(current_tick, global_status.last_volume_change +
1424 token->value.i))
1425 return "v";
1426 return NULL;
1428 case SKIN_TOKEN_LASTTOUCH:
1430 #ifdef HAVE_TOUCHSCREEN
1431 unsigned int last_touch = touchscreen_last_touch();
1432 struct touchregion_lastpress *data = token->value.data;
1433 if (data->region)
1434 last_touch = data->region->last_press;
1436 if (last_touch != 0xffff &&
1437 TIME_BEFORE(current_tick, data->timeout + last_touch))
1438 return "t";
1439 #endif
1441 return NULL;
1442 case SKIN_TOKEN_HAVE_TOUCH:
1443 #ifdef HAVE_TOUCHSCREEN
1444 return "t";
1445 #else
1446 return NULL;
1447 #endif
1449 case SKIN_TOKEN_SETTING:
1451 const struct settings_list *s = settings+token->value.i;
1452 if (intval)
1454 /* Handle contionals */
1455 switch (s->flags&F_T_MASK)
1457 case F_T_INT:
1458 case F_T_UINT:
1459 if (s->flags&F_T_SOUND)
1461 /* %?St|name|<min|min+1|...|max-1|max> */
1462 int sound_setting = s->sound_setting->setting;
1463 /* settings with decimals can't be used in conditionals */
1464 if (sound_numdecimals(sound_setting) == 0)
1466 *intval = (*(int*)s->setting-sound_min(sound_setting))
1467 /sound_steps(sound_setting) + 1;
1469 else
1470 *intval = -1;
1472 else if (s->flags&F_RGB)
1473 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1474 /* shouldn't overflow since colors are stored
1475 * on 16 bits ...
1476 * but this is pretty useless anyway */
1477 *intval = *(int*)s->setting + 1;
1478 else if (s->cfg_vals == NULL)
1479 /* %?St|name|<1st choice|2nd choice|...> */
1480 *intval = (*(int*)s->setting-s->int_setting->min)
1481 /s->int_setting->step + 1;
1482 else
1483 /* %?St|name|<1st choice|2nd choice|...> */
1484 /* Not sure about this one. cfg_name/vals are
1485 * indexed from 0 right? */
1486 *intval = *(int*)s->setting + 1;
1487 break;
1488 case F_T_BOOL:
1489 /* %?St|name|<if true|if false> */
1490 *intval = *(bool*)s->setting?1:2;
1491 break;
1492 case F_T_CHARPTR:
1493 case F_T_UCHARPTR:
1494 /* %?St|name|<if non empty string|if empty>
1495 * The string's emptyness discards the setting's
1496 * prefix and suffix */
1497 *intval = ((char*)s->setting)[0]?1:2;
1498 /* if there is a prefix we should ignore it here */
1499 if (s->filename_setting->prefix)
1500 return (char*)s->setting;
1501 break;
1502 default:
1503 /* This shouldn't happen ... but you never know */
1504 *intval = -1;
1505 break;
1508 /* Special handlng for filenames because we dont want to show the prefix */
1509 if ((s->flags&F_T_MASK) == F_T_UCHARPTR ||
1510 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1512 if (s->filename_setting->prefix)
1513 return (char*)s->setting;
1515 cfg_to_string(token->value.i,buf,buf_size);
1516 return buf;
1518 case SKIN_TOKEN_HAVE_TUNER:
1519 #if CONFIG_TUNER
1520 if (radio_hardware_present())
1521 return "r";
1522 #endif
1523 return NULL;
1524 /* Recording tokens */
1525 case SKIN_TOKEN_HAVE_RECORDING:
1526 #ifdef HAVE_RECORDING
1527 return "r";
1528 #else
1529 return NULL;
1530 #endif
1532 #ifdef HAVE_RECORDING
1533 case SKIN_TOKEN_IS_RECORDING:
1534 if (audio_status() == AUDIO_STATUS_RECORD)
1535 return "r";
1536 return NULL;
1537 case SKIN_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1539 #if CONFIG_CODEC == SWCODEC
1540 unsigned long samprk;
1541 int rec_freq = global_settings.rec_frequency;
1543 #ifdef SIMULATOR
1544 samprk = 44100;
1545 #else
1546 #if defined(HAVE_SPDIF_REC)
1547 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1549 /* Use rate in use, not current measured rate if it changed */
1550 samprk = pcm_rec_sample_rate();
1551 rec_freq = 0;
1552 while (rec_freq < SAMPR_NUM_FREQ &&
1553 audio_master_sampr_list[rec_freq] != samprk)
1555 rec_freq++;
1558 else
1559 #endif
1560 samprk = rec_freq_sampr[rec_freq];
1561 #endif /* SIMULATOR */
1562 if (intval)
1564 switch (rec_freq)
1566 REC_HAVE_96_(case REC_FREQ_96:
1567 *intval = 1;
1568 break;)
1569 REC_HAVE_88_(case REC_FREQ_88:
1570 *intval = 2;
1571 break;)
1572 REC_HAVE_64_(case REC_FREQ_64:
1573 *intval = 3;
1574 break;)
1575 REC_HAVE_48_(case REC_FREQ_48:
1576 *intval = 4;
1577 break;)
1578 REC_HAVE_44_(case REC_FREQ_44:
1579 *intval = 5;
1580 break;)
1581 REC_HAVE_32_(case REC_FREQ_32:
1582 *intval = 6;
1583 break;)
1584 REC_HAVE_24_(case REC_FREQ_24:
1585 *intval = 7;
1586 break;)
1587 REC_HAVE_22_(case REC_FREQ_22:
1588 *intval = 8;
1589 break;)
1590 REC_HAVE_16_(case REC_FREQ_16:
1591 *intval = 9;
1592 break;)
1593 REC_HAVE_12_(case REC_FREQ_12:
1594 *intval = 10;
1595 break;)
1596 REC_HAVE_11_(case REC_FREQ_11:
1597 *intval = 11;
1598 break;)
1599 REC_HAVE_8_(case REC_FREQ_8:
1600 *intval = 12;
1601 break;)
1604 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1605 #else /* HWCODEC */
1607 static const char * const freq_strings[] =
1608 {"--", "44", "48", "32", "22", "24", "16"};
1609 int freq = 1 + global_settings.rec_frequency;
1610 #ifdef HAVE_SPDIF_REC
1611 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1613 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1614 freq = 0;
1616 #endif /* HAVE_SPDIF_IN */
1617 if (intval)
1618 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1619 snprintf(buf, buf_size, "%s\n",
1620 freq_strings[global_settings.rec_frequency]);
1621 #endif
1622 return buf;
1624 #if CONFIG_CODEC == SWCODEC
1625 case SKIN_TOKEN_REC_ENCODER:
1627 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1628 if (intval)
1629 *intval = rec_format;
1630 switch (rec_format)
1632 case REC_FORMAT_PCM_WAV:
1633 return "wav";
1634 case REC_FORMAT_AIFF:
1635 return "aiff";
1636 case REC_FORMAT_WAVPACK:
1637 return "wv";
1638 case REC_FORMAT_MPA_L3:
1639 return "MP3";
1640 default:
1641 return NULL;
1643 break;
1645 #endif
1646 case SKIN_TOKEN_REC_BITRATE:
1647 #if CONFIG_CODEC == SWCODEC
1648 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1650 if (intval)
1652 #if 0 /* FIXME: I dont know if this is needed? */
1653 switch (1<<global_settings.mp3_enc_config.bitrate)
1655 case MP3_BITR_CAP_8:
1656 *intval = 1;
1657 break;
1658 case MP3_BITR_CAP_16:
1659 *intval = 2;
1660 break;
1661 case MP3_BITR_CAP_24:
1662 *intval = 3;
1663 break;
1664 case MP3_BITR_CAP_32:
1665 *intval = 4;
1666 break;
1667 case MP3_BITR_CAP_40:
1668 *intval = 5;
1669 break;
1670 case MP3_BITR_CAP_48:
1671 *intval = 6;
1672 break;
1673 case MP3_BITR_CAP_56:
1674 *intval = 7;
1675 break;
1676 case MP3_BITR_CAP_64:
1677 *intval = 8;
1678 break;
1679 case MP3_BITR_CAP_80:
1680 *intval = 9;
1681 break;
1682 case MP3_BITR_CAP_96:
1683 *intval = 10;
1684 break;
1685 case MP3_BITR_CAP_112:
1686 *intval = 11;
1687 break;
1688 case MP3_BITR_CAP_128:
1689 *intval = 12;
1690 break;
1691 case MP3_BITR_CAP_144:
1692 *intval = 13;
1693 break;
1694 case MP3_BITR_CAP_160:
1695 *intval = 14;
1696 break;
1697 case MP3_BITR_CAP_192:
1698 *intval = 15;
1699 break;
1701 #endif
1702 *intval = global_settings.mp3_enc_config.bitrate+1;
1704 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1705 return buf;
1707 else
1708 return NULL; /* Fixme later */
1709 #else /* CONFIG_CODEC == HWCODEC */
1710 if (intval)
1711 *intval = global_settings.rec_quality+1;
1712 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1713 return buf;
1714 #endif
1715 case SKIN_TOKEN_REC_MONO:
1716 if (!global_settings.rec_channels)
1717 return "m";
1718 return NULL;
1720 case SKIN_TOKEN_REC_SECONDS:
1722 int time = (audio_recorded_time() / HZ) % 60;
1723 if (intval)
1724 *intval = time;
1725 snprintf(buf, buf_size, "%02d", time);
1726 return buf;
1728 case SKIN_TOKEN_REC_MINUTES:
1730 int time = (audio_recorded_time() / HZ) / 60;
1731 if (intval)
1732 *intval = time;
1733 snprintf(buf, buf_size, "%02d", time);
1734 return buf;
1736 case SKIN_TOKEN_REC_HOURS:
1738 int time = (audio_recorded_time() / HZ) / 3600;
1739 if (intval)
1740 *intval = time;
1741 snprintf(buf, buf_size, "%02d", time);
1742 return buf;
1745 #endif /* HAVE_RECORDING */
1747 case SKIN_TOKEN_CURRENT_SCREEN:
1749 int curr_screen = get_current_activity();
1750 if (intval)
1752 *intval = curr_screen;
1754 snprintf(buf, buf_size, "%d", curr_screen);
1755 return buf;
1758 case SKIN_TOKEN_LANG_IS_RTL:
1759 return lang_is_rtl() ? "r" : NULL;
1761 #ifdef HAVE_SKIN_VARIABLES
1762 case SKIN_TOKEN_VAR_GETVAL:
1764 struct skin_var* var = token->value.data;
1765 if (intval)
1766 *intval = var->value;
1767 snprintf(buf, buf_size, "%d", var->value);
1768 return buf;
1770 break;
1771 case SKIN_TOKEN_VAR_TIMEOUT:
1773 struct skin_var_lastchange *data = token->value.data;
1774 unsigned int last_change = data->var->last_changed;
1776 if (last_change != 0xffff &&
1777 TIME_BEFORE(current_tick, data->timeout + last_change))
1778 return "t";
1780 return NULL;
1781 #endif
1783 default:
1784 return NULL;