skin engine: completly rework the sbs title handing code
[maemo-rb.git] / apps / gui / skin_engine / skin_tokens.c
blobb5c32584b1c99671b4457a0a648c657423207695
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 #ifdef HAVE_LCD_CHARCELLS
39 #include "hwcompat.h"
40 #endif
41 #include "abrepeat.h"
42 #include "lang.h"
43 #include "misc.h"
44 #include "led.h"
45 #ifdef HAVE_LCD_BITMAP
46 /* Image stuff */
47 #include "albumart.h"
48 #endif
49 #include "dsp.h"
50 #include "playlist.h"
51 #if CONFIG_CODEC == SWCODEC
52 #include "playback.h"
53 #include "tdspeed.h"
54 #endif
55 #include "viewport.h"
56 #include "tagcache.h"
58 #include "wps_internals.h"
59 #include "skin_engine.h"
60 #include "statusbar-skinned.h"
61 #include "root_menu.h"
62 #ifdef HAVE_RECORDING
63 #include "recording.h"
64 #include "pcm_record.h"
65 #endif
66 #include "language.h"
67 #include "usb.h"
68 #if CONFIG_TUNER
69 #include "radio.h"
70 #include "tuner.h"
71 #endif
73 extern struct wps_state wps_state;
75 static const char* get_codectype(const struct mp3entry* id3)
77 if (id3 && id3->codectype < AFMT_NUM_CODECS) {
78 return audio_formats[id3->codectype].label;
79 } else {
80 return NULL;
84 /* Extract a part from a path.
86 * buf - buffer extract part to.
87 * buf_size - size of buffer.
88 * path - path to extract from.
89 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
90 * parent of parent, etc.
92 * Returns buf if the desired level was found, NULL otherwise.
94 char* get_dir(char* buf, int buf_size, const char* path, int level)
96 const char* sep;
97 const char* last_sep;
98 int len;
100 sep = path + strlen(path);
101 last_sep = sep;
103 while (sep > path)
105 if ('/' == *(--sep))
107 if (!level)
108 break;
110 level--;
111 last_sep = sep - 1;
115 if (level || (last_sep <= sep))
116 return NULL;
118 len = MIN(last_sep - sep, buf_size - 1);
119 strlcpy(buf, sep + 1, len + 1);
120 return buf;
123 #if (CONFIG_CODEC != MAS3507D)
124 /* A helper to determine the enum value for pitch/speed.
126 When there are two choices (i.e. boolean), return 1 if the value is
127 different from normal value and 2 if the value is the same as the
128 normal value. E.g. "%?Sp<%Sp>" would show the pitch only when
129 playing at a modified pitch.
131 When there are more than two choices (i.e. enum), the left half of
132 the choices are to show 0..normal range, and the right half of the
133 choices are to show values over that. The last entry is used when
134 it is set to the normal setting, following the rockbox convention
135 to use the last entry for special values.
137 E.g.
139 2 items: %?Sp<0..99 or 101..infinity|100>
140 3 items: %?Sp<0..99|101..infinity|100>
141 4 items: %?Sp<0..49|50..99|101..infinity|100>
142 5 items: %?Sp<0..49|50..99|101..149|150..infinity|100>
143 6 items: %?Sp<0..33|34..66|67..99|101..133|134..infinity|100>
144 7 items: %?Sp<0..33|34..66|67..99|101..133|134..167|167..infinity|100>
146 static int pitch_speed_enum(int range, int32_t val, int32_t normval)
148 int center;
149 int n;
151 if (range < 3)
152 return (val == normval) + 1;
153 if (val == normval)
154 return range;
155 center = range / 2;
156 n = (center * val) / normval + 1;
157 return (range <= n) ? (range - 1) : n;
159 #endif
161 const char *get_cuesheetid3_token(struct wps_token *token, struct mp3entry *id3,
162 int offset_tracks, char *buf, int buf_size)
164 struct cuesheet *cue = id3?id3->cuesheet:NULL;
165 if (!cue || !cue->curr_track)
166 return NULL;
168 struct cue_track_info *track = cue->curr_track;
169 if (offset_tracks)
171 if (cue->curr_track_idx+offset_tracks < cue->track_count)
172 track+=offset_tracks;
173 else
174 return NULL;
176 switch (token->type)
178 case SKIN_TOKEN_METADATA_ARTIST:
179 return *track->performer ? track->performer : NULL;
180 case SKIN_TOKEN_METADATA_COMPOSER:
181 return *track->songwriter ? track->songwriter : NULL;
182 case SKIN_TOKEN_METADATA_ALBUM:
183 return *cue->title ? cue->title : NULL;
184 case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
185 return *cue->performer ? cue->performer : NULL;
186 case SKIN_TOKEN_METADATA_TRACK_TITLE:
187 return *track->title ? track->title : NULL;
188 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
189 snprintf(buf, buf_size, "%d/%d",
190 cue->curr_track_idx+offset_tracks+1, cue->track_count);
191 return buf;
192 default:
193 return NULL;
195 return NULL;
198 static const char* get_filename_token(struct wps_token *token, char* filename,
199 char *buf, int buf_size)
201 if (filename)
203 switch (token->type)
205 case SKIN_TOKEN_FILE_PATH:
206 return filename;
207 case SKIN_TOKEN_FILE_NAME:
208 if (get_dir(buf, buf_size, filename, 0)) {
209 /* Remove extension */
210 char* sep = strrchr(buf, '.');
211 if (NULL != sep) {
212 *sep = 0;
214 return buf;
216 return NULL;
217 case SKIN_TOKEN_FILE_NAME_WITH_EXTENSION:
218 return get_dir(buf, buf_size, filename, 0);
219 case SKIN_TOKEN_FILE_DIRECTORY:
220 return get_dir(buf, buf_size, filename, token->value.i);
221 default:
222 return NULL;
225 return NULL;
228 /* All tokens which only need the info to return a value go in here */
229 const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
230 char *filename, char *buf, int buf_size, int limit, int *intval)
232 struct wps_state *state = &wps_state;
233 if (id3)
235 unsigned long length = id3->length;
236 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
237 switch (token->type)
239 case SKIN_TOKEN_METADATA_ARTIST:
240 return id3->artist;
241 case SKIN_TOKEN_METADATA_COMPOSER:
242 return id3->composer;
243 case SKIN_TOKEN_METADATA_ALBUM:
244 return id3->album;
245 case SKIN_TOKEN_METADATA_ALBUM_ARTIST:
246 return id3->albumartist;
247 case SKIN_TOKEN_METADATA_GROUPING:
248 return id3->grouping;
249 case SKIN_TOKEN_METADATA_GENRE:
250 return id3->genre_string;
251 case SKIN_TOKEN_METADATA_DISC_NUMBER:
252 if (id3->disc_string)
253 return id3->disc_string;
254 if (id3->discnum) {
255 snprintf(buf, buf_size, "%d", id3->discnum);
256 return buf;
258 return NULL;
259 case SKIN_TOKEN_METADATA_TRACK_NUMBER:
260 if (id3->track_string)
261 return id3->track_string;
262 if (id3->tracknum) {
263 snprintf(buf, buf_size, "%d", id3->tracknum);
264 return buf;
266 return NULL;
267 case SKIN_TOKEN_METADATA_TRACK_TITLE:
268 return id3->title;
269 case SKIN_TOKEN_METADATA_VERSION:
270 switch (id3->id3version)
272 case ID3_VER_1_0:
273 return "1";
274 case ID3_VER_1_1:
275 return "1.1";
276 case ID3_VER_2_2:
277 return "2.2";
278 case ID3_VER_2_3:
279 return "2.3";
280 case ID3_VER_2_4:
281 return "2.4";
282 default:
283 break;
285 return NULL;
286 case SKIN_TOKEN_METADATA_YEAR:
287 if( id3->year_string )
288 return id3->year_string;
289 if (id3->year) {
290 snprintf(buf, buf_size, "%d", id3->year);
291 return buf;
293 return NULL;
294 case SKIN_TOKEN_METADATA_COMMENT:
295 return id3->comment;
296 case SKIN_TOKEN_FILE_BITRATE:
297 if(id3->bitrate)
298 snprintf(buf, buf_size, "%d", id3->bitrate);
299 else
300 return "?";
301 return buf;
302 case SKIN_TOKEN_TRACK_TIME_ELAPSED:
303 format_time(buf, buf_size, elapsed);
304 return buf;
306 case SKIN_TOKEN_TRACK_TIME_REMAINING:
307 format_time(buf, buf_size, length - elapsed);
308 return buf;
310 case SKIN_TOKEN_TRACK_LENGTH:
311 format_time(buf, buf_size, length);
312 return buf;
314 case SKIN_TOKEN_TRACK_ELAPSED_PERCENT:
315 if (length <= 0)
316 return NULL;
318 if (intval)
320 if (limit == TOKEN_VALUE_ONLY)
321 limit = 100; /* make it a percentage */
322 *intval = limit * elapsed / length + 1;
324 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
325 return buf;
327 case SKIN_TOKEN_TRACK_STARTING:
329 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
330 if (elapsed < time)
331 return "starting";
333 return NULL;
334 case SKIN_TOKEN_TRACK_ENDING:
336 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
337 if (length - elapsed < time)
338 return "ending";
340 return NULL;
342 case SKIN_TOKEN_FILE_CODEC:
343 if (intval)
345 if(id3->codectype == AFMT_UNKNOWN)
346 *intval = AFMT_NUM_CODECS;
347 else
348 *intval = id3->codectype;
350 return get_codectype(id3);
352 case SKIN_TOKEN_FILE_FREQUENCY:
353 snprintf(buf, buf_size, "%ld", id3->frequency);
354 return buf;
355 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
356 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
357 if ((id3->frequency % 1000) < 100)
358 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
359 else
360 snprintf(buf, buf_size, "%ld.%lu",
361 id3->frequency / 1000,
362 (id3->frequency % 1000) / 100);
363 return buf;
364 case SKIN_TOKEN_FILE_VBR:
365 return (id3->vbr) ? "(avg)" : NULL;
366 case SKIN_TOKEN_FILE_SIZE:
367 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
368 return buf;
370 #ifdef HAVE_TAGCACHE
371 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
372 if (intval)
373 *intval = id3->playcount + 1;
374 snprintf(buf, buf_size, "%ld", id3->playcount);
375 return buf;
376 case SKIN_TOKEN_DATABASE_RATING:
377 if (intval)
378 *intval = id3->rating + 1;
379 snprintf(buf, buf_size, "%d", id3->rating);
380 return buf;
381 case SKIN_TOKEN_DATABASE_AUTOSCORE:
382 if (intval)
383 *intval = id3->score + 1;
384 snprintf(buf, buf_size, "%d", id3->score);
385 return buf;
386 #endif
388 default:
389 return get_filename_token(token, id3->path, buf, buf_size);
392 else /* id3 == NULL, handle the error based on the expected return type */
394 switch (token->type)
396 /* Most tokens expect NULL on error so leave that for the default case,
397 * The ones that expect "0" need to be handled */
398 case SKIN_TOKEN_FILE_FREQUENCY:
399 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
400 case SKIN_TOKEN_FILE_SIZE:
401 #ifdef HAVE_TAGCACHE
402 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
403 case SKIN_TOKEN_DATABASE_RATING:
404 case SKIN_TOKEN_DATABASE_AUTOSCORE:
405 #endif
406 if (intval)
407 *intval = 0;
408 return "0";
409 default:
410 return get_filename_token(token, filename, buf, buf_size);
413 return buf;
416 #if CONFIG_TUNER
418 /* Formats the frequency (specified in Hz) in MHz, */
419 /* with one or two digits after the decimal point -- */
420 /* depending on the frequency changing step. */
421 /* Returns buf */
422 static char *format_freq_MHz(int freq, int freq_step, char *buf, int buf_size)
424 int scale, div;
425 char *fmt;
426 if (freq_step < 100000)
428 /* Format with two digits after decimal point */
429 scale = 10000;
430 fmt = "%d.%02d";
432 else
434 /* Format with one digit after decimal point */
435 scale = 100000;
436 fmt = "%d.%d";
438 div = 1000000 / scale;
439 freq = freq / scale;
440 snprintf(buf, buf_size, fmt, freq/div, freq%div);
441 return buf;
445 /* Tokens which are really only used by the radio screen go in here */
446 const char *get_radio_token(struct wps_token *token, int preset_offset,
447 char *buf, int buf_size, int limit, int *intval)
449 const struct fm_region_data *region_data =
450 &(fm_region_data[global_settings.fm_region]);
451 (void)limit;
452 switch (token->type)
454 /* Radio/tuner tokens */
455 case SKIN_TOKEN_TUNER_TUNED:
456 if (tuner_get(RADIO_TUNED))
457 return "t";
458 return NULL;
459 case SKIN_TOKEN_TUNER_SCANMODE:
460 if (radio_scan_mode())
461 return "s";
462 return NULL;
463 case SKIN_TOKEN_TUNER_STEREO:
464 if (radio_is_stereo())
465 return "s";
466 return NULL;
467 case SKIN_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
468 return format_freq_MHz(region_data->freq_min,
469 region_data->freq_step, buf, buf_size);
470 case SKIN_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
471 return format_freq_MHz(region_data->freq_max,
472 region_data->freq_step, buf, buf_size);
473 case SKIN_TOKEN_TUNER_CURFREQ:
474 return format_freq_MHz(radio_current_frequency(),
475 region_data->freq_step, buf, buf_size);
476 case SKIN_TOKEN_PRESET_NAME:
477 case SKIN_TOKEN_PRESET_FREQ:
478 case SKIN_TOKEN_PRESET_ID:
480 int preset_count = radio_preset_count();
481 int cur_preset = radio_current_preset();
482 if (preset_count == 0 || cur_preset < 0)
483 return NULL;
484 int preset = cur_preset + preset_offset;
485 /* make sure it's in the valid range */
486 preset %= preset_count;
487 if (preset < 0)
488 preset += preset_count;
489 if (token->type == SKIN_TOKEN_PRESET_NAME)
490 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
491 else if (token->type == SKIN_TOKEN_PRESET_FREQ)
492 format_freq_MHz(radio_get_preset(preset)->frequency,
493 region_data->freq_step, buf, buf_size);
494 else
495 snprintf(buf, buf_size, "%d", preset + 1);
496 return buf;
498 case SKIN_TOKEN_PRESET_COUNT:
499 snprintf(buf, buf_size, "%d", radio_preset_count());
500 if (intval)
501 *intval = radio_preset_count();
502 return buf;
503 case SKIN_TOKEN_HAVE_RDS:
504 #ifdef HAVE_RDS_CAP
505 return "rds";
506 case SKIN_TOKEN_RDS_NAME:
507 return tuner_get_rds_info(RADIO_RDS_NAME);
508 case SKIN_TOKEN_RDS_TEXT:
509 return tuner_get_rds_info(RADIO_RDS_TEXT);
510 #else
511 return NULL; /* end of the SKIN_TOKEN_HAVE_RDS case */
512 #endif /* HAVE_RDS_CAP */
513 default:
514 return NULL;
516 return NULL;
518 #endif
520 static struct mp3entry* get_mp3entry_from_offset(int offset, char **filename)
522 struct mp3entry* pid3 = NULL;
523 struct wps_state *state = skin_get_global_state();
524 struct cuesheet *cue = state->id3 ? state->id3->cuesheet : NULL;
525 const char *fname = NULL;
526 if (cue && cue->curr_track_idx + offset < cue->track_count)
527 pid3 = state->id3;
528 else if (offset == 0)
529 pid3 = state->id3;
530 else if (offset == 1)
531 pid3 = state->nid3;
532 else
534 static char filename_buf[MAX_PATH + 1];
535 fname = playlist_peek(offset, filename_buf, sizeof(filename_buf));
536 *filename = (char*)fname;
537 #if CONFIG_CODEC == SWCODEC
538 #ifdef HAVE_TC_RAMCACHE
539 static struct mp3entry tempid3;
540 if (tagcache_fill_tags(&tempid3, fname))
542 pid3 = &tempid3;
544 else
545 #endif
547 if (!audio_peek_track(&pid3, offset))
548 pid3 = NULL;
550 #endif
552 return pid3;
555 /* Return the tags value as text. buf should be used as temp storage if needed.
557 intval is used with conditionals/enums: when this function is called,
558 intval should contain the number of options in the conditional/enum.
559 When this function returns, intval is -1 if the tag is non numeric or,
560 if the tag is numeric, *intval is the enum case we want to go to (between 1
561 and the original value of *intval, inclusive).
562 When not treating a conditional/enum, intval should be NULL.
564 const char *get_token_value(struct gui_wps *gwps,
565 struct wps_token *token, int offset,
566 char *buf, int buf_size,
567 int *intval)
569 if (!gwps)
570 return NULL;
572 struct wps_data *data = gwps->data;
573 struct wps_state *state = skin_get_global_state();
574 struct mp3entry *id3; /* Think very carefully about using this.
575 maybe get_id3_token() is the better place? */
576 const char *out_text = NULL;
577 char *filename = NULL;
579 if (!data || !state)
580 return NULL;
582 id3 = get_mp3entry_from_offset(token->next? 1: offset, &filename);
583 if (id3)
584 filename = id3->path;
586 #if CONFIG_RTC
587 struct tm* tm = NULL;
589 /* if the token is an RTC one, update the time
590 and do the necessary checks */
591 if (token->type >= SKIN_TOKENS_RTC_BEGIN
592 && token->type <= SKIN_TOKENS_RTC_END)
594 tm = get_time();
596 if (!valid_time(tm))
597 return NULL;
599 #endif
601 int limit = 1;
602 if (intval)
604 limit = *intval;
605 *intval = -1;
608 if (id3 && id3 == state->id3 && id3->cuesheet )
610 out_text = get_cuesheetid3_token(token, id3,
611 token->next?1:offset, buf, buf_size);
612 if (out_text)
613 return out_text;
615 out_text = get_id3_token(token, id3, filename, buf, buf_size, limit, intval);
616 if (out_text)
617 return out_text;
618 #if CONFIG_TUNER
619 out_text = get_radio_token(token, offset, buf, buf_size, limit, intval);
620 if (out_text)
621 return out_text;
622 #endif
624 switch (token->type)
626 case SKIN_TOKEN_LOGICAL_IF:
628 struct logical_if *lif = token->value.data;
629 int a = lif->num_options;
630 int b;
631 out_text = get_token_value(gwps, lif->token, offset, buf, buf_size, &a);
632 if (a == -1 && lif->token->type != SKIN_TOKEN_VOLUME)
633 a = (out_text && *out_text) ? 1 : 0;
634 switch (lif->operand.type)
636 case STRING:
637 if (lif->op == IF_EQUALS)
638 return strcmp(out_text, lif->operand.data.text) == 0 ?
639 "eq" : NULL;
640 else
641 return NULL;
642 break;
643 case INTEGER:
644 case DECIMAL:
645 b = lif->operand.data.number;
646 break;
647 case CODE:
649 char temp_buf[MAX_PATH];
650 const char *outb;
651 struct wps_token *token = lif->operand.data.code->data;
652 b = lif->num_options;
653 outb = get_token_value(gwps, token, offset, temp_buf,
654 sizeof(temp_buf), &b);
655 if (b == -1 && lif->token->type != SKIN_TOKEN_VOLUME)
657 if (!out_text || !outb)
658 return (lif->op == IF_EQUALS) ? NULL : "neq";
659 bool equal = strcmp(out_text, outb) == 0;
660 if (lif->op == IF_EQUALS)
661 return equal ? "eq" : NULL;
662 else if (lif->op == IF_NOTEQUALS)
663 return !equal ? "neq" : NULL;
664 else
665 b = (outb && *outb) ? 1 : 0;
668 break;
669 case DEFAULT:
670 break;
673 switch (lif->op)
675 case IF_EQUALS:
676 return a == b ? "eq" : NULL;
677 case IF_NOTEQUALS:
678 return a != b ? "neq" : NULL;
679 case IF_LESSTHAN:
680 return a < b ? "lt" : NULL;
681 case IF_LESSTHAN_EQ:
682 return a <= b ? "lte" : NULL;
683 case IF_GREATERTHAN:
684 return a > b ? "gt" : NULL;
685 case IF_GREATERTHAN_EQ:
686 return a >= b ? "gte" : NULL;
688 return NULL;
690 break;
692 case SKIN_TOKEN_CHARACTER:
693 if (token->value.c == '\n')
694 return NULL;
695 return &(token->value.c);
697 case SKIN_TOKEN_STRING:
698 return (char*)token->value.data;
700 case SKIN_TOKEN_TRANSLATEDSTRING:
701 return (char*)P2STR(ID2P(token->value.i));
703 case SKIN_TOKEN_PLAYLIST_ENTRIES:
704 snprintf(buf, buf_size, "%d", playlist_amount());
705 if (intval)
706 *intval = playlist_amount();
707 return buf;
709 case SKIN_TOKEN_LIST_TITLE_TEXT:
710 return sb_get_title(gwps->display->screen_type);
711 case SKIN_TOKEN_LIST_TITLE_ICON:
712 if (intval)
713 *intval = sb_get_icon(gwps->display->screen_type);
714 snprintf(buf, buf_size, "%d",sb_get_icon(gwps->display->screen_type));
715 return buf;
717 case SKIN_TOKEN_PLAYLIST_NAME:
718 return playlist_name(NULL, buf, buf_size);
720 case SKIN_TOKEN_PLAYLIST_POSITION:
721 snprintf(buf, buf_size, "%d", playlist_get_display_index()+offset);
722 if (intval)
723 *intval = playlist_get_display_index()+offset;
724 return buf;
726 case SKIN_TOKEN_PLAYLIST_SHUFFLE:
727 if ( global_settings.playlist_shuffle )
728 return "s";
729 else
730 return NULL;
731 break;
733 case SKIN_TOKEN_VOLUME:
734 snprintf(buf, buf_size, "%d", global_settings.volume);
735 if (intval)
737 int minvol = sound_min(SOUND_VOLUME);
738 if (limit == TOKEN_VALUE_ONLY)
740 *intval = global_settings.volume;
742 else if (global_settings.volume == minvol)
744 *intval = 1;
746 else if (global_settings.volume == 0)
748 *intval = limit - 1;
750 else if (global_settings.volume > 0)
752 *intval = limit;
754 else
756 *intval = (limit-3) * (global_settings.volume - minvol - 1)
757 / (-1 - minvol) + 2;
760 return buf;
761 #ifdef HAVE_ALBUMART
762 case SKIN_TOKEN_ALBUMART_FOUND:
763 if (data->albumart)
765 int handle = -1;
766 handle = playback_current_aa_hid(data->playback_aa_slot);
767 #if CONFIG_TUNER
768 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
770 struct dim dim = {data->albumart->width, data->albumart->height};
771 handle = radio_get_art_hid(&dim);
773 #endif
774 if (handle >= 0)
775 return "C";
777 return NULL;
778 #endif
780 case SKIN_TOKEN_BATTERY_PERCENT:
782 int l = battery_level();
784 if (intval)
786 if (limit == TOKEN_VALUE_ONLY)
788 *intval = l;
790 else
792 limit = MAX(limit, 3);
793 if (l > -1) {
794 /* First enum is used for "unknown level",
795 * last enum is used for 100%.
797 *intval = (limit - 2) * l / 100 + 2;
798 } else {
799 *intval = 1;
804 if (l > -1) {
805 snprintf(buf, buf_size, "%d", l);
806 return buf;
807 } else {
808 return "?";
812 case SKIN_TOKEN_BATTERY_VOLTS:
814 unsigned int v = battery_voltage();
815 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
816 return buf;
819 case SKIN_TOKEN_BATTERY_TIME:
821 int t = battery_time();
822 if (t >= 0)
823 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
824 else
825 return "?h ?m";
826 return buf;
829 #if CONFIG_CHARGING
830 case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED:
832 if(charger_input_state==CHARGER)
833 return "p";
834 else
835 return NULL;
837 #endif
838 #if CONFIG_CHARGING >= CHARGING_MONITOR
839 case SKIN_TOKEN_BATTERY_CHARGING:
841 if (charge_state == CHARGING || charge_state == TOPOFF) {
842 return "c";
843 } else {
844 return NULL;
847 #endif
848 #ifdef HAVE_USB_POWER
849 case SKIN_TOKEN_USB_POWERED:
850 if (usb_powered())
851 return "u";
852 return NULL;
853 #endif
854 case SKIN_TOKEN_BATTERY_SLEEPTIME:
856 if (get_sleep_timer() == 0)
857 return NULL;
858 else
860 format_time(buf, buf_size, get_sleep_timer() * 1000);
861 return buf;
865 case SKIN_TOKEN_PLAYBACK_STATUS:
867 int status = current_playmode();
868 /* music */
869 int mode = 1; /* stop */
870 if (status == STATUS_PLAY)
871 mode = 2; /* play */
872 if (state->is_fading ||
873 (status == STATUS_PAUSE && !status_get_ffmode()))
874 mode = 3; /* pause */
875 else
876 { /* ff / rwd */
877 if (status_get_ffmode() == STATUS_FASTFORWARD)
878 mode = 4;
879 if (status_get_ffmode() == STATUS_FASTBACKWARD)
880 mode = 5;
882 #ifdef HAVE_RECORDING
883 /* recording */
884 if (status == STATUS_RECORD)
885 mode = 6;
886 else if (status == STATUS_RECORD_PAUSE)
887 mode = 7;
888 #endif
889 #if CONFIG_TUNER
890 /* radio */
891 if (status == STATUS_RADIO)
892 mode = 8;
893 else if (status == STATUS_RADIO_PAUSE)
894 mode = 9;
895 #endif
897 if (intval) {
898 *intval = mode;
901 snprintf(buf, buf_size, "%d", mode-1);
902 return buf;
905 case SKIN_TOKEN_REPEAT_MODE:
906 if (intval)
907 *intval = global_settings.repeat_mode + 1;
908 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
909 return buf;
911 case SKIN_TOKEN_RTC_PRESENT:
912 #if CONFIG_RTC
913 return "c";
914 #else
915 return NULL;
916 #endif
918 #if CONFIG_RTC
919 case SKIN_TOKEN_RTC_12HOUR_CFG:
920 if (intval)
921 *intval = global_settings.timeformat + 1;
922 snprintf(buf, buf_size, "%d", global_settings.timeformat);
923 return buf;
925 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
926 /* d: day of month (01..31) */
927 snprintf(buf, buf_size, "%02d", tm->tm_mday);
928 if (intval)
929 *intval = tm->tm_mday - 1;
930 return buf;
932 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
933 /* e: day of month, blank padded ( 1..31) */
934 snprintf(buf, buf_size, "%2d", tm->tm_mday);
935 if (intval)
936 *intval = tm->tm_mday - 1;
937 return buf;
939 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
940 /* H: hour (00..23) */
941 snprintf(buf, buf_size, "%02d", tm->tm_hour);
942 if (intval)
943 *intval = tm->tm_hour;
944 return buf;
946 case SKIN_TOKEN_RTC_HOUR_24:
947 /* k: hour ( 0..23) */
948 snprintf(buf, buf_size, "%2d", tm->tm_hour);
949 if (intval)
950 *intval = tm->tm_hour;
951 return buf;
953 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
954 /* I: hour (01..12) */
955 snprintf(buf, buf_size, "%02d",
956 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
957 if (intval)
958 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
959 return buf;
961 case SKIN_TOKEN_RTC_HOUR_12:
962 /* l: hour ( 1..12) */
963 snprintf(buf, buf_size, "%2d",
964 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
965 if (intval)
966 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
967 return buf;
969 case SKIN_TOKEN_RTC_MONTH:
970 /* m: month (01..12) */
971 if (intval)
972 *intval = tm->tm_mon + 1;
973 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
974 return buf;
976 case SKIN_TOKEN_RTC_MINUTE:
977 /* M: minute (00..59) */
978 snprintf(buf, buf_size, "%02d", tm->tm_min);
979 if (intval)
980 *intval = tm->tm_min;
981 return buf;
983 case SKIN_TOKEN_RTC_SECOND:
984 /* S: second (00..59) */
985 snprintf(buf, buf_size, "%02d", tm->tm_sec);
986 if (intval)
987 *intval = tm->tm_sec;
988 return buf;
990 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
991 /* y: last two digits of year (00..99) */
992 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
993 if (intval)
994 *intval = tm->tm_year % 100;
995 return buf;
997 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
998 /* Y: year (1970...) */
999 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
1000 if (intval)
1001 *intval = tm->tm_year + 1900;
1002 return buf;
1004 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1005 /* p: upper case AM or PM indicator */
1006 if (intval)
1007 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1008 return tm->tm_hour/12 == 0 ? "AM" : "PM";
1010 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1011 /* P: lower case am or pm indicator */
1012 if (intval)
1013 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1014 return tm->tm_hour/12 == 0 ? "am" : "pm";
1016 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1017 /* a: abbreviated weekday name (Sun..Sat) */
1018 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
1020 case SKIN_TOKEN_RTC_MONTH_NAME:
1021 /* b: abbreviated month name (Jan..Dec) */
1022 return str(LANG_MONTH_JANUARY + tm->tm_mon);
1024 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1025 /* u: day of week (1..7); 1 is Monday */
1026 if (intval)
1027 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
1028 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
1029 return buf;
1031 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1032 /* w: day of week (0..6); 0 is Sunday */
1033 if (intval)
1034 *intval = tm->tm_wday + 1;
1035 snprintf(buf, buf_size, "%1d", tm->tm_wday);
1036 return buf;
1037 #else
1038 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1039 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1040 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1041 case SKIN_TOKEN_RTC_HOUR_24:
1042 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1043 case SKIN_TOKEN_RTC_HOUR_12:
1044 case SKIN_TOKEN_RTC_MONTH:
1045 case SKIN_TOKEN_RTC_MINUTE:
1046 case SKIN_TOKEN_RTC_SECOND:
1047 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1048 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1049 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1050 return "--";
1051 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1052 return "----";
1053 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1054 case SKIN_TOKEN_RTC_MONTH_NAME:
1055 return "---";
1056 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1057 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1058 return "-";
1059 #endif
1061 #ifdef HAVE_LCD_CHARCELLS
1062 case SKIN_TOKEN_PROGRESSBAR:
1064 char *end = utf8encode(data->wps_progress_pat[0], buf);
1065 *end = '\0';
1066 return buf;
1069 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1070 if(is_new_player())
1072 /* we need 11 characters (full line) for
1073 progress-bar */
1074 strlcpy(buf, " ", buf_size);
1076 else
1078 /* Tell the user if we have an OldPlayer */
1079 strlcpy(buf, " <Old LCD> ", buf_size);
1081 return buf;
1082 #endif
1086 #if (CONFIG_CODEC == SWCODEC)
1087 case SKIN_TOKEN_CROSSFADE:
1088 #ifdef HAVE_CROSSFADE
1089 if (intval)
1090 *intval = global_settings.crossfade + 1;
1091 snprintf(buf, buf_size, "%d", global_settings.crossfade);
1092 #else
1093 snprintf(buf, buf_size, "%d", 0);
1094 #endif
1095 return buf;
1097 case SKIN_TOKEN_REPLAYGAIN:
1099 int val;
1101 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
1102 val = 1; /* off */
1103 else
1105 int type;
1106 if (LIKELY(id3))
1107 type = get_replaygain_mode(id3->track_gain_string != NULL,
1108 id3->album_gain_string != NULL);
1109 else
1110 type = -1;
1112 if (type < 0)
1113 val = 6; /* no tag */
1114 else
1115 val = type + 2;
1117 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
1118 val += 2;
1121 if (intval)
1122 *intval = val;
1124 switch (val)
1126 case 1:
1127 case 6:
1128 return "+0.00 dB";
1129 break;
1130 /* due to above, coming here with !id3 shouldn't be possible */
1131 case 2:
1132 case 4:
1133 strlcpy(buf, id3->track_gain_string, buf_size);
1134 break;
1135 case 3:
1136 case 5:
1137 strlcpy(buf, id3->album_gain_string, buf_size);
1138 break;
1140 return buf;
1142 #endif /* (CONFIG_CODEC == SWCODEC) */
1144 #if (CONFIG_CODEC != MAS3507D)
1145 case SKIN_TOKEN_SOUND_PITCH:
1147 int32_t pitch = sound_get_pitch();
1148 snprintf(buf, buf_size, "%ld.%ld",
1149 pitch / PITCH_SPEED_PRECISION,
1150 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1152 if (intval)
1153 *intval = pitch_speed_enum(limit, pitch,
1154 PITCH_SPEED_PRECISION * 100);
1155 return buf;
1157 #endif
1159 #if CONFIG_CODEC == SWCODEC
1160 case SKIN_TOKEN_SOUND_SPEED:
1162 int32_t pitch = sound_get_pitch();
1163 int32_t speed;
1164 if (dsp_timestretch_available())
1165 speed = GET_SPEED(pitch, dsp_get_timestretch());
1166 else
1167 speed = pitch;
1168 snprintf(buf, buf_size, "%ld.%ld",
1169 speed / PITCH_SPEED_PRECISION,
1170 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1171 if (intval)
1172 *intval = pitch_speed_enum(limit, speed,
1173 PITCH_SPEED_PRECISION * 100);
1174 return buf;
1176 #endif
1178 case SKIN_TOKEN_MAIN_HOLD:
1179 #ifdef HAS_BUTTON_HOLD
1180 if (button_hold())
1181 #else
1182 if (is_keys_locked())
1183 #endif /*hold switch or softlock*/
1184 return "h";
1185 else
1186 return NULL;
1188 #ifdef HAS_REMOTE_BUTTON_HOLD
1189 case SKIN_TOKEN_REMOTE_HOLD:
1190 if (remote_button_hold())
1191 return "r";
1192 else
1193 return NULL;
1194 #endif
1196 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1197 case SKIN_TOKEN_VLED_HDD:
1198 if(led_read(HZ/2))
1199 return "h";
1200 else
1201 return NULL;
1202 #endif
1203 case SKIN_TOKEN_BUTTON_VOLUME:
1204 if (global_status.last_volume_change &&
1205 TIME_BEFORE(current_tick, global_status.last_volume_change +
1206 token->value.i))
1207 return "v";
1208 return NULL;
1210 case SKIN_TOKEN_LASTTOUCH:
1212 #ifdef HAVE_TOUCHSCREEN
1213 unsigned int last_touch = touchscreen_last_touch();
1214 if (last_touch != 0xffff &&
1215 TIME_BEFORE(current_tick, token->value.i + last_touch))
1216 return "t";
1217 #endif
1219 return NULL;
1221 case SKIN_TOKEN_SETTING:
1223 const struct settings_list *s = settings+token->value.i;
1224 if (intval)
1226 /* Handle contionals */
1227 switch (s->flags&F_T_MASK)
1229 case F_T_INT:
1230 case F_T_UINT:
1231 if (s->flags&F_T_SOUND)
1233 /* %?St|name|<min|min+1|...|max-1|max> */
1234 int sound_setting = s->sound_setting->setting;
1235 /* settings with decimals can't be used in conditionals */
1236 if (sound_numdecimals(sound_setting) == 0)
1238 *intval = (*(int*)s->setting-sound_min(sound_setting))
1239 /sound_steps(sound_setting) + 1;
1241 else
1242 *intval = -1;
1244 else if (s->flags&F_RGB)
1245 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1246 /* shouldn't overflow since colors are stored
1247 * on 16 bits ...
1248 * but this is pretty useless anyway */
1249 *intval = *(int*)s->setting + 1;
1250 else if (s->cfg_vals == NULL)
1251 /* %?St|name|<1st choice|2nd choice|...> */
1252 *intval = (*(int*)s->setting-s->int_setting->min)
1253 /s->int_setting->step + 1;
1254 else
1255 /* %?St|name|<1st choice|2nd choice|...> */
1256 /* Not sure about this one. cfg_name/vals are
1257 * indexed from 0 right? */
1258 *intval = *(int*)s->setting + 1;
1259 break;
1260 case F_T_BOOL:
1261 /* %?St|name|<if true|if false> */
1262 *intval = *(bool*)s->setting?1:2;
1263 break;
1264 case F_T_CHARPTR:
1265 case F_T_UCHARPTR:
1266 /* %?St|name|<if non empty string|if empty>
1267 * The string's emptyness discards the setting's
1268 * prefix and suffix */
1269 *intval = ((char*)s->setting)[0]?1:2;
1270 /* if there is a prefix we should ignore it here */
1271 if (s->filename_setting->prefix)
1272 return (char*)s->setting;
1273 break;
1274 default:
1275 /* This shouldn't happen ... but you never know */
1276 *intval = -1;
1277 break;
1280 /* Special handlng for filenames because we dont want to show the prefix */
1281 if ((s->flags&F_T_MASK) == F_T_UCHARPTR ||
1282 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1284 if (s->filename_setting->prefix)
1285 return (char*)s->setting;
1287 cfg_to_string(token->value.i,buf,buf_size);
1288 return buf;
1290 case SKIN_TOKEN_HAVE_TUNER:
1291 #if CONFIG_TUNER
1292 if (radio_hardware_present())
1293 return "r";
1294 #endif
1295 return NULL;
1296 /* Recording tokens */
1297 case SKIN_TOKEN_HAVE_RECORDING:
1298 #ifdef HAVE_RECORDING
1299 return "r";
1300 #else
1301 return NULL;
1302 #endif
1304 #ifdef HAVE_RECORDING
1305 case SKIN_TOKEN_IS_RECORDING:
1306 if (audio_status() == AUDIO_STATUS_RECORD)
1307 return "r";
1308 return NULL;
1309 case SKIN_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1311 #if CONFIG_CODEC == SWCODEC
1312 unsigned long samprk;
1313 int rec_freq = global_settings.rec_frequency;
1315 #ifdef SIMULATOR
1316 samprk = 44100;
1317 #else
1318 #if defined(HAVE_SPDIF_REC)
1319 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1321 /* Use rate in use, not current measured rate if it changed */
1322 samprk = pcm_rec_sample_rate();
1323 rec_freq = 0;
1324 while (rec_freq < SAMPR_NUM_FREQ &&
1325 audio_master_sampr_list[rec_freq] != samprk)
1327 rec_freq++;
1330 else
1331 #endif
1332 samprk = rec_freq_sampr[rec_freq];
1333 #endif /* SIMULATOR */
1334 if (intval)
1336 switch (rec_freq)
1338 REC_HAVE_96_(case REC_FREQ_96:
1339 *intval = 1;
1340 break;)
1341 REC_HAVE_88_(case REC_FREQ_88:
1342 *intval = 2;
1343 break;)
1344 REC_HAVE_64_(case REC_FREQ_64:
1345 *intval = 3;
1346 break;)
1347 REC_HAVE_48_(case REC_FREQ_48:
1348 *intval = 4;
1349 break;)
1350 REC_HAVE_44_(case REC_FREQ_44:
1351 *intval = 5;
1352 break;)
1353 REC_HAVE_32_(case REC_FREQ_32:
1354 *intval = 6;
1355 break;)
1356 REC_HAVE_24_(case REC_FREQ_24:
1357 *intval = 7;
1358 break;)
1359 REC_HAVE_22_(case REC_FREQ_22:
1360 *intval = 8;
1361 break;)
1362 REC_HAVE_16_(case REC_FREQ_16:
1363 *intval = 9;
1364 break;)
1365 REC_HAVE_12_(case REC_FREQ_12:
1366 *intval = 10;
1367 break;)
1368 REC_HAVE_11_(case REC_FREQ_11:
1369 *intval = 11;
1370 break;)
1371 REC_HAVE_8_(case REC_FREQ_8:
1372 *intval = 12;
1373 break;)
1376 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1377 #else /* HWCODEC */
1379 static const char * const freq_strings[] =
1380 {"--", "44", "48", "32", "22", "24", "16"};
1381 int freq = 1 + global_settings.rec_frequency;
1382 #ifdef HAVE_SPDIF_REC
1383 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1385 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1386 freq = 0;
1388 #endif /* HAVE_SPDIF_IN */
1389 if (intval)
1390 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1391 snprintf(buf, buf_size, "%s\n",
1392 freq_strings[global_settings.rec_frequency]);
1393 #endif
1394 return buf;
1396 #if CONFIG_CODEC == SWCODEC
1397 case SKIN_TOKEN_REC_ENCODER:
1399 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1400 if (intval)
1401 *intval = rec_format;
1402 switch (rec_format)
1404 case REC_FORMAT_PCM_WAV:
1405 return "wav";
1406 case REC_FORMAT_AIFF:
1407 return "aiff";
1408 case REC_FORMAT_WAVPACK:
1409 return "wv";
1410 case REC_FORMAT_MPA_L3:
1411 return "MP3";
1412 default:
1413 return NULL;
1415 break;
1417 #endif
1418 case SKIN_TOKEN_REC_BITRATE:
1419 #if CONFIG_CODEC == SWCODEC
1420 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1422 if (intval)
1424 #if 0 /* FIXME: I dont know if this is needed? */
1425 switch (1<<global_settings.mp3_enc_config.bitrate)
1427 case MP3_BITR_CAP_8:
1428 *intval = 1;
1429 break;
1430 case MP3_BITR_CAP_16:
1431 *intval = 2;
1432 break;
1433 case MP3_BITR_CAP_24:
1434 *intval = 3;
1435 break;
1436 case MP3_BITR_CAP_32:
1437 *intval = 4;
1438 break;
1439 case MP3_BITR_CAP_40:
1440 *intval = 5;
1441 break;
1442 case MP3_BITR_CAP_48:
1443 *intval = 6;
1444 break;
1445 case MP3_BITR_CAP_56:
1446 *intval = 7;
1447 break;
1448 case MP3_BITR_CAP_64:
1449 *intval = 8;
1450 break;
1451 case MP3_BITR_CAP_80:
1452 *intval = 9;
1453 break;
1454 case MP3_BITR_CAP_96:
1455 *intval = 10;
1456 break;
1457 case MP3_BITR_CAP_112:
1458 *intval = 11;
1459 break;
1460 case MP3_BITR_CAP_128:
1461 *intval = 12;
1462 break;
1463 case MP3_BITR_CAP_144:
1464 *intval = 13;
1465 break;
1466 case MP3_BITR_CAP_160:
1467 *intval = 14;
1468 break;
1469 case MP3_BITR_CAP_192:
1470 *intval = 15;
1471 break;
1473 #endif
1474 *intval = global_settings.mp3_enc_config.bitrate+1;
1476 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1477 return buf;
1479 else
1480 return NULL; /* Fixme later */
1481 #else /* CONFIG_CODEC == HWCODEC */
1482 if (intval)
1483 *intval = global_settings.rec_quality+1;
1484 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1485 return buf;
1486 #endif
1487 case SKIN_TOKEN_REC_MONO:
1488 if (!global_settings.rec_channels)
1489 return "m";
1490 return NULL;
1492 case SKIN_TOKEN_REC_SECONDS:
1494 int time = (audio_recorded_time() / HZ) % 60;
1495 if (intval)
1496 *intval = time;
1497 snprintf(buf, buf_size, "%02d", time);
1498 return buf;
1500 case SKIN_TOKEN_REC_MINUTES:
1502 int time = (audio_recorded_time() / HZ) / 60;
1503 if (intval)
1504 *intval = time;
1505 snprintf(buf, buf_size, "%02d", time);
1506 return buf;
1508 case SKIN_TOKEN_REC_HOURS:
1510 int time = (audio_recorded_time() / HZ) / 3600;
1511 if (intval)
1512 *intval = time;
1513 snprintf(buf, buf_size, "%02d", time);
1514 return buf;
1517 #endif /* HAVE_RECORDING */
1519 case SKIN_TOKEN_CURRENT_SCREEN:
1521 int curr_screen = current_screen();
1523 #ifdef HAVE_RECORDING
1524 /* override current_screen() for recording screen since it may
1525 * be entered from the radio screen */
1526 if (in_recording_screen())
1527 curr_screen = GO_TO_RECSCREEN;
1528 #endif
1530 switch (curr_screen)
1532 case GO_TO_WPS:
1533 curr_screen = 2;
1534 break;
1535 #ifdef HAVE_RECORDING
1536 case GO_TO_RECSCREEN:
1537 curr_screen = 3;
1538 break;
1539 #endif
1540 #if CONFIG_TUNER
1541 case GO_TO_FM:
1542 curr_screen = 4;
1543 break;
1544 #endif
1545 case GO_TO_PLAYLIST_VIEWER:
1546 curr_screen = 5;
1547 break;
1548 default: /* lists */
1549 curr_screen = 1;
1550 break;
1552 if (intval)
1554 *intval = curr_screen;
1556 snprintf(buf, buf_size, "%d", curr_screen);
1557 return buf;
1560 case SKIN_TOKEN_LANG_IS_RTL:
1561 return lang_is_rtl() ? "r" : NULL;
1563 default:
1564 return NULL;