Use buflib for all skin engine allocations.
[maemo-rb.git] / apps / gui / skin_engine / skin_tokens.c
blobbb9466c134c759efb9ed2c6ac8e9571aa357d78b
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 format_time(buf, buf_size, elapsed);
310 return buf;
312 case SKIN_TOKEN_TRACK_TIME_REMAINING:
313 format_time(buf, buf_size, length - elapsed);
314 return buf;
316 case SKIN_TOKEN_TRACK_LENGTH:
317 format_time(buf, buf_size, length);
318 return buf;
320 case SKIN_TOKEN_TRACK_ELAPSED_PERCENT:
321 if (length <= 0)
322 return NULL;
324 if (intval)
326 if (limit == TOKEN_VALUE_ONLY)
327 limit = 100; /* make it a percentage */
328 *intval = limit * elapsed / length + 1;
330 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
331 return buf;
333 case SKIN_TOKEN_TRACK_STARTING:
335 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
336 if (elapsed < time)
337 return "starting";
339 return NULL;
340 case SKIN_TOKEN_TRACK_ENDING:
342 unsigned long time = token->value.i * (HZ/TIMEOUT_UNIT);
343 if (length - elapsed < time)
344 return "ending";
346 return NULL;
348 case SKIN_TOKEN_FILE_CODEC:
349 if (intval)
351 if(id3->codectype == AFMT_UNKNOWN)
352 *intval = AFMT_NUM_CODECS;
353 else
354 *intval = id3->codectype;
356 return get_codectype(id3);
358 case SKIN_TOKEN_FILE_FREQUENCY:
359 snprintf(buf, buf_size, "%ld", id3->frequency);
360 return buf;
361 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
362 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
363 if ((id3->frequency % 1000) < 100)
364 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
365 else
366 snprintf(buf, buf_size, "%ld.%lu",
367 id3->frequency / 1000,
368 (id3->frequency % 1000) / 100);
369 return buf;
370 case SKIN_TOKEN_FILE_VBR:
371 return (id3->vbr) ? "(avg)" : NULL;
372 case SKIN_TOKEN_FILE_SIZE:
373 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
374 return buf;
376 #ifdef HAVE_TAGCACHE
377 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
378 if (intval)
379 *intval = id3->playcount + 1;
380 snprintf(buf, buf_size, "%ld", id3->playcount);
381 return buf;
382 case SKIN_TOKEN_DATABASE_RATING:
383 if (intval)
384 *intval = id3->rating + 1;
385 snprintf(buf, buf_size, "%d", id3->rating);
386 return buf;
387 case SKIN_TOKEN_DATABASE_AUTOSCORE:
388 if (intval)
389 *intval = id3->score + 1;
390 snprintf(buf, buf_size, "%d", id3->score);
391 return buf;
392 #endif
394 default:
395 return get_filename_token(token, id3->path, buf, buf_size);
398 else /* id3 == NULL, handle the error based on the expected return type */
400 switch (token->type)
402 /* Most tokens expect NULL on error so leave that for the default case,
403 * The ones that expect "0" need to be handled */
404 case SKIN_TOKEN_FILE_FREQUENCY:
405 case SKIN_TOKEN_FILE_FREQUENCY_KHZ:
406 case SKIN_TOKEN_FILE_SIZE:
407 #ifdef HAVE_TAGCACHE
408 case SKIN_TOKEN_DATABASE_PLAYCOUNT:
409 case SKIN_TOKEN_DATABASE_RATING:
410 case SKIN_TOKEN_DATABASE_AUTOSCORE:
411 #endif
412 if (intval)
413 *intval = 0;
414 return "0";
415 default:
416 return get_filename_token(token, filename, buf, buf_size);
419 return buf;
422 #if CONFIG_TUNER
424 /* Formats the frequency (specified in Hz) in MHz, */
425 /* with one or two digits after the decimal point -- */
426 /* depending on the frequency changing step. */
427 /* Returns buf */
428 static char *format_freq_MHz(int freq, int freq_step, char *buf, int buf_size)
430 int scale, div;
431 char *fmt;
432 if (freq_step < 100000)
434 /* Format with two digits after decimal point */
435 scale = 10000;
436 fmt = "%d.%02d";
438 else
440 /* Format with one digit after decimal point */
441 scale = 100000;
442 fmt = "%d.%d";
444 div = 1000000 / scale;
445 freq = freq / scale;
446 snprintf(buf, buf_size, fmt, freq/div, freq%div);
447 return buf;
451 /* Tokens which are really only used by the radio screen go in here */
452 const char *get_radio_token(struct wps_token *token, int preset_offset,
453 char *buf, int buf_size, int limit, int *intval)
455 const struct fm_region_data *region_data =
456 &(fm_region_data[global_settings.fm_region]);
457 (void)limit;
458 switch (token->type)
460 /* Radio/tuner tokens */
461 case SKIN_TOKEN_TUNER_TUNED:
462 if (tuner_get(RADIO_TUNED))
463 return "t";
464 return NULL;
465 case SKIN_TOKEN_TUNER_SCANMODE:
466 if (radio_scan_mode())
467 return "s";
468 return NULL;
469 case SKIN_TOKEN_TUNER_STEREO:
470 if (radio_is_stereo())
471 return "s";
472 return NULL;
473 case SKIN_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
474 return format_freq_MHz(region_data->freq_min,
475 region_data->freq_step, buf, buf_size);
476 case SKIN_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
477 return format_freq_MHz(region_data->freq_max,
478 region_data->freq_step, buf, buf_size);
479 case SKIN_TOKEN_TUNER_CURFREQ:
480 return format_freq_MHz(radio_current_frequency(),
481 region_data->freq_step, buf, buf_size);
482 #ifdef HAVE_RADIO_RSSI
483 case SKIN_TOKEN_TUNER_RSSI:
484 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI));
485 if (intval)
487 int val = tuner_get(RADIO_RSSI);
488 int min = tuner_get(RADIO_RSSI_MIN);
489 int max = tuner_get(RADIO_RSSI_MAX);
490 if (limit == TOKEN_VALUE_ONLY)
492 *intval = val;
494 else
496 *intval = 1+(limit-1)*(val-min)/(max-1-min);
499 return buf;
500 case SKIN_TOKEN_TUNER_RSSI_MIN:
501 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MIN));
502 return buf;
503 case SKIN_TOKEN_TUNER_RSSI_MAX:
504 snprintf(buf, buf_size, "%d",tuner_get(RADIO_RSSI_MAX));
505 return buf;
506 #endif
507 case SKIN_TOKEN_PRESET_NAME:
508 case SKIN_TOKEN_PRESET_FREQ:
509 case SKIN_TOKEN_PRESET_ID:
511 int preset_count = radio_preset_count();
512 int cur_preset = radio_current_preset();
513 if (preset_count == 0 || cur_preset < 0)
514 return NULL;
515 int preset = cur_preset + preset_offset;
516 /* make sure it's in the valid range */
517 preset %= preset_count;
518 if (preset < 0)
519 preset += preset_count;
520 if (token->type == SKIN_TOKEN_PRESET_NAME)
521 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
522 else if (token->type == SKIN_TOKEN_PRESET_FREQ)
523 format_freq_MHz(radio_get_preset(preset)->frequency,
524 region_data->freq_step, buf, buf_size);
525 else
526 snprintf(buf, buf_size, "%d", preset + 1);
527 return buf;
529 case SKIN_TOKEN_PRESET_COUNT:
530 snprintf(buf, buf_size, "%d", radio_preset_count());
531 if (intval)
532 *intval = radio_preset_count();
533 return buf;
534 case SKIN_TOKEN_HAVE_RDS:
535 #ifdef HAVE_RDS_CAP
536 return "rds";
537 case SKIN_TOKEN_RDS_NAME:
538 return tuner_get_rds_info(RADIO_RDS_NAME);
539 case SKIN_TOKEN_RDS_TEXT:
540 return tuner_get_rds_info(RADIO_RDS_TEXT);
541 #else
542 return NULL; /* end of the SKIN_TOKEN_HAVE_RDS case */
543 #endif /* HAVE_RDS_CAP */
544 default:
545 return NULL;
547 return NULL;
549 #endif
551 static struct mp3entry* get_mp3entry_from_offset(int offset, char **filename)
553 struct mp3entry* pid3 = NULL;
554 struct wps_state *state = skin_get_global_state();
555 struct cuesheet *cue = state->id3 ? state->id3->cuesheet : NULL;
556 const char *fname = NULL;
557 if (cue && cue->curr_track_idx + offset < cue->track_count)
558 pid3 = state->id3;
559 else if (offset == 0)
560 pid3 = state->id3;
561 else if (offset == 1)
562 pid3 = state->nid3;
563 else
565 static char filename_buf[MAX_PATH + 1];
566 fname = playlist_peek(offset, filename_buf, sizeof(filename_buf));
567 *filename = (char*)fname;
568 #if CONFIG_CODEC == SWCODEC
569 static struct mp3entry tempid3;
570 if (
571 #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
572 tagcache_fill_tags(&tempid3, fname) ||
573 #endif
574 audio_peek_track(&tempid3, offset)
577 pid3 = &tempid3;
579 #endif
581 return pid3;
584 #ifdef HAVE_LCD_CHARCELLS
585 static void format_player_progress(struct gui_wps *gwps)
587 struct wps_state *state = skin_get_global_state();
588 struct screen *display = gwps->display;
589 unsigned char progress_pattern[7];
590 int pos = 0;
591 int i;
593 int elapsed, length;
594 if (LIKELY(state->id3))
596 elapsed = state->id3->elapsed;
597 length = state->id3->length;
599 else
601 elapsed = 0;
602 length = 0;
605 if (length)
606 pos = 36 * (elapsed + state->ff_rewind_count) / length;
608 for (i = 0; i < 7; i++, pos -= 5)
610 if (pos <= 0)
611 progress_pattern[i] = 0x1fu;
612 else if (pos >= 5)
613 progress_pattern[i] = 0x00u;
614 else
615 progress_pattern[i] = 0x1fu >> pos;
618 display->define_pattern(gwps->data->wps_progress_pat[0], progress_pattern);
621 static void format_player_fullbar(struct gui_wps *gwps, char* buf, int buf_size)
623 static const unsigned char numbers[10][4] = {
624 {0x0e, 0x0a, 0x0a, 0x0e}, /* 0 */
625 {0x04, 0x0c, 0x04, 0x04}, /* 1 */
626 {0x0e, 0x02, 0x04, 0x0e}, /* 2 */
627 {0x0e, 0x02, 0x06, 0x0e}, /* 3 */
628 {0x08, 0x0c, 0x0e, 0x04}, /* 4 */
629 {0x0e, 0x0c, 0x02, 0x0c}, /* 5 */
630 {0x0e, 0x08, 0x0e, 0x0e}, /* 6 */
631 {0x0e, 0x02, 0x04, 0x08}, /* 7 */
632 {0x0e, 0x0e, 0x0a, 0x0e}, /* 8 */
633 {0x0e, 0x0e, 0x02, 0x0e} /* 9 */
636 struct wps_state *state = skin_get_global_state();
637 struct screen *display = gwps->display;
638 struct wps_data *data = gwps->data;
639 unsigned char progress_pattern[7];
640 char timestr[10];
641 int time;
642 int time_idx = 0;
643 int pos = 0;
644 int pat_idx = 1;
645 int digit, i, j;
646 bool softchar;
648 int elapsed, length;
649 if (LIKELY(state->id3))
651 elapsed = state->id3->elapsed;
652 length = state->id3->length;
654 else
656 elapsed = 0;
657 length = 0;
660 if (buf_size < 34) /* worst case: 11x UTF-8 char + \0 */
661 return;
663 time = elapsed + state->ff_rewind_count;
664 if (length)
665 pos = 55 * time / length;
667 memset(timestr, 0, sizeof(timestr));
668 format_time(timestr, sizeof(timestr)-2, time);
669 timestr[strlen(timestr)] = ':'; /* always safe */
671 for (i = 0; i < 11; i++, pos -= 5)
673 softchar = false;
674 memset(progress_pattern, 0, sizeof(progress_pattern));
676 if ((digit = timestr[time_idx]))
678 softchar = true;
679 digit -= '0';
681 if (timestr[time_idx + 1] == ':') /* ones, left aligned */
683 memcpy(progress_pattern, numbers[digit], 4);
684 time_idx += 2;
686 else /* tens, shifted right */
688 for (j = 0; j < 4; j++)
689 progress_pattern[j] = numbers[digit][j] >> 1;
691 if (time_idx > 0) /* not the first group, add colon in front */
693 progress_pattern[1] |= 0x10u;
694 progress_pattern[3] |= 0x10u;
696 time_idx++;
699 if (pos >= 5)
700 progress_pattern[5] = progress_pattern[6] = 0x1fu;
703 if (pos > 0 && pos < 5)
705 softchar = true;
706 progress_pattern[5] = progress_pattern[6] = (~0x1fu >> pos) & 0x1fu;
709 if (softchar && pat_idx < 8)
711 display->define_pattern(data->wps_progress_pat[pat_idx],
712 progress_pattern);
713 buf = utf8encode(data->wps_progress_pat[pat_idx], buf);
714 pat_idx++;
716 else if (pos <= 0)
717 buf = utf8encode(' ', buf);
718 else
719 buf = utf8encode(0xe115, buf); /* 2/7 _ */
721 *buf = '\0';
724 #endif /* HAVE_LCD_CHARCELLS */
726 /* Don't inline this; it was broken out of get_token_value to reduce stack
727 * usage.
729 static const char* NOINLINE get_lif_token_value(struct gui_wps *gwps,
730 struct logical_if *lif,
731 int offset, char *buf,
732 int buf_size)
734 int a = lif->num_options;
735 int b;
736 struct wps_token *liftoken = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->token);
737 const char* out_text = get_token_value(gwps, liftoken, offset, buf, buf_size, &a);
738 if (a == -1 && liftoken->type != SKIN_TOKEN_VOLUME)
739 a = (out_text && *out_text) ? 1 : 0;
740 switch (lif->operand.type)
742 case STRING:
744 char *cmp = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->operand.data.text);
745 if (out_text == NULL)
746 return NULL;
747 a = strcmp(out_text, cmp);
748 b = 0;
749 break;
751 case INTEGER:
752 case DECIMAL:
753 b = lif->operand.data.number;
754 break;
755 case CODE:
757 char temp_buf[MAX_PATH];
758 const char *outb;
759 struct skin_element *element = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), lif->operand.data.code);
760 struct wps_token *token = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), element->data);
761 b = lif->num_options;
762 outb = get_token_value(gwps, token, offset, temp_buf,
763 sizeof(temp_buf), &b);
764 if (b == -1 && liftoken->type != SKIN_TOKEN_VOLUME)
766 if (!out_text || !outb)
767 return (lif->op == IF_EQUALS) ? NULL : "neq";
768 bool equal = strcmp(out_text, outb) == 0;
769 if (lif->op == IF_EQUALS)
770 return equal ? "eq" : NULL;
771 else if (lif->op == IF_NOTEQUALS)
772 return !equal ? "neq" : NULL;
773 else
774 b = (outb && *outb) ? 1 : 0;
777 break;
778 case DEFAULT:
779 break;
782 switch (lif->op)
784 case IF_EQUALS:
785 return a == b ? "eq" : NULL;
786 case IF_NOTEQUALS:
787 return a != b ? "neq" : NULL;
788 case IF_LESSTHAN:
789 return a < b ? "lt" : NULL;
790 case IF_LESSTHAN_EQ:
791 return a <= b ? "lte" : NULL;
792 case IF_GREATERTHAN:
793 return a > b ? "gt" : NULL;
794 case IF_GREATERTHAN_EQ:
795 return a >= b ? "gte" : NULL;
797 return NULL;
800 /* Return the tags value as text. buf should be used as temp storage if needed.
802 intval is used with conditionals/enums: when this function is called,
803 intval should contain the number of options in the conditional/enum.
804 When this function returns, intval is -1 if the tag is non numeric or,
805 if the tag is numeric, *intval is the enum case we want to go to (between 1
806 and the original value of *intval, inclusive).
807 When not treating a conditional/enum, intval should be NULL.
809 const char *get_token_value(struct gui_wps *gwps,
810 struct wps_token *token, int offset,
811 char *buf, int buf_size,
812 int *intval)
814 if (!gwps)
815 return NULL;
817 struct wps_data *data = gwps->data;
818 struct wps_state *state = skin_get_global_state();
819 struct mp3entry *id3; /* Think very carefully about using this.
820 maybe get_id3_token() is the better place? */
821 const char *out_text = NULL;
822 char *filename = NULL;
824 if (!data || !state)
825 return NULL;
827 id3 = get_mp3entry_from_offset(token->next? 1: offset, &filename);
828 if (id3)
829 filename = id3->path;
831 #if CONFIG_RTC
832 struct tm* tm = NULL;
834 /* if the token is an RTC one, update the time
835 and do the necessary checks */
836 if (token->type >= SKIN_TOKENS_RTC_BEGIN
837 && token->type <= SKIN_TOKENS_RTC_END)
839 tm = get_time();
841 if (!valid_time(tm))
842 return NULL;
844 #endif
846 int limit = 1;
847 if (intval)
849 limit = *intval;
850 *intval = -1;
853 if (id3 && id3 == state->id3 && id3->cuesheet )
855 out_text = get_cuesheetid3_token(token, id3,
856 token->next?1:offset, buf, buf_size);
857 if (out_text)
858 return out_text;
860 out_text = get_id3_token(token, id3, filename, buf, buf_size, limit, intval);
861 if (out_text)
862 return out_text;
863 #if CONFIG_TUNER
864 out_text = get_radio_token(token, offset, buf, buf_size, limit, intval);
865 if (out_text)
866 return out_text;
867 #endif
869 switch (token->type)
871 case SKIN_TOKEN_LOGICAL_IF:
873 struct logical_if *lif = SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
874 return get_lif_token_value(gwps, lif, offset, buf, buf_size);
876 break;
877 case SKIN_TOKEN_SUBSTRING:
879 struct substring *ss = SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
880 const char *token_val = get_token_value(gwps,
881 SKINOFFSETTOPTR(get_skin_buffer(data), ss->token), offset,
882 buf, buf_size, intval);
883 if (token_val)
885 int start_byte, end_byte, byte_len;
886 int utf8_len = utf8length(token_val);
888 if (utf8_len < ss->start)
889 return NULL;
891 start_byte = utf8seek(token_val, ss->start);
893 if (ss->length < 0 || (ss->start + ss->length) > utf8_len)
894 end_byte = strlen(token_val);
895 else
896 end_byte = utf8seek(token_val, ss->start + ss->length);
898 byte_len = end_byte - start_byte;
900 if (token_val != buf)
901 memcpy(buf, &token_val[start_byte], byte_len);
902 else
903 buf = &buf[start_byte];
905 buf[byte_len] = '\0';
906 return buf;
908 return NULL;
910 break;
912 case SKIN_TOKEN_CHARACTER:
913 if (token->value.c == '\n')
914 return NULL;
915 return &(token->value.c);
917 case SKIN_TOKEN_STRING:
918 return (char*)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
920 case SKIN_TOKEN_TRANSLATEDSTRING:
921 return (char*)P2STR(ID2P(token->value.i));
923 case SKIN_TOKEN_PLAYLIST_ENTRIES:
924 snprintf(buf, buf_size, "%d", playlist_amount());
925 if (intval)
926 *intval = playlist_amount();
927 return buf;
928 #ifdef HAVE_LCD_BITMAP
929 case SKIN_TOKEN_LIST_TITLE_TEXT:
930 return sb_get_title(gwps->display->screen_type);
931 case SKIN_TOKEN_LIST_TITLE_ICON:
932 if (intval)
933 *intval = sb_get_icon(gwps->display->screen_type);
934 snprintf(buf, buf_size, "%d",sb_get_icon(gwps->display->screen_type));
935 return buf;
936 case SKIN_TOKEN_LIST_ITEM_TEXT:
938 struct listitem *li = (struct listitem *)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
939 return skinlist_get_item_text(li->offset, li->wrap, buf, buf_size);
941 case SKIN_TOKEN_LIST_ITEM_NUMBER:
942 if (intval)
943 *intval = skinlist_get_item_number() + 1;
944 snprintf(buf, buf_size, "%d",skinlist_get_item_number() + 1);
945 return buf;
946 case SKIN_TOKEN_LIST_ITEM_IS_SELECTED:
947 return skinlist_is_selected_item()?"s":"";
948 case SKIN_TOKEN_LIST_ITEM_ICON:
950 struct listitem *li = (struct listitem *)SKINOFFSETTOPTR(get_skin_buffer(data), token->value.data);
951 int icon = skinlist_get_item_icon(li->offset, li->wrap);
952 if (intval)
953 *intval = icon;
954 snprintf(buf, buf_size, "%d", icon);
955 return buf;
957 case SKIN_TOKEN_LIST_NEEDS_SCROLLBAR:
958 return skinlist_needs_scrollbar(gwps->display->screen_type) ? "s" : "";
959 #endif
960 case SKIN_TOKEN_PLAYLIST_NAME:
961 return playlist_name(NULL, buf, buf_size);
963 case SKIN_TOKEN_PLAYLIST_POSITION:
964 snprintf(buf, buf_size, "%d", playlist_get_display_index()+offset);
965 if (intval)
966 *intval = playlist_get_display_index()+offset;
967 return buf;
969 case SKIN_TOKEN_PLAYLIST_SHUFFLE:
970 if ( global_settings.playlist_shuffle )
971 return "s";
972 else
973 return NULL;
974 break;
976 case SKIN_TOKEN_VOLUME:
977 snprintf(buf, buf_size, "%d", global_settings.volume);
978 if (intval)
980 int minvol = sound_min(SOUND_VOLUME);
981 if (limit == TOKEN_VALUE_ONLY)
983 *intval = global_settings.volume;
985 else if (global_settings.volume == minvol)
987 *intval = 1;
989 else if (global_settings.volume == 0)
991 *intval = limit - 1;
993 else if (global_settings.volume > 0)
995 *intval = limit;
997 else
999 *intval = (limit-3) * (global_settings.volume - minvol - 1)
1000 / (-1 - minvol) + 2;
1003 return buf;
1004 #ifdef HAVE_ALBUMART
1005 case SKIN_TOKEN_ALBUMART_FOUND:
1006 if (SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart))
1008 int handle = -1;
1009 handle = playback_current_aa_hid(data->playback_aa_slot);
1010 #if CONFIG_TUNER
1011 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
1013 struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart);
1014 struct dim dim = {aa->width, aa->height};
1015 handle = radio_get_art_hid(&dim);
1017 #endif
1018 if (handle >= 0)
1019 return "C";
1021 return NULL;
1022 #endif
1024 case SKIN_TOKEN_BATTERY_PERCENT:
1026 int l = battery_level();
1028 if (intval)
1030 if (limit == TOKEN_VALUE_ONLY)
1032 *intval = l;
1034 else
1036 limit = MAX(limit, 3);
1037 if (l > -1) {
1038 /* First enum is used for "unknown level",
1039 * last enum is used for 100%.
1041 *intval = (limit - 2) * l / 100 + 2;
1042 } else {
1043 *intval = 1;
1048 if (l > -1) {
1049 snprintf(buf, buf_size, "%d", l);
1050 return buf;
1051 } else {
1052 return "?";
1056 case SKIN_TOKEN_BATTERY_VOLTS:
1058 unsigned int v = battery_voltage();
1059 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
1060 return buf;
1063 case SKIN_TOKEN_BATTERY_TIME:
1065 int t = battery_time();
1066 if (t >= 0)
1067 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
1068 else
1069 return "?h ?m";
1070 return buf;
1073 #if CONFIG_CHARGING
1074 case SKIN_TOKEN_BATTERY_CHARGER_CONNECTED:
1076 if(charger_input_state==CHARGER)
1077 return "p";
1078 else
1079 return NULL;
1081 #endif
1082 #if CONFIG_CHARGING >= CHARGING_MONITOR
1083 case SKIN_TOKEN_BATTERY_CHARGING:
1085 if (charge_state == CHARGING || charge_state == TOPOFF) {
1086 return "c";
1087 } else {
1088 return NULL;
1091 #endif
1092 #ifdef HAVE_USB_POWER
1093 case SKIN_TOKEN_USB_POWERED:
1094 if (usb_powered())
1095 return "u";
1096 return NULL;
1097 #endif
1098 case SKIN_TOKEN_BATTERY_SLEEPTIME:
1100 if (get_sleep_timer() == 0)
1101 return NULL;
1102 else
1104 format_time(buf, buf_size, get_sleep_timer() * 1000);
1105 return buf;
1109 case SKIN_TOKEN_PLAYBACK_STATUS:
1111 int status = current_playmode();
1112 /* music */
1113 int mode = 1; /* stop */
1114 if (status == STATUS_PLAY)
1115 mode = 2; /* play */
1116 if (state->is_fading ||
1117 (status == STATUS_PAUSE && !status_get_ffmode()))
1118 mode = 3; /* pause */
1119 else
1120 { /* ff / rwd */
1121 if (status_get_ffmode() == STATUS_FASTFORWARD)
1122 mode = 4;
1123 if (status_get_ffmode() == STATUS_FASTBACKWARD)
1124 mode = 5;
1126 #ifdef HAVE_RECORDING
1127 /* recording */
1128 if (status == STATUS_RECORD)
1129 mode = 6;
1130 else if (status == STATUS_RECORD_PAUSE)
1131 mode = 7;
1132 #endif
1133 #if CONFIG_TUNER
1134 /* radio */
1135 if (status == STATUS_RADIO)
1136 mode = 8;
1137 else if (status == STATUS_RADIO_PAUSE)
1138 mode = 9;
1139 #endif
1141 if (intval) {
1142 *intval = mode;
1145 snprintf(buf, buf_size, "%d", mode-1);
1146 return buf;
1149 case SKIN_TOKEN_REPEAT_MODE:
1150 if (intval)
1151 *intval = global_settings.repeat_mode + 1;
1152 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
1153 return buf;
1155 case SKIN_TOKEN_RTC_PRESENT:
1156 #if CONFIG_RTC
1157 return "c";
1158 #else
1159 return NULL;
1160 #endif
1162 #if CONFIG_RTC
1163 case SKIN_TOKEN_RTC_12HOUR_CFG:
1164 if (intval)
1165 *intval = global_settings.timeformat + 1;
1166 snprintf(buf, buf_size, "%d", global_settings.timeformat);
1167 return buf;
1169 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1170 /* d: day of month (01..31) */
1171 snprintf(buf, buf_size, "%02d", tm->tm_mday);
1172 if (intval)
1173 *intval = tm->tm_mday - 1;
1174 return buf;
1176 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1177 /* e: day of month, blank padded ( 1..31) */
1178 snprintf(buf, buf_size, "%2d", tm->tm_mday);
1179 if (intval)
1180 *intval = tm->tm_mday - 1;
1181 return buf;
1183 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1184 /* H: hour (00..23) */
1185 snprintf(buf, buf_size, "%02d", tm->tm_hour);
1186 if (intval)
1187 *intval = tm->tm_hour;
1188 return buf;
1190 case SKIN_TOKEN_RTC_HOUR_24:
1191 /* k: hour ( 0..23) */
1192 snprintf(buf, buf_size, "%2d", tm->tm_hour);
1193 if (intval)
1194 *intval = tm->tm_hour;
1195 return buf;
1197 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1198 /* I: hour (01..12) */
1199 snprintf(buf, buf_size, "%02d",
1200 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1201 if (intval)
1202 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1203 return buf;
1205 case SKIN_TOKEN_RTC_HOUR_12:
1206 /* l: hour ( 1..12) */
1207 snprintf(buf, buf_size, "%2d",
1208 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
1209 if (intval)
1210 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
1211 return buf;
1213 case SKIN_TOKEN_RTC_MONTH:
1214 /* m: month (01..12) */
1215 if (intval)
1216 *intval = tm->tm_mon + 1;
1217 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
1218 return buf;
1220 case SKIN_TOKEN_RTC_MINUTE:
1221 /* M: minute (00..59) */
1222 snprintf(buf, buf_size, "%02d", tm->tm_min);
1223 if (intval)
1224 *intval = tm->tm_min;
1225 return buf;
1227 case SKIN_TOKEN_RTC_SECOND:
1228 /* S: second (00..59) */
1229 snprintf(buf, buf_size, "%02d", tm->tm_sec);
1230 if (intval)
1231 *intval = tm->tm_sec;
1232 return buf;
1234 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1235 /* y: last two digits of year (00..99) */
1236 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
1237 if (intval)
1238 *intval = tm->tm_year % 100;
1239 return buf;
1241 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1242 /* Y: year (1970...) */
1243 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
1244 if (intval)
1245 *intval = tm->tm_year + 1900;
1246 return buf;
1248 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1249 /* p: upper case AM or PM indicator */
1250 if (intval)
1251 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1252 return tm->tm_hour/12 == 0 ? "AM" : "PM";
1254 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1255 /* P: lower case am or pm indicator */
1256 if (intval)
1257 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
1258 return tm->tm_hour/12 == 0 ? "am" : "pm";
1260 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1261 /* a: abbreviated weekday name (Sun..Sat) */
1262 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
1264 case SKIN_TOKEN_RTC_MONTH_NAME:
1265 /* b: abbreviated month name (Jan..Dec) */
1266 return str(LANG_MONTH_JANUARY + tm->tm_mon);
1268 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1269 /* u: day of week (1..7); 1 is Monday */
1270 if (intval)
1271 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
1272 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
1273 return buf;
1275 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1276 /* w: day of week (0..6); 0 is Sunday */
1277 if (intval)
1278 *intval = tm->tm_wday + 1;
1279 snprintf(buf, buf_size, "%1d", tm->tm_wday);
1280 return buf;
1281 #else
1282 case SKIN_TOKEN_RTC_DAY_OF_MONTH:
1283 case SKIN_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
1284 case SKIN_TOKEN_RTC_HOUR_24_ZERO_PADDED:
1285 case SKIN_TOKEN_RTC_HOUR_24:
1286 case SKIN_TOKEN_RTC_HOUR_12_ZERO_PADDED:
1287 case SKIN_TOKEN_RTC_HOUR_12:
1288 case SKIN_TOKEN_RTC_MONTH:
1289 case SKIN_TOKEN_RTC_MINUTE:
1290 case SKIN_TOKEN_RTC_SECOND:
1291 case SKIN_TOKEN_RTC_AM_PM_UPPER:
1292 case SKIN_TOKEN_RTC_AM_PM_LOWER:
1293 case SKIN_TOKEN_RTC_YEAR_2_DIGITS:
1294 return "--";
1295 case SKIN_TOKEN_RTC_YEAR_4_DIGITS:
1296 return "----";
1297 case SKIN_TOKEN_RTC_WEEKDAY_NAME:
1298 case SKIN_TOKEN_RTC_MONTH_NAME:
1299 return "---";
1300 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_MON:
1301 case SKIN_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
1302 return "-";
1303 #endif
1305 #ifdef HAVE_LCD_CHARCELLS
1306 case SKIN_TOKEN_PROGRESSBAR:
1308 char *end;
1309 format_player_progress(gwps);
1310 end = utf8encode(data->wps_progress_pat[0], buf);
1311 *end = '\0';
1312 return buf;
1315 case SKIN_TOKEN_PLAYER_PROGRESSBAR:
1316 if(is_new_player())
1318 /* we need 11 characters (full line) for
1319 progress-bar */
1320 strlcpy(buf, " ", buf_size);
1321 format_player_fullbar(gwps,buf,buf_size);
1322 DEBUGF("bar='%s'\n",buf);
1324 else
1326 /* Tell the user if we have an OldPlayer */
1327 strlcpy(buf, " <Old LCD> ", buf_size);
1329 return buf;
1330 #endif
1333 #ifdef HAVE_LCD_BITMAP
1334 /* peakmeter */
1335 case SKIN_TOKEN_PEAKMETER_LEFT:
1336 case SKIN_TOKEN_PEAKMETER_RIGHT:
1338 int left, right, val;
1339 peak_meter_current_vals(&left, &right);
1340 val = token->type == SKIN_TOKEN_PEAKMETER_LEFT ?
1341 left : right;
1342 val = peak_meter_scale_value(val, limit==1 ? MAX_PEAK : limit);
1343 if (intval)
1344 *intval = val;
1345 snprintf(buf, buf_size, "%d", val);
1346 data->peak_meter_enabled = true;
1347 return buf;
1349 #endif
1351 #if (CONFIG_CODEC == SWCODEC)
1352 case SKIN_TOKEN_CROSSFADE:
1353 #ifdef HAVE_CROSSFADE
1354 if (intval)
1355 *intval = global_settings.crossfade + 1;
1356 snprintf(buf, buf_size, "%d", global_settings.crossfade);
1357 #else
1358 snprintf(buf, buf_size, "%d", 0);
1359 #endif
1360 return buf;
1362 case SKIN_TOKEN_REPLAYGAIN:
1364 int val;
1366 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
1367 val = 1; /* off */
1368 else
1370 int type;
1371 if (LIKELY(id3))
1372 type = get_replaygain_mode(id3->track_gain != 0,
1373 id3->album_gain != 0);
1374 else
1375 type = -1;
1377 if (type < 0)
1378 val = 6; /* no tag */
1379 else
1380 val = type + 2;
1382 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
1383 val += 2;
1386 if (intval)
1387 *intval = val;
1389 switch (val)
1391 case 1:
1392 case 6:
1393 return "+0.00 dB";
1394 break;
1395 /* due to above, coming here with !id3 shouldn't be possible */
1396 case 2:
1397 case 4:
1398 replaygain_itoa(buf, buf_size, id3->track_level);
1399 break;
1400 case 3:
1401 case 5:
1402 replaygain_itoa(buf, buf_size, id3->album_level);
1403 break;
1405 return buf;
1407 #endif /* (CONFIG_CODEC == SWCODEC) */
1409 #if (CONFIG_CODEC != MAS3507D) && defined (HAVE_PITCHSCREEN)
1410 case SKIN_TOKEN_SOUND_PITCH:
1412 int32_t pitch = sound_get_pitch();
1413 snprintf(buf, buf_size, "%ld.%ld",
1414 pitch / PITCH_SPEED_PRECISION,
1415 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1417 if (intval)
1418 *intval = pitch_speed_enum(limit, pitch,
1419 PITCH_SPEED_PRECISION * 100);
1420 return buf;
1422 #endif
1424 #if (CONFIG_CODEC == SWCODEC) && defined (HAVE_PITCHSCREEN)
1425 case SKIN_TOKEN_SOUND_SPEED:
1427 int32_t pitch = sound_get_pitch();
1428 int32_t speed;
1429 if (dsp_timestretch_available())
1430 speed = GET_SPEED(pitch, dsp_get_timestretch());
1431 else
1432 speed = pitch;
1433 snprintf(buf, buf_size, "%ld.%ld",
1434 speed / PITCH_SPEED_PRECISION,
1435 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1436 if (intval)
1437 *intval = pitch_speed_enum(limit, speed,
1438 PITCH_SPEED_PRECISION * 100);
1439 return buf;
1441 #endif
1443 case SKIN_TOKEN_MAIN_HOLD:
1444 #ifdef HAVE_TOUCHSCREEN
1445 if (data->touchscreen_locked)
1446 return "t";
1447 #endif
1448 #ifdef HAS_BUTTON_HOLD
1449 if (button_hold())
1450 #else
1451 if (is_keys_locked())
1452 #endif /*hold switch or softlock*/
1453 return "h";
1454 else
1455 return NULL;
1457 #ifdef HAS_REMOTE_BUTTON_HOLD
1458 case SKIN_TOKEN_REMOTE_HOLD:
1459 if (remote_button_hold())
1460 return "r";
1461 else
1462 return NULL;
1463 #endif
1465 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1466 case SKIN_TOKEN_VLED_HDD:
1467 if(led_read(HZ/2))
1468 return "h";
1469 else
1470 return NULL;
1471 #endif
1472 case SKIN_TOKEN_BUTTON_VOLUME:
1473 if (global_status.last_volume_change &&
1474 TIME_BEFORE(current_tick, global_status.last_volume_change +
1475 token->value.i))
1476 return "v";
1477 return NULL;
1479 case SKIN_TOKEN_LASTTOUCH:
1481 #ifdef HAVE_TOUCHSCREEN
1482 unsigned int last_touch = touchscreen_last_touch();
1483 char *skin_base = get_skin_buffer(data);
1484 struct touchregion_lastpress *data = SKINOFFSETTOPTR(skin_base, token->value.data);
1485 struct touchregion *region = SKINOFFSETTOPTR(skin_base, data->region);
1486 if (region)
1487 last_touch = region->last_press;
1489 if (last_touch != 0xffff &&
1490 TIME_BEFORE(current_tick, data->timeout + last_touch))
1491 return "t";
1492 #endif
1494 return NULL;
1495 case SKIN_TOKEN_HAVE_TOUCH:
1496 #ifdef HAVE_TOUCHSCREEN
1497 return "t";
1498 #else
1499 return NULL;
1500 #endif
1502 case SKIN_TOKEN_SETTING:
1504 const struct settings_list *s = settings+token->value.i;
1505 if (intval)
1507 /* Handle contionals */
1508 switch (s->flags&F_T_MASK)
1510 case F_T_INT:
1511 case F_T_UINT:
1512 if (s->flags&F_T_SOUND)
1514 /* %?St|name|<min|min+1|...|max-1|max> */
1515 int sound_setting = s->sound_setting->setting;
1516 /* settings with decimals can't be used in conditionals */
1517 if (sound_numdecimals(sound_setting) == 0)
1519 *intval = (*(int*)s->setting-sound_min(sound_setting))
1520 /sound_steps(sound_setting) + 1;
1522 else
1523 *intval = -1;
1525 else if (s->flags&F_RGB)
1526 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1527 /* shouldn't overflow since colors are stored
1528 * on 16 bits ...
1529 * but this is pretty useless anyway */
1530 *intval = *(int*)s->setting + 1;
1531 else if (s->cfg_vals == NULL)
1532 /* %?St|name|<1st choice|2nd choice|...> */
1533 *intval = (*(int*)s->setting-s->int_setting->min)
1534 /s->int_setting->step + 1;
1535 else
1536 /* %?St|name|<1st choice|2nd choice|...> */
1537 /* Not sure about this one. cfg_name/vals are
1538 * indexed from 0 right? */
1539 *intval = *(int*)s->setting + 1;
1540 break;
1541 case F_T_BOOL:
1542 /* %?St|name|<if true|if false> */
1543 *intval = *(bool*)s->setting?1:2;
1544 break;
1545 case F_T_CHARPTR:
1546 case F_T_UCHARPTR:
1547 /* %?St|name|<if non empty string|if empty>
1548 * The string's emptyness discards the setting's
1549 * prefix and suffix */
1550 *intval = ((char*)s->setting)[0]?1:2;
1551 /* if there is a prefix we should ignore it here */
1552 if (s->filename_setting->prefix)
1553 return (char*)s->setting;
1554 break;
1555 default:
1556 /* This shouldn't happen ... but you never know */
1557 *intval = -1;
1558 break;
1561 /* Special handlng for filenames because we dont want to show the prefix */
1562 if ((s->flags&F_T_MASK) == F_T_CHARPTR ||
1563 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1565 if (s->filename_setting->prefix)
1566 return (char*)s->setting;
1568 cfg_to_string(token->value.i,buf,buf_size);
1569 return buf;
1571 case SKIN_TOKEN_HAVE_TUNER:
1572 #if CONFIG_TUNER
1573 if (radio_hardware_present())
1574 return "r";
1575 #endif
1576 return NULL;
1577 /* Recording tokens */
1578 case SKIN_TOKEN_HAVE_RECORDING:
1579 #ifdef HAVE_RECORDING
1580 return "r";
1581 #else
1582 return NULL;
1583 #endif
1585 #ifdef HAVE_RECORDING
1586 case SKIN_TOKEN_IS_RECORDING:
1587 if (audio_status() == AUDIO_STATUS_RECORD)
1588 return "r";
1589 return NULL;
1590 case SKIN_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1592 #if CONFIG_CODEC == SWCODEC
1593 unsigned long samprk;
1594 int rec_freq = global_settings.rec_frequency;
1596 #ifdef SIMULATOR
1597 samprk = 44100;
1598 #else
1599 #if defined(HAVE_SPDIF_REC)
1600 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1602 /* Use rate in use, not current measured rate if it changed */
1603 samprk = pcm_rec_sample_rate();
1604 rec_freq = 0;
1605 while (rec_freq < SAMPR_NUM_FREQ &&
1606 audio_master_sampr_list[rec_freq] != samprk)
1608 rec_freq++;
1611 else
1612 #endif
1613 samprk = rec_freq_sampr[rec_freq];
1614 #endif /* SIMULATOR */
1615 if (intval)
1617 switch (rec_freq)
1619 REC_HAVE_96_(case REC_FREQ_96:
1620 *intval = 1;
1621 break;)
1622 REC_HAVE_88_(case REC_FREQ_88:
1623 *intval = 2;
1624 break;)
1625 REC_HAVE_64_(case REC_FREQ_64:
1626 *intval = 3;
1627 break;)
1628 REC_HAVE_48_(case REC_FREQ_48:
1629 *intval = 4;
1630 break;)
1631 REC_HAVE_44_(case REC_FREQ_44:
1632 *intval = 5;
1633 break;)
1634 REC_HAVE_32_(case REC_FREQ_32:
1635 *intval = 6;
1636 break;)
1637 REC_HAVE_24_(case REC_FREQ_24:
1638 *intval = 7;
1639 break;)
1640 REC_HAVE_22_(case REC_FREQ_22:
1641 *intval = 8;
1642 break;)
1643 REC_HAVE_16_(case REC_FREQ_16:
1644 *intval = 9;
1645 break;)
1646 REC_HAVE_12_(case REC_FREQ_12:
1647 *intval = 10;
1648 break;)
1649 REC_HAVE_11_(case REC_FREQ_11:
1650 *intval = 11;
1651 break;)
1652 REC_HAVE_8_(case REC_FREQ_8:
1653 *intval = 12;
1654 break;)
1657 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1658 #else /* HWCODEC */
1660 static const char * const freq_strings[] =
1661 {"--", "44", "48", "32", "22", "24", "16"};
1662 int freq = 1 + global_settings.rec_frequency;
1663 #ifdef HAVE_SPDIF_REC
1664 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1666 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1667 freq = 0;
1669 #endif /* HAVE_SPDIF_IN */
1670 if (intval)
1671 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1672 snprintf(buf, buf_size, "%s\n",
1673 freq_strings[global_settings.rec_frequency]);
1674 #endif
1675 return buf;
1677 #if CONFIG_CODEC == SWCODEC
1678 case SKIN_TOKEN_REC_ENCODER:
1680 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1681 if (intval)
1682 *intval = rec_format;
1683 switch (rec_format)
1685 case REC_FORMAT_PCM_WAV:
1686 return "wav";
1687 case REC_FORMAT_AIFF:
1688 return "aiff";
1689 case REC_FORMAT_WAVPACK:
1690 return "wv";
1691 case REC_FORMAT_MPA_L3:
1692 return "MP3";
1693 default:
1694 return NULL;
1696 break;
1698 #endif
1699 case SKIN_TOKEN_REC_BITRATE:
1700 #if CONFIG_CODEC == SWCODEC
1701 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1703 if (intval)
1705 #if 0 /* FIXME: I dont know if this is needed? */
1706 switch (1<<global_settings.mp3_enc_config.bitrate)
1708 case MP3_BITR_CAP_8:
1709 *intval = 1;
1710 break;
1711 case MP3_BITR_CAP_16:
1712 *intval = 2;
1713 break;
1714 case MP3_BITR_CAP_24:
1715 *intval = 3;
1716 break;
1717 case MP3_BITR_CAP_32:
1718 *intval = 4;
1719 break;
1720 case MP3_BITR_CAP_40:
1721 *intval = 5;
1722 break;
1723 case MP3_BITR_CAP_48:
1724 *intval = 6;
1725 break;
1726 case MP3_BITR_CAP_56:
1727 *intval = 7;
1728 break;
1729 case MP3_BITR_CAP_64:
1730 *intval = 8;
1731 break;
1732 case MP3_BITR_CAP_80:
1733 *intval = 9;
1734 break;
1735 case MP3_BITR_CAP_96:
1736 *intval = 10;
1737 break;
1738 case MP3_BITR_CAP_112:
1739 *intval = 11;
1740 break;
1741 case MP3_BITR_CAP_128:
1742 *intval = 12;
1743 break;
1744 case MP3_BITR_CAP_144:
1745 *intval = 13;
1746 break;
1747 case MP3_BITR_CAP_160:
1748 *intval = 14;
1749 break;
1750 case MP3_BITR_CAP_192:
1751 *intval = 15;
1752 break;
1754 #endif
1755 *intval = global_settings.mp3_enc_config.bitrate+1;
1757 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1758 return buf;
1760 else
1761 return NULL; /* Fixme later */
1762 #else /* CONFIG_CODEC == HWCODEC */
1763 if (intval)
1764 *intval = global_settings.rec_quality+1;
1765 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1766 return buf;
1767 #endif
1768 case SKIN_TOKEN_REC_MONO:
1769 if (!global_settings.rec_channels)
1770 return "m";
1771 return NULL;
1773 case SKIN_TOKEN_REC_SECONDS:
1775 int time = (audio_recorded_time() / HZ) % 60;
1776 if (intval)
1777 *intval = time;
1778 snprintf(buf, buf_size, "%02d", time);
1779 return buf;
1781 case SKIN_TOKEN_REC_MINUTES:
1783 int time = (audio_recorded_time() / HZ) / 60;
1784 if (intval)
1785 *intval = time;
1786 snprintf(buf, buf_size, "%02d", time);
1787 return buf;
1789 case SKIN_TOKEN_REC_HOURS:
1791 int time = (audio_recorded_time() / HZ) / 3600;
1792 if (intval)
1793 *intval = time;
1794 snprintf(buf, buf_size, "%02d", time);
1795 return buf;
1798 #endif /* HAVE_RECORDING */
1800 case SKIN_TOKEN_CURRENT_SCREEN:
1802 int curr_screen = get_current_activity();
1803 if (intval)
1805 *intval = curr_screen;
1807 snprintf(buf, buf_size, "%d", curr_screen);
1808 return buf;
1811 case SKIN_TOKEN_LANG_IS_RTL:
1812 return lang_is_rtl() ? "r" : NULL;
1814 #ifdef HAVE_SKIN_VARIABLES
1815 case SKIN_TOKEN_VAR_GETVAL:
1817 char *skin_base = get_skin_buffer(data);
1818 struct skin_var* var = SKINOFFSETTOPTR(skin_base, token->value.data);
1819 if (intval)
1820 *intval = var->value;
1821 snprintf(buf, buf_size, "%d", var->value);
1822 return buf;
1824 break;
1825 case SKIN_TOKEN_VAR_TIMEOUT:
1827 char *skin_base = get_skin_buffer(data);
1828 struct skin_var_lastchange *data = SKINOFFSETTOPTR(skin_base, token->value.data);
1829 struct skin_var* var = SKINOFFSETTOPTR(skin_base, data->var);
1830 unsigned int last_change = var->last_changed;
1832 if (last_change != 0xffff &&
1833 TIME_BEFORE(current_tick, data->timeout + last_change))
1834 return "t";
1836 return NULL;
1837 #endif
1839 default:
1840 return NULL;