diff options
Diffstat (limited to 'apps/wps-display.c')
-rw-r--r-- | apps/wps-display.c | 1841 |
1 files changed, 0 insertions, 1841 deletions
diff --git a/apps/wps-display.c b/apps/wps-display.c deleted file mode 100644 index 58a953e4c0..0000000000 --- a/apps/wps-display.c +++ /dev/null | |||
@@ -1,1841 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 Björn Stenberg | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | /* ID3 formatting based on code from the MAD Winamp plugin (in_mad.dll), | ||
21 | * Copyright (C) 2000-2001 Robert Leslie. | ||
22 | * See http://www.mars.org/home/rob/proj/mpeg/ for more information. | ||
23 | */ | ||
24 | |||
25 | #include <stdio.h> | ||
26 | #include <string.h> | ||
27 | #include <stdlib.h> | ||
28 | |||
29 | #include "lcd.h" | ||
30 | #include "hwcompat.h" | ||
31 | #include "font.h" | ||
32 | #include "audio.h" | ||
33 | #include "id3.h" | ||
34 | #include "settings.h" | ||
35 | #include "playlist.h" | ||
36 | #include "kernel.h" | ||
37 | #include "system.h" | ||
38 | #include "status.h" | ||
39 | #include "wps-display.h" | ||
40 | #include "debug.h" | ||
41 | #include "mas.h" | ||
42 | #include "lang.h" | ||
43 | #include "powermgmt.h" | ||
44 | #include "power.h" | ||
45 | #include "sprintf.h" | ||
46 | #include "backlight.h" | ||
47 | #include "button.h" | ||
48 | #include "abrepeat.h" | ||
49 | #include "screens.h" | ||
50 | #include "splash.h" | ||
51 | #ifdef HAVE_LCD_BITMAP | ||
52 | #include <ctype.h> | ||
53 | #include "icons.h" | ||
54 | #include "widgets.h" | ||
55 | #include "peakmeter.h" | ||
56 | |||
57 | /* Image stuff */ | ||
58 | #include "bmp.h" | ||
59 | #include "atoi.h" | ||
60 | #define MAX_IMAGES (26*2) /* a-z and A-Z */ | ||
61 | #define IMG_BUFSIZE (LCD_HEIGHT * LCD_WIDTH * MAX_IMAGES / 25 ) / 8 | ||
62 | static unsigned char img_buf[IMG_BUFSIZE]; /* image buffer */ | ||
63 | static unsigned char* img_buf_ptr = img_buf; /* where are in image buffer? */ | ||
64 | |||
65 | static int img_buf_free = IMG_BUFSIZE; /* free space in image buffer */ | ||
66 | |||
67 | struct { | ||
68 | unsigned char* ptr; /* pointer */ | ||
69 | int x; /* x-pos */ | ||
70 | int y; /* y-pos */ | ||
71 | int w; /* width */ | ||
72 | int h; /* height */ | ||
73 | bool loaded; /* load state */ | ||
74 | bool display; /* is to be displayed */ | ||
75 | bool always_display; /* not using the preload/display mechanism */ | ||
76 | } img[MAX_IMAGES] ; | ||
77 | |||
78 | |||
79 | #endif | ||
80 | |||
81 | #define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps" | ||
82 | |||
83 | #ifdef HAVE_LCD_BITMAP | ||
84 | #define MAX_LINES (LCD_HEIGHT/5+1) | ||
85 | #define FORMAT_BUFFER_SIZE 3072 | ||
86 | #else | ||
87 | #define MAX_LINES 2 | ||
88 | #define FORMAT_BUFFER_SIZE 400 | ||
89 | #endif | ||
90 | #define MAX_SUBLINES 12 | ||
91 | #define DEFAULT_SUBLINE_TIME_MULTIPLIER 20 /* (10ths of sec) */ | ||
92 | #define BASE_SUBLINE_TIME 10 /* base time that multiplier is applied to | ||
93 | (1/HZ sec, or 100ths of sec) */ | ||
94 | #define SUBLINE_RESET -1 | ||
95 | |||
96 | #ifdef HAVE_LCD_CHARCELLS | ||
97 | static unsigned char wps_progress_pat[8]={0,0,0,0,0,0,0,0}; | ||
98 | static bool full_line_progressbar=0; | ||
99 | static bool draw_player_progress(const struct mp3entry* id3, | ||
100 | int ff_rewwind_count); | ||
101 | static void draw_player_fullbar(char* buf, int buf_size, | ||
102 | const struct mp3entry* id3, | ||
103 | int ff_rewwind_count); | ||
104 | static char map_fullbar_char(char ascii_val); | ||
105 | #endif | ||
106 | |||
107 | struct align_pos { | ||
108 | char* left; | ||
109 | char* center; | ||
110 | char* right; | ||
111 | }; | ||
112 | static char format_buffer[FORMAT_BUFFER_SIZE]; | ||
113 | static char* format_lines[MAX_LINES][MAX_SUBLINES]; | ||
114 | static struct align_pos format_align[MAX_LINES][MAX_SUBLINES]; | ||
115 | static unsigned char line_type[MAX_LINES][MAX_SUBLINES]; | ||
116 | static unsigned short time_mult[MAX_LINES][MAX_SUBLINES]; | ||
117 | static long subline_expire_time[MAX_LINES]; | ||
118 | static int curr_subline[MAX_LINES]; | ||
119 | |||
120 | static int ff_rewind_count; | ||
121 | bool wps_time_countup = true; | ||
122 | static bool wps_loaded = false; | ||
123 | |||
124 | #ifdef HAVE_LCD_BITMAP | ||
125 | /* Display images */ | ||
126 | static void wps_display_images(void) { | ||
127 | int n; | ||
128 | for (n = 0; n < MAX_IMAGES; n++) { | ||
129 | if (img[n].loaded && img[n].display) { | ||
130 | if(img[n].always_display) | ||
131 | lcd_set_drawmode(DRMODE_FG); | ||
132 | else | ||
133 | lcd_set_drawmode(DRMODE_SOLID); | ||
134 | |||
135 | lcd_mono_bitmap(img[n].ptr, img[n].x, img[n].y, img[n].w, img[n].h); | ||
136 | lcd_update_rect(img[n].x, img[n].y, img[n].w, img[n].h); | ||
137 | } | ||
138 | } | ||
139 | lcd_set_drawmode(DRMODE_SOLID); | ||
140 | } | ||
141 | #endif | ||
142 | |||
143 | /* Set format string to use for WPS, splitting it into lines */ | ||
144 | static void wps_format(const char* fmt, char *bmpdir, size_t bmpdirlen) | ||
145 | { | ||
146 | char* buf = format_buffer; | ||
147 | char* start_of_line = format_buffer; | ||
148 | int line = 0; | ||
149 | int subline; | ||
150 | #ifndef HAVE_LCD_BITMAP | ||
151 | /* no bitmap lcd == no bitmap loading */ | ||
152 | (void)bmpdir; | ||
153 | (void)bmpdirlen; | ||
154 | #endif | ||
155 | |||
156 | strncpy(format_buffer, fmt, sizeof(format_buffer)); | ||
157 | format_buffer[sizeof(format_buffer) - 1] = 0; | ||
158 | |||
159 | for (line=0; line<MAX_LINES; line++) | ||
160 | { | ||
161 | for (subline=0; subline<MAX_SUBLINES; subline++) | ||
162 | { | ||
163 | format_lines[line][subline] = 0; | ||
164 | time_mult[line][subline] = 0; | ||
165 | } | ||
166 | subline_expire_time[line] = 0; | ||
167 | curr_subline[line] = SUBLINE_RESET; | ||
168 | } | ||
169 | |||
170 | line = 0; | ||
171 | subline = 0; | ||
172 | format_lines[line][subline] = buf; | ||
173 | |||
174 | while ((*buf) && (line < MAX_LINES)) | ||
175 | { | ||
176 | switch (*buf) | ||
177 | { | ||
178 | /* | ||
179 | * skip % sequences so "%;" doesn't start a new subline | ||
180 | * don't skip %x lines (pre-load bitmaps) | ||
181 | */ | ||
182 | case '%': | ||
183 | if (*(buf+1) != 'x') | ||
184 | buf++; | ||
185 | break; | ||
186 | |||
187 | case '\r': /* CR */ | ||
188 | *buf = 0; | ||
189 | break; | ||
190 | |||
191 | case '\n': /* LF */ | ||
192 | *buf = 0; | ||
193 | |||
194 | if (*start_of_line != '#') /* A comment? */ | ||
195 | line++; | ||
196 | |||
197 | if (line < MAX_LINES) | ||
198 | { | ||
199 | /* the next line starts on the next byte */ | ||
200 | subline = 0; | ||
201 | format_lines[line][subline] = buf+1; | ||
202 | start_of_line = format_lines[line][subline]; | ||
203 | } | ||
204 | break; | ||
205 | |||
206 | case ';': /* start a new subline */ | ||
207 | *buf = 0; | ||
208 | subline++; | ||
209 | if (subline < MAX_SUBLINES) | ||
210 | { | ||
211 | format_lines[line][subline] = buf+1; | ||
212 | } | ||
213 | else /* exceeded max sublines, skip rest of line */ | ||
214 | { | ||
215 | while (*(++buf)) | ||
216 | { | ||
217 | if ((*buf == '\r') || (*buf == '\n')) | ||
218 | { | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | buf--; | ||
223 | subline = 0; | ||
224 | } | ||
225 | break; | ||
226 | |||
227 | case 'x': | ||
228 | #ifdef HAVE_LCD_BITMAP | ||
229 | /* Preload images so the %xd# tag can display it */ | ||
230 | { | ||
231 | int ret = 0; | ||
232 | int n; | ||
233 | char *ptr = buf+1; | ||
234 | char *pos = NULL; | ||
235 | char imgname[MAX_PATH]; | ||
236 | char qual = *ptr; | ||
237 | if (qual == 'l' || qual == '|') /* format: | ||
238 | %x|n|filename.bmp|x|y| | ||
239 | or | ||
240 | %xl|n|filename.bmp|x|y| | ||
241 | */ | ||
242 | { | ||
243 | ptr = strchr(ptr, '|') + 1; | ||
244 | pos = strchr(ptr, '|'); | ||
245 | if (pos) | ||
246 | { | ||
247 | /* get the image ID */ | ||
248 | n = *ptr; | ||
249 | if(n >= 'a' && n <= 'z') | ||
250 | n -= 'a'; | ||
251 | if(n >= 'A' && n <= 'Z') | ||
252 | n = n - 'A' + 26; | ||
253 | |||
254 | if(n < 0 || n >= MAX_IMAGES) | ||
255 | { | ||
256 | /* Skip the rest of the line */ | ||
257 | while(*buf != '\n') | ||
258 | buf++; | ||
259 | break; | ||
260 | } | ||
261 | ptr = pos+1; | ||
262 | |||
263 | /* check the image number and load state */ | ||
264 | if (!img[n].loaded) | ||
265 | { | ||
266 | /* get filename */ | ||
267 | pos = strchr(ptr, '|'); | ||
268 | if ((pos - ptr) < | ||
269 | (int)sizeof(imgname)-ROCKBOX_DIR_LEN-2) | ||
270 | { | ||
271 | memcpy(imgname, bmpdir, bmpdirlen); | ||
272 | imgname[bmpdirlen] = '/'; | ||
273 | memcpy(&imgname[bmpdirlen+1], | ||
274 | ptr, pos - ptr); | ||
275 | imgname[bmpdirlen+1+pos-ptr] = 0; | ||
276 | } | ||
277 | else | ||
278 | /* filename too long */ | ||
279 | imgname[0] = 0; | ||
280 | |||
281 | ptr = pos+1; | ||
282 | |||
283 | /* get x-position */ | ||
284 | pos = strchr(ptr, '|'); | ||
285 | if (pos) | ||
286 | img[n].x = atoi(ptr); | ||
287 | else | ||
288 | { | ||
289 | /* weird syntax, bail out */ | ||
290 | buf++; | ||
291 | break; | ||
292 | } | ||
293 | |||
294 | /* get y-position */ | ||
295 | ptr = pos+1; | ||
296 | pos = strchr(ptr, '|'); | ||
297 | if (pos) | ||
298 | img[n].y = atoi(ptr); | ||
299 | else | ||
300 | { | ||
301 | /* weird syntax, bail out */ | ||
302 | buf++; | ||
303 | break; | ||
304 | } | ||
305 | |||
306 | pos++; | ||
307 | |||
308 | /* reposition buf pointer to next WPS element */ | ||
309 | while (*pos && *pos != ';' && | ||
310 | *pos != '\r' && *pos != '\n') | ||
311 | pos++; | ||
312 | |||
313 | buf = pos; | ||
314 | |||
315 | /* load the image */ | ||
316 | ret = read_bmp_file(imgname, &img[n].w, &img[n].h, | ||
317 | img_buf_ptr, img_buf_free); | ||
318 | if (ret > 0) | ||
319 | { | ||
320 | img[n].ptr = img_buf_ptr; | ||
321 | img_buf_ptr += ret; | ||
322 | img_buf_free -= ret; | ||
323 | img[n].loaded = true; | ||
324 | if(qual == '|') | ||
325 | img[n].always_display = true; | ||
326 | } | ||
327 | } | ||
328 | buf++; | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | #endif | ||
333 | break; | ||
334 | } | ||
335 | buf++; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | /* Clear the WPS image cache */ | ||
340 | static void wps_clear(void) | ||
341 | { | ||
342 | #ifdef HAVE_LCD_BITMAP | ||
343 | int i; | ||
344 | |||
345 | /* reset image buffer */ | ||
346 | img_buf_ptr = img_buf; | ||
347 | img_buf_free = IMG_BUFSIZE; | ||
348 | |||
349 | /* set images to unloaded and not displayed */ | ||
350 | for (i = 0; i < MAX_IMAGES; i++) { | ||
351 | img[i].loaded = false; | ||
352 | img[i].display = false; | ||
353 | img[i].always_display = false; | ||
354 | } | ||
355 | #endif | ||
356 | |||
357 | } | ||
358 | |||
359 | void wps_reset(void) | ||
360 | { | ||
361 | wps_loaded = false; | ||
362 | memset(&format_buffer, 0, sizeof format_buffer); | ||
363 | wps_clear(); | ||
364 | } | ||
365 | |||
366 | bool wps_load(const char* file, bool display) | ||
367 | { | ||
368 | int i,s; | ||
369 | char buffer[FORMAT_BUFFER_SIZE]; | ||
370 | int fd; | ||
371 | size_t bmpdirlen; | ||
372 | |||
373 | char *bmpdir = strrchr(file, '.'); | ||
374 | bmpdirlen = bmpdir - file; | ||
375 | |||
376 | /* | ||
377 | * Hardcode loading WPS_DEFAULTCFG to cause a reset ideally this | ||
378 | * wants to be a virtual file. Feel free to modify dirbrowse() | ||
379 | * if you're feeling brave. | ||
380 | */ | ||
381 | if (! strcmp(file, WPS_DEFAULTCFG) ) { | ||
382 | wps_reset(); | ||
383 | return(false); | ||
384 | } | ||
385 | |||
386 | fd = open(file, O_RDONLY); | ||
387 | |||
388 | if (fd >= 0) | ||
389 | { | ||
390 | int numread = read(fd, buffer, sizeof(buffer) - 1); | ||
391 | |||
392 | if (numread > 0) | ||
393 | { | ||
394 | wps_clear(); | ||
395 | buffer[numread] = 0; | ||
396 | wps_format(buffer, (char *)file, bmpdirlen); | ||
397 | } | ||
398 | |||
399 | close(fd); | ||
400 | |||
401 | if ( display ) { | ||
402 | bool any_defined_line; | ||
403 | lcd_clear_display(); | ||
404 | #ifdef HAVE_LCD_BITMAP | ||
405 | lcd_setmargins(0,0); | ||
406 | #endif | ||
407 | for (s=0; s<MAX_SUBLINES; s++) | ||
408 | { | ||
409 | any_defined_line = false; | ||
410 | for (i=0; i<MAX_LINES; i++) | ||
411 | { | ||
412 | if (format_lines[i][s]) | ||
413 | { | ||
414 | if (*format_lines[i][s] == 0) | ||
415 | lcd_puts(0,i," "); | ||
416 | else | ||
417 | lcd_puts(0,i,format_lines[i][s]); | ||
418 | any_defined_line = true; | ||
419 | } | ||
420 | else | ||
421 | { | ||
422 | lcd_puts(0,i," "); | ||
423 | } | ||
424 | } | ||
425 | if (any_defined_line) | ||
426 | { | ||
427 | #ifdef HAVE_LCD_BITMAP | ||
428 | wps_display_images(); | ||
429 | #endif | ||
430 | lcd_update(); | ||
431 | sleep(HZ/2); | ||
432 | } | ||
433 | } | ||
434 | } | ||
435 | wps_loaded = true; | ||
436 | |||
437 | return numread > 0; | ||
438 | } | ||
439 | |||
440 | return false; | ||
441 | } | ||
442 | |||
443 | /* Format time into buf. | ||
444 | * | ||
445 | * buf - buffer to format to. | ||
446 | * buf_size - size of buffer. | ||
447 | * time - time to format, in milliseconds. | ||
448 | */ | ||
449 | void wps_format_time(char* buf, int buf_size, long time) | ||
450 | { | ||
451 | if ( time < 3600000 ) { | ||
452 | snprintf(buf, buf_size, "%d:%02d", | ||
453 | (int) (time % 3600000 / 60000), (int) (time % 60000 / 1000)); | ||
454 | } else { | ||
455 | snprintf(buf, buf_size, "%d:%02d:%02d", | ||
456 | (int) (time / 3600000), (int) (time % 3600000 / 60000), | ||
457 | (int) (time % 60000 / 1000)); | ||
458 | } | ||
459 | } | ||
460 | |||
461 | /* Extract a part from a path. | ||
462 | * | ||
463 | * buf - buffer extract part to. | ||
464 | * buf_size - size of buffer. | ||
465 | * path - path to extract from. | ||
466 | * level - what to extract. 0 is file name, 1 is parent of file, 2 is | ||
467 | * parent of parent, etc. | ||
468 | * | ||
469 | * Returns buf if the desired level was found, NULL otherwise. | ||
470 | */ | ||
471 | static char* get_dir(char* buf, int buf_size, const char* path, int level) | ||
472 | { | ||
473 | const char* sep; | ||
474 | const char* last_sep; | ||
475 | int len; | ||
476 | |||
477 | sep = path + strlen(path); | ||
478 | last_sep = sep; | ||
479 | |||
480 | while (sep > path) | ||
481 | { | ||
482 | if ('/' == *(--sep)) | ||
483 | { | ||
484 | if (!level) | ||
485 | { | ||
486 | break; | ||
487 | } | ||
488 | |||
489 | level--; | ||
490 | last_sep = sep - 1; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | if (level || (last_sep <= sep)) | ||
495 | { | ||
496 | return NULL; | ||
497 | } | ||
498 | |||
499 | len = MIN(last_sep - sep, buf_size - 1); | ||
500 | strncpy(buf, sep + 1, len); | ||
501 | buf[len] = 0; | ||
502 | return buf; | ||
503 | } | ||
504 | |||
505 | /* Get the tag specified by the two characters at fmt. | ||
506 | * | ||
507 | * cid3 - ID3 data to get tag values from. | ||
508 | * nid3 - next-song ID3 data to get tag values from. | ||
509 | * tag - string (of two characters) specifying the tag to get. | ||
510 | * buf - buffer to certain tags, such as track number, play time or | ||
511 | * directory name. | ||
512 | * buf_size - size of buffer. | ||
513 | * flags - returns the type of the line. See constants i wps-display.h | ||
514 | * | ||
515 | * Returns the tag. NULL indicates the tag wasn't available. | ||
516 | */ | ||
517 | static char* get_tag(struct mp3entry* cid3, | ||
518 | struct mp3entry* nid3, | ||
519 | const char* tag, | ||
520 | char* buf, | ||
521 | int buf_size, | ||
522 | unsigned char* tag_len, | ||
523 | unsigned short* subline_time_mult, | ||
524 | unsigned char* flags, | ||
525 | int *intval) | ||
526 | { | ||
527 | struct mp3entry *id3 = cid3; /* default to current song */ | ||
528 | |||
529 | if ((0 == tag[0]) || (0 == tag[1])) | ||
530 | { | ||
531 | *tag_len = 0; | ||
532 | return NULL; | ||
533 | } | ||
534 | |||
535 | *tag_len = 2; | ||
536 | |||
537 | *intval = 0; | ||
538 | |||
539 | switch (tag[0]) | ||
540 | { | ||
541 | case 'I': /* ID3 Information */ | ||
542 | id3 = nid3; /* display next-song data */ | ||
543 | *flags |= WPS_REFRESH_DYNAMIC; | ||
544 | if(!id3) | ||
545 | return NULL; /* no such info (yet) */ | ||
546 | /* fall-through */ | ||
547 | case 'i': /* ID3 Information */ | ||
548 | *flags |= WPS_REFRESH_STATIC; | ||
549 | switch (tag[1]) | ||
550 | { | ||
551 | case 't': /* ID3 Title */ | ||
552 | return id3->title; | ||
553 | |||
554 | case 'a': /* ID3 Artist */ | ||
555 | return id3->artist; | ||
556 | |||
557 | case 'n': /* ID3 Track Number */ | ||
558 | if (id3->track_string) | ||
559 | return id3->track_string; | ||
560 | |||
561 | if (id3->tracknum) { | ||
562 | snprintf(buf, buf_size, "%d", id3->tracknum); | ||
563 | return buf; | ||
564 | } | ||
565 | return NULL; | ||
566 | |||
567 | case 'd': /* ID3 Album/Disc */ | ||
568 | return id3->album; | ||
569 | |||
570 | case 'c': /* ID3 Composer */ | ||
571 | return id3->composer; | ||
572 | |||
573 | case 'y': /* year */ | ||
574 | if( id3->year_string ) | ||
575 | return id3->year_string; | ||
576 | |||
577 | if (id3->year) { | ||
578 | snprintf(buf, buf_size, "%d", id3->year); | ||
579 | return buf; | ||
580 | } | ||
581 | return NULL; | ||
582 | |||
583 | case 'g': /* genre */ | ||
584 | return id3_get_genre(id3); | ||
585 | |||
586 | case 'v': /* id3 version */ | ||
587 | switch (id3->id3version) { | ||
588 | case ID3_VER_1_0: | ||
589 | return "1"; | ||
590 | |||
591 | case ID3_VER_1_1: | ||
592 | return "1.1"; | ||
593 | |||
594 | case ID3_VER_2_2: | ||
595 | return "2.2"; | ||
596 | |||
597 | case ID3_VER_2_3: | ||
598 | return "2.3"; | ||
599 | |||
600 | case ID3_VER_2_4: | ||
601 | return "2.4"; | ||
602 | |||
603 | default: | ||
604 | return NULL; | ||
605 | } | ||
606 | } | ||
607 | break; | ||
608 | |||
609 | case 'F': /* File Information */ | ||
610 | id3 = nid3; | ||
611 | *flags |= WPS_REFRESH_DYNAMIC; | ||
612 | if(!id3) | ||
613 | return NULL; /* no such info (yet) */ | ||
614 | /* fall-through */ | ||
615 | case 'f': /* File Information */ | ||
616 | *flags |= WPS_REFRESH_STATIC; | ||
617 | switch(tag[1]) | ||
618 | { | ||
619 | case 'v': /* VBR file? */ | ||
620 | return id3->vbr ? "(avg)" : NULL; | ||
621 | |||
622 | case 'b': /* File Bitrate */ | ||
623 | if(id3->bitrate) | ||
624 | snprintf(buf, buf_size, "%d", id3->bitrate); | ||
625 | else | ||
626 | snprintf(buf, buf_size, "?"); | ||
627 | return buf; | ||
628 | |||
629 | case 'f': /* File Frequency */ | ||
630 | snprintf(buf, buf_size, "%ld", id3->frequency); | ||
631 | return buf; | ||
632 | |||
633 | case 'p': /* File Path */ | ||
634 | return id3->path; | ||
635 | |||
636 | case 'm': /* File Name - With Extension */ | ||
637 | return get_dir(buf, buf_size, id3->path, 0); | ||
638 | |||
639 | case 'n': /* File Name */ | ||
640 | if (get_dir(buf, buf_size, id3->path, 0)) | ||
641 | { | ||
642 | /* Remove extension */ | ||
643 | char* sep = strrchr(buf, '.'); | ||
644 | |||
645 | if (NULL != sep) | ||
646 | { | ||
647 | *sep = 0; | ||
648 | } | ||
649 | |||
650 | return buf; | ||
651 | } | ||
652 | else | ||
653 | { | ||
654 | return NULL; | ||
655 | } | ||
656 | |||
657 | case 's': /* File Size (in kilobytes) */ | ||
658 | snprintf(buf, buf_size, "%ld", id3->filesize / 1024); | ||
659 | return buf; | ||
660 | |||
661 | case 'c': /* File Codec */ | ||
662 | if(id3->codectype == AFMT_UNKNOWN) | ||
663 | *intval = AFMT_NUM_CODECS; | ||
664 | else | ||
665 | *intval = id3->codectype; | ||
666 | return id3_get_codec(id3); | ||
667 | } | ||
668 | break; | ||
669 | |||
670 | case 'p': /* Playlist/Song Information */ | ||
671 | switch(tag[1]) | ||
672 | { | ||
673 | case 'b': /* progress bar */ | ||
674 | *flags |= WPS_REFRESH_PLAYER_PROGRESS; | ||
675 | #ifdef HAVE_LCD_CHARCELLS | ||
676 | snprintf(buf, buf_size, "%c", wps_progress_pat[0]); | ||
677 | full_line_progressbar=0; | ||
678 | return buf; | ||
679 | #else | ||
680 | return "\x01"; | ||
681 | #endif | ||
682 | case 'f': /* full-line progress bar */ | ||
683 | #ifdef HAVE_LCD_CHARCELLS | ||
684 | if(is_new_player()) { | ||
685 | *flags |= WPS_REFRESH_PLAYER_PROGRESS; | ||
686 | *flags |= WPS_REFRESH_DYNAMIC; | ||
687 | full_line_progressbar=1; | ||
688 | /* we need 11 characters (full line) for | ||
689 | progress-bar */ | ||
690 | snprintf(buf, buf_size, " "); | ||
691 | } | ||
692 | else | ||
693 | { | ||
694 | /* Tell the user if we have an OldPlayer */ | ||
695 | snprintf(buf, buf_size, " <Old LCD> "); | ||
696 | } | ||
697 | return buf; | ||
698 | #endif | ||
699 | case 'p': /* Playlist Position */ | ||
700 | *flags |= WPS_REFRESH_STATIC; | ||
701 | snprintf(buf, buf_size, "%d", playlist_get_display_index()); | ||
702 | return buf; | ||
703 | |||
704 | case 'n': /* Playlist Name (without path) */ | ||
705 | *flags |= WPS_REFRESH_STATIC; | ||
706 | return playlist_name(NULL, buf, buf_size); | ||
707 | |||
708 | case 'e': /* Playlist Total Entries */ | ||
709 | *flags |= WPS_REFRESH_STATIC; | ||
710 | snprintf(buf, buf_size, "%d", playlist_amount()); | ||
711 | return buf; | ||
712 | |||
713 | case 'c': /* Current Time in Song */ | ||
714 | *flags |= WPS_REFRESH_DYNAMIC; | ||
715 | wps_format_time(buf, buf_size, | ||
716 | id3->elapsed + ff_rewind_count); | ||
717 | return buf; | ||
718 | |||
719 | case 'r': /* Remaining Time in Song */ | ||
720 | *flags |= WPS_REFRESH_DYNAMIC; | ||
721 | wps_format_time(buf, buf_size, | ||
722 | id3->length - id3->elapsed - ff_rewind_count); | ||
723 | return buf; | ||
724 | |||
725 | case 't': /* Total Time */ | ||
726 | *flags |= WPS_REFRESH_STATIC; | ||
727 | wps_format_time(buf, buf_size, id3->length); | ||
728 | return buf; | ||
729 | |||
730 | #ifdef HAVE_LCD_BITMAP | ||
731 | case 'm': /* Peak Meter */ | ||
732 | *flags |= WPS_REFRESH_PEAK_METER; | ||
733 | return "\x01"; | ||
734 | #endif | ||
735 | case 's': /* shuffle */ | ||
736 | *flags |= WPS_REFRESH_DYNAMIC; | ||
737 | if ( global_settings.playlist_shuffle ) | ||
738 | return "s"; | ||
739 | else | ||
740 | return NULL; | ||
741 | break; | ||
742 | |||
743 | case 'v': /* volume */ | ||
744 | *flags |= WPS_REFRESH_DYNAMIC; | ||
745 | snprintf(buf, buf_size, "%d%%", global_settings.volume); | ||
746 | *intval = global_settings.volume / 10 + 1; | ||
747 | return buf; | ||
748 | |||
749 | } | ||
750 | break; | ||
751 | |||
752 | case 'm': | ||
753 | switch (tag[1]) | ||
754 | { | ||
755 | case 'm': /* playback repeat mode */ | ||
756 | *flags |= WPS_REFRESH_DYNAMIC; | ||
757 | *intval = global_settings.repeat_mode + 1; | ||
758 | snprintf(buf, buf_size, "%d", *intval); | ||
759 | return buf; | ||
760 | |||
761 | /* playback status */ | ||
762 | case 'p': /* play */ | ||
763 | *flags |= WPS_REFRESH_DYNAMIC; | ||
764 | int status = audio_status(); | ||
765 | *intval = 1; | ||
766 | if (status == AUDIO_STATUS_PLAY && \ | ||
767 | !(status & AUDIO_STATUS_PAUSE)) | ||
768 | *intval = 2; | ||
769 | if (audio_status() & AUDIO_STATUS_PAUSE && \ | ||
770 | (! status_get_ffmode())) | ||
771 | *intval = 3; | ||
772 | if (status_get_ffmode() == STATUS_FASTFORWARD) | ||
773 | *intval = 4; | ||
774 | if (status_get_ffmode() == STATUS_FASTBACKWARD) | ||
775 | *intval = 5; | ||
776 | snprintf(buf, buf_size, "%d", *intval); | ||
777 | return buf; | ||
778 | |||
779 | #if CONFIG_KEYPAD == IRIVER_H100_PAD | ||
780 | case 'h': /* hold */ | ||
781 | *flags |= WPS_REFRESH_DYNAMIC; | ||
782 | if (button_hold()) | ||
783 | return "h"; | ||
784 | else | ||
785 | return NULL; | ||
786 | case 'r': /* remote hold */ | ||
787 | *flags |= WPS_REFRESH_DYNAMIC; | ||
788 | if (remote_button_hold()) | ||
789 | return "r"; | ||
790 | else | ||
791 | return NULL; | ||
792 | #endif | ||
793 | } | ||
794 | break; | ||
795 | |||
796 | case 'b': /* battery info */ | ||
797 | *flags |= WPS_REFRESH_DYNAMIC; | ||
798 | switch (tag[1]) { | ||
799 | case 'l': /* battery level */ | ||
800 | { | ||
801 | int l = battery_level(); | ||
802 | if (l > -1) | ||
803 | { | ||
804 | snprintf(buf, buf_size, "%d%%", l); | ||
805 | *intval = l / 20 + 1; | ||
806 | } | ||
807 | else | ||
808 | { | ||
809 | *intval = 6; | ||
810 | return "?%"; | ||
811 | } | ||
812 | return buf; | ||
813 | } | ||
814 | |||
815 | case 't': /* estimated battery time */ | ||
816 | { | ||
817 | int t = battery_time(); | ||
818 | if (t >= 0) | ||
819 | snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60); | ||
820 | else | ||
821 | strncpy(buf, "?h ?m", buf_size); | ||
822 | return buf; | ||
823 | } | ||
824 | |||
825 | case 'p': /* External power plugged in? */ | ||
826 | { | ||
827 | if(charger_inserted()) | ||
828 | return "p"; | ||
829 | else | ||
830 | return NULL; | ||
831 | } | ||
832 | } | ||
833 | break; | ||
834 | |||
835 | case 'D': /* Directory path information */ | ||
836 | id3 = nid3; /* next song please! */ | ||
837 | *flags |= WPS_REFRESH_DYNAMIC; | ||
838 | if(!id3) | ||
839 | return NULL; /* no such info (yet) */ | ||
840 | /* fall-through */ | ||
841 | case 'd': /* Directory path information */ | ||
842 | { | ||
843 | int level = tag[1] - '0'; | ||
844 | *flags |= WPS_REFRESH_STATIC; | ||
845 | /* d1 through d9 */ | ||
846 | if ((0 < level) && (9 > level)) | ||
847 | { | ||
848 | return get_dir(buf, buf_size, id3->path, level); | ||
849 | } | ||
850 | } | ||
851 | break; | ||
852 | |||
853 | case 't': /* set sub line time multiplier */ | ||
854 | { | ||
855 | int d = 1; | ||
856 | int time_mult = 0; | ||
857 | bool have_point = false; | ||
858 | bool have_tenth = false; | ||
859 | |||
860 | while (((tag[d] >= '0') && | ||
861 | (tag[d] <= '9')) || | ||
862 | (tag[d] == '.')) | ||
863 | { | ||
864 | if (tag[d] != '.') | ||
865 | { | ||
866 | time_mult = time_mult * 10; | ||
867 | time_mult = time_mult + tag[d] - '0'; | ||
868 | if (have_point) | ||
869 | { | ||
870 | have_tenth = true; | ||
871 | d++; | ||
872 | break; | ||
873 | } | ||
874 | } | ||
875 | else | ||
876 | { | ||
877 | have_point = true; | ||
878 | } | ||
879 | d++; | ||
880 | } | ||
881 | |||
882 | if (have_tenth == false) | ||
883 | time_mult *= 10; | ||
884 | |||
885 | *subline_time_mult = time_mult; | ||
886 | *tag_len = d; | ||
887 | |||
888 | buf[0] = 0; | ||
889 | return buf; | ||
890 | } | ||
891 | break; | ||
892 | case 'r': /* Runtime database Information */ | ||
893 | switch(tag[1]) | ||
894 | { | ||
895 | case 'p': /* Playcount */ | ||
896 | *flags |= WPS_REFRESH_STATIC; | ||
897 | snprintf(buf, buf_size, "%ld", cid3->playcount); | ||
898 | return buf; | ||
899 | case 'r': /* Rating */ | ||
900 | *flags |= WPS_REFRESH_STATIC; | ||
901 | *intval = cid3->rating+1; | ||
902 | snprintf(buf, buf_size, "%d", cid3->rating); | ||
903 | return buf; | ||
904 | } | ||
905 | break; | ||
906 | } | ||
907 | return NULL; | ||
908 | } | ||
909 | |||
910 | /* Skip to the end of the current %? conditional. | ||
911 | * | ||
912 | * fmt - string to skip it. Should point to somewhere after the leading | ||
913 | * "<" char (and before or at the last ">"). | ||
914 | * num - number of |'s to skip, or 0 to skip to the end (the ">"). | ||
915 | * | ||
916 | * Returns the new position in fmt. | ||
917 | */ | ||
918 | static const char* skip_conditional(const char* fmt, int num) | ||
919 | { | ||
920 | int level = 1; | ||
921 | int count = num; | ||
922 | const char *last_alternative = NULL; | ||
923 | |||
924 | while (*fmt) | ||
925 | { | ||
926 | switch (*fmt++) | ||
927 | { | ||
928 | case '%': | ||
929 | break; | ||
930 | |||
931 | case '|': | ||
932 | if(1 == level) { | ||
933 | last_alternative = fmt; | ||
934 | if(num) { | ||
935 | count--; | ||
936 | if(count == 0) | ||
937 | return fmt; | ||
938 | continue; | ||
939 | } | ||
940 | } | ||
941 | continue; | ||
942 | |||
943 | case '>': | ||
944 | if (0 == --level) | ||
945 | { | ||
946 | /* We're just skipping to the end */ | ||
947 | if(num == 0) | ||
948 | return fmt; | ||
949 | |||
950 | /* If we are parsing an enum, we'll return the selected | ||
951 | item. If there weren't enough items in the enum, we'll | ||
952 | return the last one found. */ | ||
953 | if(count && last_alternative) | ||
954 | { | ||
955 | return last_alternative; | ||
956 | } | ||
957 | return fmt - 1; | ||
958 | } | ||
959 | continue; | ||
960 | |||
961 | default: | ||
962 | continue; | ||
963 | } | ||
964 | |||
965 | switch (*fmt++) | ||
966 | { | ||
967 | case 0: | ||
968 | case '%': | ||
969 | case '|': | ||
970 | case '<': | ||
971 | case '>': | ||
972 | break; | ||
973 | |||
974 | case '?': | ||
975 | while (*fmt && ('<' != *fmt)) | ||
976 | fmt++; | ||
977 | |||
978 | if ('<' == *fmt) | ||
979 | fmt++; | ||
980 | |||
981 | level++; | ||
982 | break; | ||
983 | |||
984 | default: | ||
985 | break; | ||
986 | } | ||
987 | } | ||
988 | |||
989 | return fmt; | ||
990 | } | ||
991 | |||
992 | /* Generate the display based on id3 information and format string. | ||
993 | * | ||
994 | * buf - char buffer to write the display to. | ||
995 | * buf_size - the size of buffer. | ||
996 | * id3 - the ID3 data to format with. | ||
997 | * nid3 - the ID3 data of the next song (might by NULL) | ||
998 | * fmt - format description. | ||
999 | * flags - returns the type of the line. See constants i wps-display.h | ||
1000 | */ | ||
1001 | static void format_display(char* buf, | ||
1002 | int buf_size, | ||
1003 | struct mp3entry* id3, | ||
1004 | struct mp3entry* nid3, /* next song's id3 */ | ||
1005 | const char* fmt, | ||
1006 | struct align_pos* align, | ||
1007 | unsigned short* subline_time_mult, | ||
1008 | unsigned char* flags) | ||
1009 | { | ||
1010 | char temp_buf[128]; | ||
1011 | char* buf_start = buf; | ||
1012 | char* buf_end = buf + buf_size - 1; /* Leave room for end null */ | ||
1013 | char* value = NULL; | ||
1014 | int level = 0; | ||
1015 | unsigned char tag_length; | ||
1016 | int intval; | ||
1017 | int cur_align; | ||
1018 | char* cur_align_start; | ||
1019 | #ifdef HAVE_LCD_BITMAP | ||
1020 | int n; | ||
1021 | #endif | ||
1022 | |||
1023 | cur_align_start = buf; | ||
1024 | cur_align = WPS_ALIGN_LEFT; | ||
1025 | *subline_time_mult = DEFAULT_SUBLINE_TIME_MULTIPLIER; | ||
1026 | |||
1027 | align->left = 0; | ||
1028 | align->center = 0; | ||
1029 | align->right = 0; | ||
1030 | |||
1031 | while (fmt && *fmt && buf < buf_end) | ||
1032 | { | ||
1033 | switch (*fmt) | ||
1034 | { | ||
1035 | case '%': | ||
1036 | ++fmt; | ||
1037 | break; | ||
1038 | |||
1039 | case '|': | ||
1040 | case '>': | ||
1041 | if (level > 0) | ||
1042 | { | ||
1043 | fmt = skip_conditional(fmt, 0); | ||
1044 | level--; | ||
1045 | continue; | ||
1046 | } | ||
1047 | /* Else fall through */ | ||
1048 | |||
1049 | default: | ||
1050 | *buf++ = *fmt++; | ||
1051 | continue; | ||
1052 | } | ||
1053 | |||
1054 | switch (*fmt) | ||
1055 | { | ||
1056 | case 0: | ||
1057 | *buf++ = '%'; | ||
1058 | break; | ||
1059 | case 'a': | ||
1060 | ++fmt; | ||
1061 | /* remember where the current aligned text started */ | ||
1062 | switch (cur_align) | ||
1063 | { | ||
1064 | case WPS_ALIGN_LEFT: | ||
1065 | align->left = cur_align_start; | ||
1066 | break; | ||
1067 | |||
1068 | case WPS_ALIGN_CENTER: | ||
1069 | align->center = cur_align_start; | ||
1070 | break; | ||
1071 | |||
1072 | case WPS_ALIGN_RIGHT: | ||
1073 | align->right = cur_align_start; | ||
1074 | break; | ||
1075 | } | ||
1076 | /* start a new alignment */ | ||
1077 | switch (*fmt) | ||
1078 | { | ||
1079 | case 'l': | ||
1080 | cur_align = WPS_ALIGN_LEFT; | ||
1081 | break; | ||
1082 | case 'c': | ||
1083 | cur_align = WPS_ALIGN_CENTER; | ||
1084 | break; | ||
1085 | case 'r': | ||
1086 | cur_align = WPS_ALIGN_RIGHT; | ||
1087 | break; | ||
1088 | } | ||
1089 | *buf++=0; | ||
1090 | cur_align_start = buf; | ||
1091 | ++fmt; | ||
1092 | break; | ||
1093 | case 's': | ||
1094 | *flags |= WPS_REFRESH_SCROLL; | ||
1095 | ++fmt; | ||
1096 | break; | ||
1097 | |||
1098 | case 'x': /* image support */ | ||
1099 | #ifdef HAVE_LCD_BITMAP | ||
1100 | /* skip preload or regular image tag */ | ||
1101 | if ('l' == *(fmt+1) || '|' == *(fmt+1)) | ||
1102 | { | ||
1103 | while (*fmt && *fmt != '\n') | ||
1104 | fmt++; | ||
1105 | } | ||
1106 | else if ('d' == *(fmt+1)) | ||
1107 | { | ||
1108 | fmt+=2; | ||
1109 | |||
1110 | /* get the image ID */ | ||
1111 | n = *fmt; | ||
1112 | if(n >= 'a' && n <= 'z') | ||
1113 | n -= 'a'; | ||
1114 | if(n >= 'A' && n <= 'Z') | ||
1115 | n = n - 'A' + 26; | ||
1116 | |||
1117 | if (n >= 0 && n < MAX_IMAGES && img[n].loaded) { | ||
1118 | img[n].display = true; | ||
1119 | } | ||
1120 | } | ||
1121 | #endif | ||
1122 | fmt++; | ||
1123 | break; | ||
1124 | |||
1125 | |||
1126 | case '%': | ||
1127 | case '|': | ||
1128 | case '<': | ||
1129 | case '>': | ||
1130 | case ';': | ||
1131 | *buf++ = *fmt++; | ||
1132 | break; | ||
1133 | |||
1134 | case '?': | ||
1135 | fmt++; | ||
1136 | value = get_tag(id3, nid3, fmt, temp_buf, sizeof(temp_buf), | ||
1137 | &tag_length, subline_time_mult, flags, | ||
1138 | &intval); | ||
1139 | |||
1140 | while (*fmt && ('<' != *fmt)) | ||
1141 | fmt++; | ||
1142 | |||
1143 | if ('<' == *fmt) | ||
1144 | fmt++; | ||
1145 | |||
1146 | /* No value, so skip to else part, using a sufficiently high | ||
1147 | value to "hit" the last part of the conditional */ | ||
1148 | if ((!value) || (!strlen(value))) | ||
1149 | fmt = skip_conditional(fmt, 1000); | ||
1150 | else | ||
1151 | if(intval > 1) /* enum */ | ||
1152 | fmt = skip_conditional(fmt, intval - 1); | ||
1153 | |||
1154 | level++; | ||
1155 | break; | ||
1156 | |||
1157 | default: | ||
1158 | value = get_tag(id3, nid3, fmt, temp_buf, sizeof(temp_buf), | ||
1159 | &tag_length, subline_time_mult, flags, | ||
1160 | &intval); | ||
1161 | fmt += tag_length; | ||
1162 | |||
1163 | if (value) | ||
1164 | { | ||
1165 | while (*value && (buf < buf_end)) | ||
1166 | *buf++ = *value++; | ||
1167 | } | ||
1168 | } | ||
1169 | } | ||
1170 | |||
1171 | /* remember where the current aligned text started */ | ||
1172 | switch (cur_align) | ||
1173 | { | ||
1174 | case WPS_ALIGN_LEFT: | ||
1175 | align->left = cur_align_start; | ||
1176 | break; | ||
1177 | |||
1178 | case WPS_ALIGN_CENTER: | ||
1179 | align->center = cur_align_start; | ||
1180 | break; | ||
1181 | |||
1182 | case WPS_ALIGN_RIGHT: | ||
1183 | align->right = cur_align_start; | ||
1184 | break; | ||
1185 | } | ||
1186 | |||
1187 | *buf = 0; | ||
1188 | |||
1189 | /* if resulting line is an empty line, set the subline time to 0 */ | ||
1190 | if (buf - buf_start == 0) | ||
1191 | *subline_time_mult = 0; | ||
1192 | |||
1193 | /* If no flags have been set, the line didn't contain any format codes. | ||
1194 | We still want to refresh it. */ | ||
1195 | if(*flags == 0) | ||
1196 | *flags = WPS_REFRESH_STATIC; | ||
1197 | } | ||
1198 | |||
1199 | bool wps_refresh(struct mp3entry* id3, | ||
1200 | struct mp3entry* nid3, | ||
1201 | int ffwd_offset, | ||
1202 | unsigned char refresh_mode) | ||
1203 | { | ||
1204 | char buf[MAX_PATH]; | ||
1205 | unsigned char flags; | ||
1206 | int i; | ||
1207 | bool update_line; | ||
1208 | bool only_one_subline; | ||
1209 | bool new_subline_refresh; | ||
1210 | int search; | ||
1211 | int search_start; | ||
1212 | #ifdef HAVE_LCD_BITMAP | ||
1213 | int h = font_get(FONT_UI)->height; | ||
1214 | int offset = global_settings.statusbar ? STATUSBAR_HEIGHT : 0; | ||
1215 | /* to find out wether the peak meter is enabled we | ||
1216 | assume it wasn't until we find a line that contains | ||
1217 | the peak meter. We can't use peak_meter_enabled itself | ||
1218 | because that would mean to turn off the meter thread | ||
1219 | temporarily. (That shouldn't matter unless yield | ||
1220 | or sleep is called but who knows...) | ||
1221 | */ | ||
1222 | bool enable_pm = false; | ||
1223 | |||
1224 | /* Set images to not to be displayed */ | ||
1225 | for (i = 0; i < MAX_IMAGES; i++) { | ||
1226 | img[i].display = false; | ||
1227 | } | ||
1228 | #endif | ||
1229 | |||
1230 | /* reset to first subline if refresh all flag is set */ | ||
1231 | if (refresh_mode == WPS_REFRESH_ALL) | ||
1232 | { | ||
1233 | for (i=0; i<MAX_LINES; i++) | ||
1234 | { | ||
1235 | curr_subline[i] = SUBLINE_RESET; | ||
1236 | } | ||
1237 | } | ||
1238 | |||
1239 | #ifdef HAVE_LCD_CHARCELLS | ||
1240 | for (i=0; i<8; i++) { | ||
1241 | if (wps_progress_pat[i]==0) | ||
1242 | wps_progress_pat[i]=lcd_get_locked_pattern(); | ||
1243 | } | ||
1244 | #endif | ||
1245 | |||
1246 | if (!id3) | ||
1247 | { | ||
1248 | lcd_stop_scroll(); | ||
1249 | return false; | ||
1250 | } | ||
1251 | |||
1252 | ff_rewind_count = ffwd_offset; | ||
1253 | |||
1254 | for (i = 0; i < MAX_LINES; i++) | ||
1255 | { | ||
1256 | new_subline_refresh = false; | ||
1257 | only_one_subline = false; | ||
1258 | |||
1259 | /* if time to advance to next sub-line */ | ||
1260 | if (TIME_AFTER(current_tick, subline_expire_time[i] - 1) || | ||
1261 | (curr_subline[i] == SUBLINE_RESET)) | ||
1262 | { | ||
1263 | /* search all sublines until the next subline with time > 0 | ||
1264 | is found or we get back to the subline we started with */ | ||
1265 | if (curr_subline[i] == SUBLINE_RESET) | ||
1266 | search_start = 0; | ||
1267 | else | ||
1268 | search_start = curr_subline[i]; | ||
1269 | for (search=0; search<MAX_SUBLINES; search++) | ||
1270 | { | ||
1271 | curr_subline[i]++; | ||
1272 | |||
1273 | /* wrap around if beyond last defined subline or MAX_SUBLINES */ | ||
1274 | if ((!format_lines[i][curr_subline[i]]) || | ||
1275 | (curr_subline[i] == MAX_SUBLINES)) | ||
1276 | { | ||
1277 | if (curr_subline[i] == 1) | ||
1278 | only_one_subline = true; | ||
1279 | curr_subline[i] = 0; | ||
1280 | } | ||
1281 | |||
1282 | /* if back where we started after search or | ||
1283 | only one subline is defined on the line */ | ||
1284 | if (((search > 0) && (curr_subline[i] == search_start)) || | ||
1285 | only_one_subline) | ||
1286 | { | ||
1287 | /* no other subline with a time > 0 exists */ | ||
1288 | subline_expire_time[i] = current_tick + 100 * HZ; | ||
1289 | break; | ||
1290 | } | ||
1291 | else | ||
1292 | { | ||
1293 | /* get initial time multiplier and | ||
1294 | line type flags for this subline */ | ||
1295 | format_display(buf, sizeof(buf), id3, nid3, | ||
1296 | format_lines[i][curr_subline[i]], | ||
1297 | &format_align[i][curr_subline[i]], | ||
1298 | &time_mult[i][curr_subline[i]], | ||
1299 | &line_type[i][curr_subline[i]]); | ||
1300 | |||
1301 | /* only use this subline if subline time > 0 */ | ||
1302 | if (time_mult[i][curr_subline[i]] > 0) | ||
1303 | { | ||
1304 | new_subline_refresh = true; | ||
1305 | subline_expire_time[i] = current_tick + | ||
1306 | BASE_SUBLINE_TIME * time_mult[i][curr_subline[i]]; | ||
1307 | break; | ||
1308 | } | ||
1309 | } | ||
1310 | } | ||
1311 | |||
1312 | } | ||
1313 | |||
1314 | update_line = false; | ||
1315 | |||
1316 | if ( !format_lines[i][curr_subline[i]] ) | ||
1317 | break; | ||
1318 | |||
1319 | if ((line_type[i][curr_subline[i]] & refresh_mode) || | ||
1320 | (refresh_mode == WPS_REFRESH_ALL) || | ||
1321 | new_subline_refresh) | ||
1322 | { | ||
1323 | flags = 0; | ||
1324 | #ifdef HAVE_LCD_BITMAP | ||
1325 | int left_width, left_xpos; | ||
1326 | int center_width, center_xpos; | ||
1327 | int right_width, right_xpos; | ||
1328 | int space_width; | ||
1329 | int string_height; | ||
1330 | int ypos; | ||
1331 | #endif | ||
1332 | |||
1333 | format_display(buf, sizeof(buf), id3, nid3, | ||
1334 | format_lines[i][curr_subline[i]], | ||
1335 | &format_align[i][curr_subline[i]], | ||
1336 | &time_mult[i][curr_subline[i]], | ||
1337 | &flags); | ||
1338 | line_type[i][curr_subline[i]] = flags; | ||
1339 | |||
1340 | #ifdef HAVE_LCD_BITMAP | ||
1341 | /* progress */ | ||
1342 | if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) | ||
1343 | { | ||
1344 | #define PROGRESS_BAR_HEIGHT 6 /* this should probably be defined elsewhere; config-*.h perhaps? */ | ||
1345 | int sby = i*h + offset + (h > 7 ? (h - 6) / 2 : 1); | ||
1346 | scrollbar(0, sby, LCD_WIDTH, PROGRESS_BAR_HEIGHT, | ||
1347 | id3->length?id3->length:1, 0, | ||
1348 | id3->length?id3->elapsed + ff_rewind_count:0, | ||
1349 | HORIZONTAL); | ||
1350 | #ifdef AB_REPEAT_ENABLE | ||
1351 | if ( ab_repeat_mode_enabled() ) | ||
1352 | ab_draw_markers(id3->length, 0, sby, LCD_WIDTH, PROGRESS_BAR_HEIGHT); | ||
1353 | #endif | ||
1354 | update_line = true; | ||
1355 | } | ||
1356 | if (flags & refresh_mode & WPS_REFRESH_PEAK_METER) { | ||
1357 | /* peak meter */ | ||
1358 | int peak_meter_y; | ||
1359 | |||
1360 | update_line = true; | ||
1361 | peak_meter_y = i * h + offset; | ||
1362 | |||
1363 | /* The user might decide to have the peak meter in the last | ||
1364 | line so that it is only displayed if no status bar is | ||
1365 | visible. If so we neither want do draw nor enable the | ||
1366 | peak meter. */ | ||
1367 | if (peak_meter_y + h <= LCD_HEIGHT) { | ||
1368 | /* found a line with a peak meter -> remember that we must | ||
1369 | enable it later */ | ||
1370 | enable_pm = true; | ||
1371 | peak_meter_draw(0, peak_meter_y, LCD_WIDTH, | ||
1372 | MIN(h, LCD_HEIGHT - peak_meter_y)); | ||
1373 | } | ||
1374 | } | ||
1375 | #else | ||
1376 | /* progress */ | ||
1377 | if (flags & refresh_mode & WPS_REFRESH_PLAYER_PROGRESS) { | ||
1378 | if (full_line_progressbar) | ||
1379 | draw_player_fullbar(buf, sizeof(buf), | ||
1380 | id3, ff_rewind_count); | ||
1381 | else | ||
1382 | draw_player_progress(id3, ff_rewind_count); | ||
1383 | } | ||
1384 | #endif | ||
1385 | #ifdef HAVE_LCD_BITMAP | ||
1386 | /* calculate different string sizes and positions */ | ||
1387 | lcd_getstringsize(" ", &space_width, &string_height); | ||
1388 | if (format_align[i][curr_subline[i]].left != 0) { | ||
1389 | lcd_getstringsize(format_align[i][curr_subline[i]].left, | ||
1390 | &left_width, &string_height); | ||
1391 | } | ||
1392 | else { | ||
1393 | left_width = 0; | ||
1394 | } | ||
1395 | left_xpos = 0; | ||
1396 | |||
1397 | if (format_align[i][curr_subline[i]].center != 0) { | ||
1398 | lcd_getstringsize(format_align[i][curr_subline[i]].center, | ||
1399 | ¢er_width, &string_height); | ||
1400 | } | ||
1401 | else { | ||
1402 | center_width = 0; | ||
1403 | } | ||
1404 | center_xpos=(LCD_WIDTH - center_width) / 2; | ||
1405 | |||
1406 | if (format_align[i][curr_subline[i]].right != 0) { | ||
1407 | lcd_getstringsize(format_align[i][curr_subline[i]].right, | ||
1408 | &right_width, &string_height); | ||
1409 | } | ||
1410 | else { | ||
1411 | right_width = 0; | ||
1412 | } | ||
1413 | right_xpos = (LCD_WIDTH - right_width); | ||
1414 | |||
1415 | /* Checks for overlapping strings. | ||
1416 | If needed the overlapping strings will be merged, separated by a | ||
1417 | space */ | ||
1418 | |||
1419 | /* CASE 1: left and centered string overlap */ | ||
1420 | /* there is a left string, need to merge left and center */ | ||
1421 | if ((left_width != 0 && center_width != 0) && | ||
1422 | (left_xpos + left_width + space_width > center_xpos)) { | ||
1423 | /* replace the former separator '\0' of left and | ||
1424 | center string with a space */ | ||
1425 | *(--format_align[i][curr_subline[i]].center) = ' '; | ||
1426 | /* calculate the new width and position of the merged string */ | ||
1427 | left_width = left_width + space_width + center_width; | ||
1428 | left_xpos = 0; | ||
1429 | /* there is no centered string anymore */ | ||
1430 | center_width = 0; | ||
1431 | } | ||
1432 | /* there is no left string, move center to left */ | ||
1433 | if ((left_width == 0 && center_width != 0) && | ||
1434 | (left_xpos + left_width > center_xpos)) { | ||
1435 | /* move the center string to the left string */ | ||
1436 | format_align[i][curr_subline[i]].left = format_align[i][curr_subline[i]].center; | ||
1437 | /* calculate the new width and position of the string */ | ||
1438 | left_width = center_width; | ||
1439 | left_xpos = 0; | ||
1440 | /* there is no centered string anymore */ | ||
1441 | center_width = 0; | ||
1442 | } | ||
1443 | |||
1444 | /* CASE 2: centered and right string overlap */ | ||
1445 | /* there is a right string, need to merge center and right */ | ||
1446 | if ((center_width != 0 && right_width != 0) && | ||
1447 | (center_xpos + center_width + space_width > right_xpos)) { | ||
1448 | /* replace the former separator '\0' of center and | ||
1449 | right string with a space */ | ||
1450 | *(--format_align[i][curr_subline[i]].right) = ' '; | ||
1451 | /* move the center string to the right after merge */ | ||
1452 | format_align[i][curr_subline[i]].right = format_align[i][curr_subline[i]].center; | ||
1453 | /* calculate the new width and position of the merged string */ | ||
1454 | right_width = center_width + space_width + right_width; | ||
1455 | right_xpos = (LCD_WIDTH - right_width); | ||
1456 | /* there is no centered string anymore */ | ||
1457 | center_width = 0; | ||
1458 | } | ||
1459 | /* there is no right string, move center to right */ | ||
1460 | if ((center_width != 0 && right_width == 0) && | ||
1461 | (center_xpos + center_width > right_xpos)) { | ||
1462 | /* move the center string to the right string */ | ||
1463 | format_align[i][curr_subline[i]].right = format_align[i][curr_subline[i]].center; | ||
1464 | /* calculate the new width and position of the string */ | ||
1465 | right_width = center_width; | ||
1466 | right_xpos = (LCD_WIDTH - right_width); | ||
1467 | /* there is no centered string anymore */ | ||
1468 | center_width = 0; | ||
1469 | } | ||
1470 | |||
1471 | /* CASE 3: left and right overlap | ||
1472 | There is no center string anymore, either there never | ||
1473 | was one or it has been merged in case 1 or 2 */ | ||
1474 | /* there is a left string, need to merge left and right */ | ||
1475 | if ((left_width != 0 && center_width == 0 && right_width != 0) && | ||
1476 | (left_xpos + left_width + space_width > right_xpos)) { | ||
1477 | /* replace the former separator '\0' of left and | ||
1478 | right string with a space */ | ||
1479 | *(--format_align[i][curr_subline[i]].right) = ' '; | ||
1480 | /* calculate the new width and position of the string */ | ||
1481 | left_width = left_width + space_width + right_width; | ||
1482 | left_xpos = 0; | ||
1483 | /* there is no right string anymore */ | ||
1484 | right_width = 0; | ||
1485 | } | ||
1486 | /* there is no left string, move right to left */ | ||
1487 | if ((left_width == 0 && center_width == 0 && right_width != 0) && | ||
1488 | (left_xpos + left_width > right_xpos)) { | ||
1489 | /* move the right string to the left string */ | ||
1490 | format_align[i][curr_subline[i]].left = format_align[i][curr_subline[i]].right; | ||
1491 | /* calculate the new width and position of the string */ | ||
1492 | left_width = right_width; | ||
1493 | left_xpos = 0; | ||
1494 | /* there is no right string anymore */ | ||
1495 | right_width = 0; | ||
1496 | } | ||
1497 | |||
1498 | #endif | ||
1499 | |||
1500 | if (flags & WPS_REFRESH_SCROLL) { | ||
1501 | |||
1502 | /* scroll line */ | ||
1503 | if ((refresh_mode & WPS_REFRESH_SCROLL) || | ||
1504 | new_subline_refresh) { | ||
1505 | #ifdef HAVE_LCD_BITMAP | ||
1506 | ypos = (i*string_height)+lcd_getymargin(); | ||
1507 | update_line = true; | ||
1508 | |||
1509 | if (left_width>LCD_WIDTH) { | ||
1510 | lcd_puts_scroll(0, i, format_align[i][curr_subline[i]].left); | ||
1511 | } else { | ||
1512 | /* clear the line first */ | ||
1513 | lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); | ||
1514 | lcd_fillrect(0, ypos, LCD_WIDTH, string_height); | ||
1515 | lcd_set_drawmode(DRMODE_SOLID); | ||
1516 | |||
1517 | /* Nasty hack: we output an empty scrolling string, | ||
1518 | which will reset the scroller for that line */ | ||
1519 | lcd_puts_scroll(0, i, ""); | ||
1520 | |||
1521 | /* print aligned strings */ | ||
1522 | if (left_width != 0) | ||
1523 | { | ||
1524 | lcd_putsxy(left_xpos, ypos, format_align[i][curr_subline[i]].left); | ||
1525 | } | ||
1526 | if (center_width != 0) | ||
1527 | { | ||
1528 | lcd_putsxy(center_xpos, ypos, format_align[i][curr_subline[i]].center); | ||
1529 | } | ||
1530 | if (right_width != 0) | ||
1531 | { | ||
1532 | lcd_putsxy(right_xpos, ypos, format_align[i][curr_subline[i]].right); | ||
1533 | } | ||
1534 | } | ||
1535 | #else | ||
1536 | lcd_puts_scroll(0, i, buf); | ||
1537 | update_line = true; | ||
1538 | #endif | ||
1539 | } | ||
1540 | } | ||
1541 | else if (flags & (WPS_REFRESH_DYNAMIC | WPS_REFRESH_STATIC)) | ||
1542 | { | ||
1543 | /* dynamic / static line */ | ||
1544 | if ((refresh_mode & (WPS_REFRESH_DYNAMIC|WPS_REFRESH_STATIC)) || | ||
1545 | new_subline_refresh) | ||
1546 | { | ||
1547 | #ifdef HAVE_LCD_BITMAP | ||
1548 | ypos = (i*string_height)+lcd_getymargin(); | ||
1549 | update_line = true; | ||
1550 | |||
1551 | /* clear the line first */ | ||
1552 | lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); | ||
1553 | lcd_fillrect(0, ypos, LCD_WIDTH, string_height); | ||
1554 | lcd_set_drawmode(DRMODE_SOLID); | ||
1555 | |||
1556 | /* Nasty hack: we output an empty scrolling string, | ||
1557 | which will reset the scroller for that line */ | ||
1558 | lcd_puts_scroll(0, i, ""); | ||
1559 | |||
1560 | /* print aligned strings */ | ||
1561 | if (left_width != 0) | ||
1562 | { | ||
1563 | lcd_putsxy(left_xpos, ypos, format_align[i][curr_subline[i]].left); | ||
1564 | } | ||
1565 | if (center_width != 0) | ||
1566 | { | ||
1567 | lcd_putsxy(center_xpos, ypos, format_align[i][curr_subline[i]].center); | ||
1568 | } | ||
1569 | if (right_width != 0) | ||
1570 | { | ||
1571 | lcd_putsxy(right_xpos, ypos, format_align[i][curr_subline[i]].right); | ||
1572 | } | ||
1573 | #else | ||
1574 | update_line = true; | ||
1575 | lcd_puts(0, i, buf); | ||
1576 | #endif | ||
1577 | } | ||
1578 | } | ||
1579 | } | ||
1580 | #ifdef HAVE_LCD_BITMAP | ||
1581 | if (update_line) { | ||
1582 | lcd_update_rect(0, i*h + offset, LCD_WIDTH, h); | ||
1583 | } | ||
1584 | #endif | ||
1585 | } | ||
1586 | |||
1587 | #ifdef HAVE_LCD_BITMAP | ||
1588 | /* Display all images */ | ||
1589 | for (i = 0; i < MAX_IMAGES; i++) { | ||
1590 | if(img[i].always_display) | ||
1591 | img[i].display = img[i].always_display; | ||
1592 | } | ||
1593 | wps_display_images(); | ||
1594 | |||
1595 | /* Now we know wether the peak meter is used. | ||
1596 | So we can enable / disable the peak meter thread */ | ||
1597 | peak_meter_enabled = enable_pm; | ||
1598 | #endif | ||
1599 | |||
1600 | #if defined(CONFIG_BACKLIGHT) && !defined(SIMULATOR) | ||
1601 | if (global_settings.caption_backlight && id3) { | ||
1602 | /* turn on backlight n seconds before track ends, and turn it off n | ||
1603 | seconds into the new track. n == backlight_timeout, or 5s */ | ||
1604 | int n = | ||
1605 | backlight_timeout_value[global_settings.backlight_timeout] * 1000; | ||
1606 | |||
1607 | if ( n < 1000 ) | ||
1608 | n = 5000; /* use 5s if backlight is always on or off */ | ||
1609 | |||
1610 | if ((id3->elapsed < 1000) || | ||
1611 | ((id3->length - id3->elapsed) < (unsigned)n)) | ||
1612 | backlight_on(); | ||
1613 | } | ||
1614 | #endif | ||
1615 | return true; | ||
1616 | } | ||
1617 | |||
1618 | bool wps_display(struct mp3entry* id3, | ||
1619 | struct mp3entry* nid3) | ||
1620 | { | ||
1621 | if (!id3 && !(audio_status() & AUDIO_STATUS_PLAY)) | ||
1622 | { | ||
1623 | global_settings.resume_index = -1; | ||
1624 | #ifdef HAVE_LCD_CHARCELLS | ||
1625 | gui_syncsplash(HZ, true, str(LANG_END_PLAYLIST_PLAYER)); | ||
1626 | #else | ||
1627 | status_draw(true); | ||
1628 | gui_syncsplash(HZ, true, str(LANG_END_PLAYLIST_RECORDER)); | ||
1629 | #endif | ||
1630 | return true; | ||
1631 | } | ||
1632 | else | ||
1633 | { | ||
1634 | lcd_clear_display(); | ||
1635 | |||
1636 | if (!wps_loaded) { | ||
1637 | if ( !format_buffer[0] ) { | ||
1638 | #ifdef HAVE_LCD_BITMAP | ||
1639 | wps_format("%s%?it<%?in<%in. |>%it|%fn>\n" | ||
1640 | "%s%?ia<%ia|%?d2<%d2|(root)>>\n" | ||
1641 | "%s%?id<%id|%?d1<%d1|(root)>> %?iy<(%iy)|>\n" | ||
1642 | "\n" | ||
1643 | "%al%pc/%pt%ar[%pp:%pe]\n" | ||
1644 | "%fbkBit %?fv<avg|> %?iv<(id3v%iv)|(no id3)>\n" | ||
1645 | "%pb\n" | ||
1646 | "%pm\n", NULL, 0); | ||
1647 | #else | ||
1648 | wps_format("%s%pp/%pe: %?it<%it|%fn> - %?ia<%ia|%d2> - %?id<%id|%d1>\n" | ||
1649 | "%pc%?ps<*|/>%pt\n", NULL, 0); | ||
1650 | #endif | ||
1651 | } | ||
1652 | } | ||
1653 | } | ||
1654 | yield(); | ||
1655 | wps_refresh(id3, nid3, 0, WPS_REFRESH_ALL); | ||
1656 | status_draw(true); | ||
1657 | #ifdef HAVE_LCD_BITMAP | ||
1658 | wps_display_images(); | ||
1659 | #endif | ||
1660 | lcd_update(); | ||
1661 | return false; | ||
1662 | } | ||
1663 | |||
1664 | #ifdef HAVE_LCD_CHARCELLS | ||
1665 | static bool draw_player_progress(const struct mp3entry* id3, | ||
1666 | int ff_rewwind_count) | ||
1667 | { | ||
1668 | char player_progressbar[7]; | ||
1669 | char binline[36]; | ||
1670 | int songpos = 0; | ||
1671 | int i,j; | ||
1672 | |||
1673 | if (!id3) | ||
1674 | return false; | ||
1675 | |||
1676 | memset(binline, 1, sizeof binline); | ||
1677 | memset(player_progressbar, 1, sizeof player_progressbar); | ||
1678 | |||
1679 | if(id3->elapsed >= id3->length) | ||
1680 | songpos = 0; | ||
1681 | else | ||
1682 | { | ||
1683 | if(wps_time_countup == false) | ||
1684 | songpos = ((id3->elapsed - ff_rewwind_count) * 36) / id3->length; | ||
1685 | else | ||
1686 | songpos = ((id3->elapsed + ff_rewwind_count) * 36) / id3->length; | ||
1687 | } | ||
1688 | for (i=0; i < songpos; i++) | ||
1689 | binline[i] = 0; | ||
1690 | |||
1691 | for (i=0; i<=6; i++) { | ||
1692 | for (j=0;j<5;j++) { | ||
1693 | player_progressbar[i] <<= 1; | ||
1694 | player_progressbar[i] += binline[i*5+j]; | ||
1695 | } | ||
1696 | } | ||
1697 | lcd_define_pattern(wps_progress_pat[0], player_progressbar); | ||
1698 | return true; | ||
1699 | } | ||
1700 | |||
1701 | static void draw_player_fullbar(char* buf, int buf_size, | ||
1702 | const struct mp3entry* id3, | ||
1703 | int ff_rewwind_count) | ||
1704 | { | ||
1705 | int i,j,lcd_char_pos; | ||
1706 | |||
1707 | char player_progressbar[7]; | ||
1708 | char binline[36]; | ||
1709 | static const char numbers[12][4][3]={ | ||
1710 | {{1,1,1},{1,0,1},{1,0,1},{1,1,1}},/*0*/ | ||
1711 | {{0,1,0},{1,1,0},{0,1,0},{0,1,0}},/*1*/ | ||
1712 | {{1,1,1},{0,0,1},{0,1,0},{1,1,1}},/*2*/ | ||
1713 | {{1,1,1},{0,0,1},{0,1,1},{1,1,1}},/*3*/ | ||
1714 | {{1,0,0},{1,1,0},{1,1,1},{0,1,0}},/*4*/ | ||
1715 | {{1,1,1},{1,1,0},{0,0,1},{1,1,0}},/*5*/ | ||
1716 | {{1,1,1},{1,0,0},{1,1,1},{1,1,1}},/*6*/ | ||
1717 | {{1,1,1},{0,0,1},{0,1,0},{1,0,0}},/*7*/ | ||
1718 | {{1,1,1},{1,1,1},{1,0,1},{1,1,1}},/*8*/ | ||
1719 | {{1,1,1},{1,1,1},{0,0,1},{1,1,1}},/*9*/ | ||
1720 | {{0,0,0},{0,1,0},{0,0,0},{0,1,0}},/*:*/ | ||
1721 | {{0,0,0},{0,0,0},{0,0,0},{0,0,0}} /*<blank>*/ | ||
1722 | }; | ||
1723 | |||
1724 | int songpos = 0; | ||
1725 | int digits[6]; | ||
1726 | int time; | ||
1727 | char timestr[7]; | ||
1728 | |||
1729 | for (i=0; i < buf_size; i++) | ||
1730 | buf[i] = ' '; | ||
1731 | |||
1732 | if(id3->elapsed >= id3->length) | ||
1733 | songpos = 55; | ||
1734 | else { | ||
1735 | if(wps_time_countup == false) | ||
1736 | songpos = ((id3->elapsed - ff_rewwind_count) * 55) / id3->length; | ||
1737 | else | ||
1738 | songpos = ((id3->elapsed + ff_rewwind_count) * 55) / id3->length; | ||
1739 | } | ||
1740 | |||
1741 | time=(id3->elapsed + ff_rewind_count); | ||
1742 | |||
1743 | memset(timestr, 0, sizeof(timestr)); | ||
1744 | wps_format_time(timestr, sizeof(timestr), time); | ||
1745 | for(lcd_char_pos=0; lcd_char_pos<6; lcd_char_pos++) { | ||
1746 | digits[lcd_char_pos] = map_fullbar_char(timestr[lcd_char_pos]); | ||
1747 | } | ||
1748 | |||
1749 | /* build the progressbar-icons */ | ||
1750 | for (lcd_char_pos=0; lcd_char_pos<6; lcd_char_pos++) { | ||
1751 | memset(binline, 0, sizeof binline); | ||
1752 | memset(player_progressbar, 0, sizeof player_progressbar); | ||
1753 | |||
1754 | /* make the character (progressbar & digit)*/ | ||
1755 | for (i=0; i<7; i++) { | ||
1756 | for (j=0;j<5;j++) { | ||
1757 | /* make the progressbar */ | ||
1758 | if (lcd_char_pos==(songpos/5)) { | ||
1759 | /* partial */ | ||
1760 | if ((j<(songpos%5))&&(i>4)) | ||
1761 | binline[i*5+j] = 1; | ||
1762 | else | ||
1763 | binline[i*5+j] = 0; | ||
1764 | } | ||
1765 | else { | ||
1766 | if (lcd_char_pos<(songpos/5)) { | ||
1767 | /* full character */ | ||
1768 | if (i>4) | ||
1769 | binline[i*5+j] = 1; | ||
1770 | } | ||
1771 | } | ||
1772 | /* insert the digit */ | ||
1773 | if ((j<3)&&(i<4)) { | ||
1774 | if (numbers[digits[lcd_char_pos]][i][j]==1) | ||
1775 | binline[i*5+j] = 1; | ||
1776 | } | ||
1777 | } | ||
1778 | } | ||
1779 | |||
1780 | for (i=0; i<=6; i++) { | ||
1781 | for (j=0;j<5;j++) { | ||
1782 | player_progressbar[i] <<= 1; | ||
1783 | player_progressbar[i] += binline[i*5+j]; | ||
1784 | } | ||
1785 | } | ||
1786 | |||
1787 | lcd_define_pattern(wps_progress_pat[lcd_char_pos+1],player_progressbar); | ||
1788 | buf[lcd_char_pos]=wps_progress_pat[lcd_char_pos+1]; | ||
1789 | |||
1790 | } | ||
1791 | |||
1792 | /* make rest of the progressbar if necessary */ | ||
1793 | if (songpos/5>5) { | ||
1794 | |||
1795 | /* set the characters positions that use the full 5 pixel wide bar */ | ||
1796 | for (lcd_char_pos=6; lcd_char_pos < (songpos/5); lcd_char_pos++) | ||
1797 | buf[lcd_char_pos] = 0x86; /* '_' */ | ||
1798 | |||
1799 | /* build the partial bar character for the tail character position */ | ||
1800 | memset(binline, 0, sizeof binline); | ||
1801 | memset(player_progressbar, 0, sizeof player_progressbar); | ||
1802 | |||
1803 | for (i=5; i<7; i++) { | ||
1804 | for (j=0;j<5;j++) { | ||
1805 | if (j<(songpos%5)) { | ||
1806 | binline[i*5+j] = 1; | ||
1807 | } | ||
1808 | } | ||
1809 | } | ||
1810 | |||
1811 | for (i=0; i<7; i++) { | ||
1812 | for (j=0;j<5;j++) { | ||
1813 | player_progressbar[i] <<= 1; | ||
1814 | player_progressbar[i] += binline[i*5+j]; | ||
1815 | } | ||
1816 | } | ||
1817 | |||
1818 | lcd_define_pattern(wps_progress_pat[7],player_progressbar); | ||
1819 | |||
1820 | buf[songpos/5]=wps_progress_pat[7]; | ||
1821 | } | ||
1822 | } | ||
1823 | |||
1824 | static char map_fullbar_char(char ascii_val) | ||
1825 | { | ||
1826 | if (ascii_val >= '0' && ascii_val <= '9') { | ||
1827 | return(ascii_val - '0'); | ||
1828 | } | ||
1829 | else if (ascii_val == ':') { | ||
1830 | return(10); | ||
1831 | } | ||
1832 | else | ||
1833 | return(11); /* anything besides a number or ':' is mapped to <blank> */ | ||
1834 | } | ||
1835 | |||
1836 | |||
1837 | #endif | ||
1838 | |||
1839 | /* ----------------------------------------------------------------- | ||
1840 | * vim: et sw=4 ts=8 sts=4 tw=78 | ||
1841 | */ | ||