Now fully v1 spec compliant
[kugel-rb.git] / apps / screens.c
blob2db36075fdbd7010094e9f2fa4319bc48d097241
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Björn Stenberg
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include <stdbool.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include "backlight.h"
23 #include "button.h"
24 #include "lcd.h"
25 #include "lang.h"
26 #include "icons.h"
27 #include "font.h"
28 #include "mpeg.h"
29 #include "mp3_playback.h"
30 #include "usb.h"
31 #include "settings.h"
32 #include "status.h"
33 #include "playlist.h"
34 #include "sprintf.h"
35 #include "kernel.h"
36 #include "power.h"
37 #include "system.h"
38 #include "powermgmt.h"
39 #include "adc.h"
40 #include "action.h"
41 #include "talk.h"
42 #include "misc.h"
43 #include "id3.h"
44 #include "screens.h"
45 #include "debug.h"
47 #ifdef HAVE_LCD_BITMAP
48 #define BMPHEIGHT_usb_logo 32
49 #define BMPWIDTH_usb_logo 100
50 static const unsigned char usb_logo[] = {
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08,
54 0x04, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
55 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x81, 0x81, 0x81, 0x81,
56 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
57 0x01, 0x01, 0x01, 0x01, 0xf1, 0x4f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
58 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0,
59 0x00, 0x00, 0xe0, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
60 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
61 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x81, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0,
62 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x1c,
63 0x0c, 0x0e, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f,
64 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00,
65 0x00, 0x00, 0xe0, 0x1f, 0x00, 0xf8, 0x06, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
66 0x02, 0x02, 0x02, 0x82, 0x7e, 0x00, 0xc0, 0x3e, 0x01,
67 0x70, 0x4f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
68 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
69 0x40, 0x40, 0x40, 0x40, 0x40, 0x80, 0x00, 0x07, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f,
70 0x0f, 0x07, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x0f,
71 0x1f, 0x3f, 0x7b, 0xf3, 0xe3, 0xc3, 0x83, 0x83, 0x83, 0x83, 0xe3, 0xe3, 0xe3,
72 0xe3, 0xe3, 0xe3, 0x03, 0x03, 0x03, 0x3f, 0x1f, 0x1f, 0x0f, 0x0f, 0x07, 0x02,
73 0xc0, 0x3e, 0x01, 0xe0, 0x9f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
74 0x80, 0x80, 0xf0, 0x0f, 0x80, 0x78, 0x07, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0c, 0x10, 0x20, 0x40, 0x40, 0x80, 0x80,
78 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
79 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x87, 0x87, 0x87,
80 0x87, 0x87, 0x87, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xf0,
81 0x0f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
82 0x04, 0x04, 0x04, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00,
84 #endif
86 void usb_display_info(void)
88 lcd_clear_display();
90 #ifdef HAVE_LCD_BITMAP
91 lcd_bitmap(usb_logo, 6, 16, BMPWIDTH_usb_logo, BMPHEIGHT_usb_logo, false);
92 status_draw(true);
93 lcd_update();
94 #else
95 lcd_puts(0, 0, "[USB Mode]");
96 status_set_param(false);
97 status_set_audio(false);
98 status_set_usb(true);
99 status_draw(false);
100 #endif
103 void usb_screen(void)
105 #ifdef USB_NONE
106 /* nothing here! */
107 #else
108 #ifndef SIMULATOR
109 backlight_on();
110 usb_acknowledge(SYS_USB_CONNECTED_ACK);
111 usb_display_info();
112 while(usb_wait_for_disconnect_w_tmo(&button_queue, HZ)) {
113 if(usb_inserted()) {
114 status_draw(false);
117 #ifdef HAVE_LCD_CHARCELLS
118 status_set_usb(false);
119 #endif
121 backlight_on();
122 #endif
123 #endif /* USB_NONE */
126 #ifdef HAVE_MMC
127 int mmc_remove_request(void)
129 struct event ev;
131 lcd_clear_display();
132 splash(1, true, str(LANG_REMOVE_MMC));
133 talk_id(LANG_REMOVE_MMC, false);
135 while (1)
137 queue_wait_w_tmo(&button_queue, &ev, HZ/2);
138 switch (ev.id)
140 case SYS_MMC_EXTRACTED:
141 return SYS_MMC_EXTRACTED;
143 case SYS_USB_DISCONNECTED:
144 return SYS_USB_DISCONNECTED;
148 #endif
151 /* some simulator dummies */
152 #ifdef SIMULATOR
153 #define BATTERY_SCALE_FACTOR 7000
154 unsigned short adc_read(int channel)
156 (void)channel;
157 return 100;
159 #endif
162 #ifdef HAVE_LCD_BITMAP
163 void charging_display_info(bool animate)
165 unsigned char charging_logo[36];
166 const int pox_x = (LCD_WIDTH - sizeof(charging_logo)) / 2;
167 const int pox_y = 32;
168 static unsigned phase = 3;
169 unsigned i;
170 char buf[32];
171 (void)buf;
173 #ifdef NEED_ATA_POWER_BATT_MEASURE
174 if (ide_powered()) /* FM and V2 can only measure when ATA power is on */
175 #endif
177 int battery_voltage;
178 int batt_int, batt_frac;
180 battery_voltage = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000;
181 batt_int = battery_voltage / 100;
182 batt_frac = battery_voltage % 100;
184 snprintf(buf, 32, " Batt: %d.%02dV %d%% ", batt_int, batt_frac,
185 battery_level());
186 lcd_puts(0, 7, buf);
189 #ifdef HAVE_CHARGE_CTRL
191 snprintf(buf, 32, "Charge mode:");
192 lcd_puts(0, 2, buf);
194 if (charge_state == 1)
195 snprintf(buf, 32, str(LANG_BATTERY_CHARGE));
196 else if (charge_state == 2)
197 snprintf(buf, 32, str(LANG_BATTERY_TOPOFF_CHARGE));
198 else if (charge_state == 3)
199 snprintf(buf, 32, str(LANG_BATTERY_TRICKLE_CHARGE));
200 else
201 snprintf(buf, 32, "not charging");
203 lcd_puts(0, 3, buf);
204 if (!charger_enabled)
205 animate = false;
206 #endif
209 /* middle part */
210 memset(charging_logo+3, 0x00, 32);
211 charging_logo[0] = 0x3C;
212 charging_logo[1] = 0x24;
213 charging_logo[2] = charging_logo[35] = 0xFF;
215 if (!animate)
216 { /* draw the outline */
217 /* middle part */
218 lcd_bitmap(charging_logo, pox_x, pox_y + 8, sizeof(charging_logo), 8, true);
219 /* upper line */
220 charging_logo[0] = charging_logo[1] = 0x00;
221 memset(charging_logo+2, 0x80, 34);
222 lcd_bitmap(charging_logo, pox_x, pox_y, sizeof(charging_logo), 8, false);
223 /* lower line */
224 memset(charging_logo+2, 0x01, 34);
225 lcd_bitmap(charging_logo, pox_x, pox_y + 16, sizeof(charging_logo), 8, false);
227 else
228 { /* animate the middle part */
229 for (i = 3; i<MIN(sizeof(charging_logo)-1, phase); i++)
231 if ((i-phase) % 8 == 0)
232 { /* draw a "bubble" here */
233 unsigned bitpos;
234 bitpos = (phase + i/8) % 15; /* "bounce" effect */
235 if (bitpos > 7)
236 bitpos = 14 - bitpos;
237 charging_logo[i] = 0x01 << bitpos;
240 lcd_bitmap(charging_logo, pox_x, pox_y + 8, sizeof(charging_logo), 8, true);
241 phase++;
243 lcd_update();
245 #else /* not HAVE_LCD_BITMAP */
246 void charging_display_info(bool animate)
248 /* ToDo for Player */
249 (void)animate;
251 #endif
253 #ifdef HAVE_CHARGING
254 /* blocks while charging, returns on event:
255 1 if charger cable was removed
256 2 if Off/Stop key was pressed
257 3 if On key was pressed
258 4 if USB was connected */
259 int charging_screen(void)
261 int button;
262 int rc = 0;
263 #ifdef BUTTON_OFF
264 const int offbutton = BUTTON_OFF;
265 #else
266 const int offbutton = BUTTON_STOP;
267 #endif
269 ide_power_enable(false); /* power down the disk, else would be spinning */
271 lcd_clear_display();
272 if(global_settings.backlight_on_when_charging)
273 backlight_on();
274 status_draw(true);
276 #ifdef HAVE_LCD_BITMAP
277 charging_display_info(false);
278 #else
279 lcd_puts(0, 1, "[charging]");
280 #endif
284 status_draw(false);
285 charging_display_info(true);
286 button = button_get_w_tmo(HZ/3);
287 #ifdef BUTTON_ON
288 if (button == (BUTTON_ON | BUTTON_REL))
289 #else
290 if (button == (BUTTON_RIGHT | BUTTON_REL))
291 #endif
292 rc = 3;
293 else if (button == offbutton)
294 rc = 2;
295 else
297 if (usb_detect())
298 rc = 4;
299 else if (!charger_inserted())
300 rc = 1;
302 } while (!rc);
304 return rc;
306 #endif /* HAVE_CHARGING */
309 #if CONFIG_KEYPAD == RECORDER_PAD
310 /* returns:
311 0 if no key was pressed
312 1 if a key was pressed (or if ON was held down long enough to repeat)
313 2 if USB was connected */
314 int pitch_screen(void)
316 int button;
317 static int pitch = 1000;
318 bool exit = false;
319 bool used = false;
321 while (!exit) {
323 if ( used ) {
324 char* ptr;
325 char buf[32];
326 int w, h;
328 lcd_clear_display();
329 lcd_setfont(FONT_SYSFIXED);
331 ptr = str(LANG_PITCH_UP);
332 lcd_getstringsize(ptr,&w,&h);
333 lcd_putsxy((LCD_WIDTH-w)/2, 0, ptr);
334 lcd_bitmap(bitmap_icons_7x8[Icon_UpArrow],
335 LCD_WIDTH/2 - 3, h*2, 7, 8, true);
337 snprintf(buf, sizeof buf, "%d.%d%%", pitch / 10, pitch % 10 );
338 lcd_getstringsize(buf,&w,&h);
339 lcd_putsxy((LCD_WIDTH-w)/2, h, buf);
341 ptr = str(LANG_PITCH_DOWN);
342 lcd_getstringsize(ptr,&w,&h);
343 lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr);
344 lcd_bitmap(bitmap_icons_7x8[Icon_DownArrow],
345 LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8, true);
347 ptr = str(LANG_PAUSE);
348 lcd_getstringsize(ptr,&w,&h);
349 lcd_putsxy((LCD_WIDTH-(w/2))/2, LCD_HEIGHT/2 - h/2, ptr);
350 lcd_bitmap(bitmap_icons_7x8[Icon_Pause],
351 (LCD_WIDTH-(w/2))/2-10, LCD_HEIGHT/2 - h/2, 7, 8, true);
353 lcd_update();
356 /* use lastbutton, so the main loop can decide whether to
357 exit to browser or not */
358 button = button_get(true);
359 switch (button) {
360 case BUTTON_UP:
361 case BUTTON_ON | BUTTON_UP:
362 case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT:
363 used = true;
364 pitch++;
365 if ( pitch > 2000 )
366 pitch = 2000;
367 mpeg_set_pitch(pitch);
368 break;
370 case BUTTON_DOWN:
371 case BUTTON_ON | BUTTON_DOWN:
372 case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT:
373 used = true;
374 pitch--;
375 if ( pitch < 500 )
376 pitch = 500;
377 mpeg_set_pitch(pitch);
378 break;
380 case BUTTON_ON | BUTTON_PLAY:
381 mpeg_pause();
382 used = true;
383 break;
385 case BUTTON_PLAY | BUTTON_REL:
386 mpeg_resume();
387 used = true;
388 break;
390 case BUTTON_ON | BUTTON_PLAY | BUTTON_REL:
391 mpeg_resume();
392 exit = true;
393 break;
395 case BUTTON_ON | BUTTON_RIGHT:
396 if ( pitch < 2000 ) {
397 pitch += 20;
398 mpeg_set_pitch(pitch);
400 break;
402 case BUTTON_RIGHT | BUTTON_REL:
403 if ( pitch > 500 ) {
404 pitch -= 20;
405 mpeg_set_pitch(pitch);
407 break;
409 case BUTTON_ON | BUTTON_LEFT:
410 if ( pitch > 500 ) {
411 pitch -= 20;
412 mpeg_set_pitch(pitch);
414 break;
416 case BUTTON_LEFT | BUTTON_REL:
417 if ( pitch < 2000 ) {
418 pitch += 20;
419 mpeg_set_pitch(pitch);
421 break;
423 #ifdef SIMULATOR
424 case BUTTON_ON:
425 #else
426 case BUTTON_ON | BUTTON_REL:
427 case BUTTON_ON | BUTTON_UP | BUTTON_REL:
428 case BUTTON_ON | BUTTON_DOWN | BUTTON_REL:
429 #endif
430 exit = true;
431 break;
433 case BUTTON_ON | BUTTON_REPEAT:
434 used = true;
435 break;
437 default:
438 if(default_event_handler(button) == SYS_USB_CONNECTED)
439 return 2;
440 break;
444 lcd_setfont(FONT_UI);
446 if ( used )
447 return 1;
448 else
449 return 0;
452 bool quick_screen(int context, int button)
454 bool exit = false;
455 bool used = false;
456 int w, h, key;
457 char buf[32];
458 int oldrepeat = global_settings.repeat_mode;
460 /* just to stop compiler warning */
461 context = context;
462 lcd_setfont(FONT_SYSFIXED);
464 lcd_getstringsize("A",&w,&h);
466 while (!exit) {
467 char* ptr=NULL;
469 lcd_clear_display();
471 switch(button)
473 case BUTTON_F2:
474 /* Shuffle mode */
475 lcd_putsxy(0, LCD_HEIGHT/2 - h*2, str(LANG_SHUFFLE));
476 lcd_putsxy(0, LCD_HEIGHT/2 - h, str(LANG_F2_MODE));
477 lcd_putsxy(0, LCD_HEIGHT/2,
478 global_settings.playlist_shuffle ?
479 str(LANG_ON) : str(LANG_OFF));
481 /* Directory Filter */
482 switch ( global_settings.dirfilter ) {
483 case SHOW_ALL:
484 ptr = str(LANG_FILTER_ALL);
485 break;
487 case SHOW_SUPPORTED:
488 ptr = str(LANG_FILTER_SUPPORTED);
489 break;
491 case SHOW_MUSIC:
492 ptr = str(LANG_FILTER_MUSIC);
493 break;
495 case SHOW_PLAYLIST:
496 ptr = str(LANG_FILTER_PLAYLIST);
497 break;
500 snprintf(buf, sizeof buf, "%s:", str(LANG_FILTER));
501 lcd_getstringsize(buf,&w,&h);
502 lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, buf);
503 lcd_getstringsize(ptr,&w,&h);
504 lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr);
506 /* Repeat Mode */
507 switch ( global_settings.repeat_mode ) {
508 case REPEAT_OFF:
509 ptr = str(LANG_OFF);
510 break;
512 case REPEAT_ALL:
513 ptr = str(LANG_REPEAT_ALL);
514 break;
516 case REPEAT_ONE:
517 ptr = str(LANG_REPEAT_ONE);
518 break;
521 lcd_getstringsize(str(LANG_REPEAT),&w,&h);
522 lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h*2, str(LANG_REPEAT));
523 lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h, str(LANG_F2_MODE));
524 lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2, ptr);
525 break;
526 case BUTTON_F3:
527 /* Scrollbar */
528 lcd_putsxy(0, LCD_HEIGHT/2 - h*2, str(LANG_F3_SCROLL));
529 lcd_putsxy(0, LCD_HEIGHT/2 - h, str(LANG_F3_BAR));
530 lcd_putsxy(0, LCD_HEIGHT/2,
531 global_settings.scrollbar ? str(LANG_ON) : str(LANG_OFF));
533 /* Status bar */
534 ptr = str(LANG_F3_STATUS);
535 lcd_getstringsize(ptr,&w,&h);
536 lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h*2, ptr);
537 lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2 - h, str(LANG_F3_BAR));
538 lcd_putsxy(LCD_WIDTH - w, LCD_HEIGHT/2,
539 global_settings.statusbar ? str(LANG_ON) : str(LANG_OFF));
541 /* Flip */
542 ptr = str(LANG_FLIP_DISPLAY);
543 lcd_getstringsize(ptr,&w,&h);
544 lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, str(LANG_FLIP_DISPLAY));
545 ptr = global_settings.flip_display ?
546 str(LANG_SET_BOOL_YES) : str(LANG_SET_BOOL_NO);
547 lcd_getstringsize(ptr,&w,&h);
548 lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr);
549 break;
552 lcd_bitmap(bitmap_icons_7x8[Icon_FastBackward],
553 LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8, true);
554 lcd_bitmap(bitmap_icons_7x8[Icon_DownArrow],
555 LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8, true);
556 lcd_bitmap(bitmap_icons_7x8[Icon_FastForward],
557 LCD_WIDTH/2 + 8, LCD_HEIGHT/2 - 4, 7, 8, true);
559 lcd_update();
560 key = button_get(true);
563 * This is a temporary kludge so that the F2 & F3 menus operate in exactly
564 * the same manner up until the full F2/F3 configurable menus are complete
567 if( key == BUTTON_LEFT || key == BUTTON_RIGHT || key == BUTTON_DOWN || key == ( BUTTON_LEFT | BUTTON_REPEAT ) || key == ( BUTTON_RIGHT | BUTTON_REPEAT ) || key == ( BUTTON_DOWN | BUTTON_REPEAT ) )
568 key = button | key;
570 switch (key) {
571 case BUTTON_F2 | BUTTON_LEFT:
572 case BUTTON_F2 | BUTTON_LEFT | BUTTON_REPEAT:
573 global_settings.playlist_shuffle =
574 !global_settings.playlist_shuffle;
576 if(mpeg_status() & MPEG_STATUS_PLAY)
578 if (global_settings.playlist_shuffle)
579 playlist_randomise(NULL, current_tick, true);
580 else
581 playlist_sort(NULL, true);
583 used = true;
584 break;
586 case BUTTON_F2 | BUTTON_DOWN:
587 case BUTTON_F2 | BUTTON_DOWN | BUTTON_REPEAT:
588 global_settings.dirfilter++;
589 if ( global_settings.dirfilter >= NUM_FILTER_MODES )
590 global_settings.dirfilter = 0;
591 used = true;
592 break;
594 case BUTTON_F2 | BUTTON_RIGHT:
595 case BUTTON_F2 | BUTTON_RIGHT | BUTTON_REPEAT:
596 global_settings.repeat_mode++;
597 if ( global_settings.repeat_mode >= NUM_REPEAT_MODES )
598 global_settings.repeat_mode = 0;
599 used = true;
600 break;
602 case BUTTON_F3 | BUTTON_LEFT:
603 case BUTTON_F3 | BUTTON_LEFT | BUTTON_REPEAT:
604 global_settings.scrollbar = !global_settings.scrollbar;
605 used = true;
606 break;
608 case BUTTON_F3 | BUTTON_RIGHT:
609 case BUTTON_F3 | BUTTON_RIGHT | BUTTON_REPEAT:
610 global_settings.statusbar = !global_settings.statusbar;
611 used = true;
612 break;
614 case BUTTON_F3 | BUTTON_DOWN:
615 case BUTTON_F3 | BUTTON_DOWN | BUTTON_REPEAT:
616 case BUTTON_F3 | BUTTON_UP:
617 case BUTTON_F3 | BUTTON_UP | BUTTON_REPEAT:
618 global_settings.flip_display = !global_settings.flip_display;
619 button_set_flip(global_settings.flip_display);
620 lcd_set_flip(global_settings.flip_display);
621 used = true;
622 break;
624 case BUTTON_F3 | BUTTON_REL:
625 case BUTTON_F2 | BUTTON_REL:
627 if( used )
628 exit = true;
630 used = true;
632 break;
634 case BUTTON_OFF | BUTTON_REPEAT:
635 return false;
637 default:
638 if(default_event_handler(key) == SYS_USB_CONNECTED)
639 return true;
640 break;
644 settings_save();
646 switch( button )
648 case BUTTON_F2:
650 if ( oldrepeat != global_settings.repeat_mode )
651 mpeg_flush_and_reload_tracks();
653 break;
654 case BUTTON_F3:
656 if (global_settings.statusbar)
657 lcd_setmargins(0, STATUSBAR_HEIGHT);
658 else
659 lcd_setmargins(0, 0);
661 break;
664 lcd_setfont(FONT_UI);
666 return false;
668 #endif
670 #ifdef HAVE_LCD_BITMAP
671 #define SPACE 3 /* pixels between words */
672 #define MAXLETTERS 128 /* 16*8 */
673 #define MAXLINES 10
674 #else
675 #define SPACE 1 /* one letter space */
676 #undef LCD_WIDTH
677 #define LCD_WIDTH 11
678 #undef LCD_HEIGHT
679 #define LCD_HEIGHT 2
680 #define MAXLETTERS 22 /* 11 * 2 */
681 #define MAXLINES 2
682 #endif
684 void splash(int ticks, /* how long the splash is displayed */
685 bool center, /* FALSE means left-justified, TRUE means
686 horizontal and vertical center */
687 const char *fmt, /* what to say *printf style */
688 ...)
690 char *next;
691 char *store=NULL;
692 int x=0;
693 int y=0;
694 int w, h;
695 unsigned char splash_buf[MAXLETTERS];
696 va_list ap;
697 unsigned char widths[MAXLINES];
698 int line=0;
699 bool first=true;
700 #ifdef HAVE_LCD_BITMAP
701 int maxw=0;
702 #endif
704 #ifdef HAVE_LCD_CHARCELLS
705 lcd_double_height (false);
706 #endif
707 va_start( ap, fmt );
708 vsnprintf( splash_buf, sizeof(splash_buf), fmt, ap );
710 if(center) {
712 /* first a pass to measure sizes */
713 next = strtok_r(splash_buf, " ", &store);
714 while (next) {
715 #ifdef HAVE_LCD_BITMAP
716 lcd_getstringsize(next, &w, &h);
717 #else
718 w = strlen(next);
719 h = 1; /* store height in characters */
720 #endif
721 if(!first) {
722 if(x+w> LCD_WIDTH) {
723 /* Too wide, wrap */
724 y+=h;
725 line++;
726 if((y > (LCD_HEIGHT-h)) || (line > MAXLINES))
727 /* STOP */
728 break;
729 x=0;
730 first=true;
733 else
734 first = false;
736 /* think of it as if the text was written here at position x,y
737 being w pixels/chars wide and h high */
739 x += w+SPACE;
740 widths[line]=x-SPACE; /* don't count the trailing space */
741 #ifdef HAVE_LCD_BITMAP
742 /* store the widest line */
743 if(widths[line]>maxw)
744 maxw = widths[line];
745 #endif
746 next = strtok_r(NULL, " ", &store);
748 #ifdef HAVE_LCD_BITMAP
749 /* Start displaying the message at position y. The reason for the
750 added h here is that it isn't added until the end of lines in the
751 loop above and we always break the loop in the middle of a line. */
752 y = (LCD_HEIGHT - (y+h) )/2;
753 #else
754 y = 0; /* vertical center on 2 lines would be silly */
755 #endif
756 first=true;
758 /* Now recreate the string again since the strtok_r() above has ruined
759 the one we already have! Here's room for improvements! */
760 vsnprintf( splash_buf, sizeof(splash_buf), fmt, ap );
762 va_end( ap );
764 if(center)
766 x = (LCD_WIDTH-widths[0])/2;
767 if(x < 0)
768 x = 0;
771 #ifdef HAVE_LCD_BITMAP
772 /* If we center the display and it wouldn't cover the full screen,
773 then just clear the box we need and put a nice little frame and
774 put the text in there! */
775 if(center && (y > 2)) {
776 if(maxw < (LCD_WIDTH -4)) {
777 int xx = (LCD_WIDTH-maxw)/2 - 2;
778 lcd_clearrect(xx, y-2, maxw+4, LCD_HEIGHT-y*2+4);
779 lcd_drawrect(xx, y-2, maxw+4, LCD_HEIGHT-y*2+4);
781 else {
782 lcd_clearrect(0, y-2, LCD_WIDTH, LCD_HEIGHT-y*2+4);
783 lcd_drawline(0, y-2, LCD_WIDTH-1, y-2);
784 lcd_drawline(0, LCD_HEIGHT-y+2, LCD_WIDTH-1, LCD_HEIGHT-y+2);
787 else
788 #endif
789 lcd_clear_display();
790 line=0;
791 next = strtok_r(splash_buf, " ", &store);
792 while (next) {
793 #ifdef HAVE_LCD_BITMAP
794 lcd_getstringsize(next, &w, &h);
795 #else
796 w = strlen(next);
797 h = 1;
798 #endif
799 if(!first) {
800 if(x+w> LCD_WIDTH) {
801 /* too wide */
802 y+=h;
803 line++; /* goto next line */
804 first=true;
805 if(y > (LCD_HEIGHT-h))
806 /* STOP */
807 break;
808 if(center) {
809 x = (LCD_WIDTH-widths[line])/2;
810 if(x < 0)
811 x = 0;
813 else
814 x=0;
817 else
818 first=false;
819 #ifdef HAVE_LCD_BITMAP
820 lcd_putsxy(x, y, next);
821 #else
822 lcd_puts(x, y, next);
823 #endif
824 x += w+SPACE; /* pixels space! */
825 next = strtok_r(NULL, " ", &store);
827 lcd_update();
829 if(ticks)
830 /* unbreakable! */
831 sleep(ticks);
834 void charging_splash(void)
836 splash(2*HZ, true, str(LANG_BATTERY_CHARGE));
837 while (button_get(false));
841 #ifdef HAVE_LCD_BITMAP
843 /* little helper function for voice output */
844 static void say_time(int cursorpos, const struct tm *tm)
846 static const int unit[] = { UNIT_HOUR, UNIT_MIN, UNIT_SEC, 0, 0, 0 };
847 int value = 0;
849 if (!global_settings.talk_menu)
850 return;
852 switch(cursorpos)
854 case 0:
855 value = tm->tm_hour;
856 break;
857 case 1:
858 value = tm->tm_min;
859 break;
860 case 2:
861 value = tm->tm_sec;
862 break;
863 case 3:
864 value = tm->tm_year + 1900;
865 break;
866 case 5:
867 value = tm->tm_mday;
868 break;
871 if (cursorpos == 4) /* month */
872 talk_id(LANG_MONTH_JANUARY + tm->tm_mon, false);
873 else
874 talk_value(value, unit[cursorpos], false);
878 #define INDEX_X 0
879 #define INDEX_Y 1
880 #define INDEX_WIDTH 2
881 bool set_time_screen(const char* string, struct tm *tm)
883 bool done = false;
884 int button;
885 int min = 0, steps = 0;
886 int cursorpos = 0;
887 int lastcursorpos = !cursorpos;
888 unsigned char buffer[19];
889 int realyear;
890 int julianday;
891 int i;
892 unsigned char reffub[5];
893 unsigned int width, height;
894 unsigned int separator_width, weekday_width;
895 unsigned int line_height, prev_line_height;
897 static const int dayname[] = {
898 LANG_WEEKDAY_SUNDAY,
899 LANG_WEEKDAY_MONDAY,
900 LANG_WEEKDAY_TUESDAY,
901 LANG_WEEKDAY_WEDNESDAY,
902 LANG_WEEKDAY_THURSDAY,
903 LANG_WEEKDAY_FRIDAY,
904 LANG_WEEKDAY_SATURDAY
906 static const int monthname[] = {
907 LANG_MONTH_JANUARY,
908 LANG_MONTH_FEBRUARY,
909 LANG_MONTH_MARCH,
910 LANG_MONTH_APRIL,
911 LANG_MONTH_MAY,
912 LANG_MONTH_JUNE,
913 LANG_MONTH_JULY,
914 LANG_MONTH_AUGUST,
915 LANG_MONTH_SEPTEMBER,
916 LANG_MONTH_OCTOBER,
917 LANG_MONTH_NOVEMBER,
918 LANG_MONTH_DECEMBER
920 char cursor[][3] = {{ 0, 8, 12}, {18, 8, 12}, {36, 8, 12},
921 {24, 16, 24}, {54, 16, 18}, {78, 16, 12}};
922 char daysinmonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
924 int monthname_len = 0, dayname_len = 0;
926 int *valptr = NULL;
928 #ifdef HAVE_LCD_BITMAP
929 if(global_settings.statusbar)
930 lcd_setmargins(0, STATUSBAR_HEIGHT);
931 else
932 lcd_setmargins(0, 0);
933 #endif
934 lcd_clear_display();
935 lcd_puts_scroll(0, 0, string);
937 while ( !done ) {
938 /* calculate the number of days in febuary */
939 realyear = tm->tm_year + 1900;
940 if((realyear % 4 == 0 && !(realyear % 100 == 0)) || realyear % 400 == 0)
941 daysinmonth[1] = 29;
942 else
943 daysinmonth[1] = 28;
945 /* fix day if month or year changed */
946 if (tm->tm_mday > daysinmonth[tm->tm_mon])
947 tm->tm_mday = daysinmonth[tm->tm_mon];
949 /* calculate day of week */
950 julianday = 0;
951 for(i = 0; i < tm->tm_mon; i++) {
952 julianday += daysinmonth[i];
954 julianday += tm->tm_mday;
955 tm->tm_wday = (realyear + julianday + (realyear - 1) / 4 -
956 (realyear - 1) / 100 + (realyear - 1) / 400 + 7 - 1) % 7;
958 snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d ",
959 tm->tm_hour, tm->tm_min, tm->tm_sec);
960 lcd_puts(0, 1, buffer);
962 /* recalculate the positions and offsets */
963 lcd_getstringsize(string, &width, &prev_line_height);
964 lcd_getstringsize(buffer, &width, &line_height);
965 lcd_getstringsize(":", &separator_width, &height);
967 /* hour */
968 strncpy(reffub, buffer, 2);
969 reffub[2] = '\0';
970 lcd_getstringsize(reffub, &width, &height);
971 cursor[0][INDEX_X] = 0;
972 cursor[0][INDEX_Y] = prev_line_height;
973 cursor[0][INDEX_WIDTH] = width;
975 /* minute */
976 strncpy(reffub, buffer + 3, 2);
977 reffub[2] = '\0';
978 lcd_getstringsize(reffub, &width, &height);
979 cursor[1][INDEX_X] = cursor[0][INDEX_WIDTH] + separator_width;
980 cursor[1][INDEX_Y] = prev_line_height;
981 cursor[1][INDEX_WIDTH] = width;
983 /* second */
984 strncpy(reffub, buffer + 6, 2);
985 reffub[2] = '\0';
986 lcd_getstringsize(reffub, &width, &height);
987 cursor[2][INDEX_X] = cursor[0][INDEX_WIDTH] + separator_width +
988 cursor[1][INDEX_WIDTH] + separator_width;
989 cursor[2][INDEX_Y] = prev_line_height;
990 cursor[2][INDEX_WIDTH] = width;
992 lcd_getstringsize(buffer, &width, &prev_line_height);
994 snprintf(buffer, sizeof(buffer), "%s %04d %s %02d ",
995 str(dayname[tm->tm_wday]), tm->tm_year+1900,
996 str(monthname[tm->tm_mon]), tm->tm_mday);
997 lcd_puts(0, 2, buffer);
999 /* recalculate the positions and offsets */
1000 lcd_getstringsize(buffer, &width, &line_height);
1002 /* store these 2 to prevent _repeated_ strlen calls */
1003 monthname_len = strlen(str(monthname[tm->tm_mon]));
1004 dayname_len = strlen(str(dayname[tm->tm_wday]));
1006 /* weekday */
1007 strncpy(reffub, buffer, dayname_len);
1008 reffub[dayname_len] = '\0';
1009 lcd_getstringsize(reffub, &weekday_width, &height);
1010 lcd_getstringsize(" ", &separator_width, &height);
1012 /* year */
1013 strncpy(reffub, buffer + dayname_len + 1, 4);
1014 reffub[4] = '\0';
1015 lcd_getstringsize(reffub, &width, &height);
1016 cursor[3][INDEX_X] = weekday_width + separator_width;
1017 cursor[3][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
1018 cursor[3][INDEX_WIDTH] = width;
1020 /* month */
1021 strncpy(reffub, buffer + dayname_len + 6, monthname_len);
1022 reffub[monthname_len] = '\0';
1023 lcd_getstringsize(reffub, &width, &height);
1024 cursor[4][INDEX_X] = weekday_width + separator_width +
1025 cursor[3][INDEX_WIDTH] + separator_width;
1026 cursor[4][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
1027 cursor[4][INDEX_WIDTH] = width;
1029 /* day */
1030 strncpy(reffub, buffer + dayname_len + monthname_len + 7, 2);
1031 reffub[2] = '\0';
1032 lcd_getstringsize(reffub, &width, &height);
1033 cursor[5][INDEX_X] = weekday_width + separator_width +
1034 cursor[3][INDEX_WIDTH] + separator_width +
1035 cursor[4][INDEX_WIDTH] + separator_width;
1036 cursor[5][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
1037 cursor[5][INDEX_WIDTH] = width;
1039 lcd_invertrect(cursor[cursorpos][INDEX_X],
1040 cursor[cursorpos][INDEX_Y] + lcd_getymargin(),
1041 cursor[cursorpos][INDEX_WIDTH],
1042 line_height);
1044 lcd_puts(0, 4, str(LANG_TIME_SET));
1045 lcd_puts(0, 5, str(LANG_TIME_REVERT));
1046 #ifdef HAVE_LCD_BITMAP
1047 status_draw(true);
1048 #endif
1049 lcd_update();
1051 /* calculate the minimum and maximum for the number under cursor */
1052 if(cursorpos!=lastcursorpos) {
1053 lastcursorpos=cursorpos;
1054 switch(cursorpos) {
1055 case 0: /* hour */
1056 min = 0;
1057 steps = 24;
1058 valptr = &tm->tm_hour;
1059 break;
1060 case 1: /* minute */
1061 min = 0;
1062 steps = 60;
1063 valptr = &tm->tm_min;
1064 break;
1065 case 2: /* second */
1066 min = 0;
1067 steps = 60;
1068 valptr = &tm->tm_sec;
1069 break;
1070 case 3: /* year */
1071 min = 1;
1072 steps = 200;
1073 valptr = &tm->tm_year;
1074 break;
1075 case 4: /* month */
1076 min = 0;
1077 steps = 12;
1078 valptr = &tm->tm_mon;
1079 break;
1080 case 5: /* day */
1081 min = 1;
1082 steps = daysinmonth[tm->tm_mon];
1083 valptr = &tm->tm_mday;
1084 break;
1086 say_time(cursorpos, tm);
1089 button = button_get_w_tmo(HZ/2);
1090 switch ( button ) {
1091 case BUTTON_LEFT:
1092 cursorpos = (cursorpos + 6 - 1) % 6;
1093 break;
1094 case BUTTON_RIGHT:
1095 cursorpos = (cursorpos + 6 + 1) % 6;
1096 break;
1097 case BUTTON_UP:
1098 case BUTTON_UP | BUTTON_REPEAT:
1099 *valptr = (*valptr + steps - min + 1) %
1100 steps + min;
1101 if(*valptr == 0)
1102 *valptr = min;
1103 say_time(cursorpos, tm);
1104 break;
1105 case BUTTON_DOWN:
1106 case BUTTON_DOWN | BUTTON_REPEAT:
1107 *valptr = (*valptr + steps - min - 1) %
1108 steps + min;
1109 if(*valptr == 0)
1110 *valptr = min;
1111 say_time(cursorpos, tm);
1112 break;
1114 #ifdef BUTTON_ON
1115 case BUTTON_ON:
1116 #elif defined BUTTON_MENU
1117 case BUTTON_MENU:
1118 #endif
1119 done = true;
1120 break;
1122 case BUTTON_OFF:
1123 done = true;
1124 tm->tm_year = -1;
1125 break;
1127 default:
1128 if (default_event_handler(button) == SYS_USB_CONNECTED)
1129 return true;
1130 break;
1134 return false;
1136 #endif
1138 #if CONFIG_KEYPAD == RECORDER_PAD
1139 bool shutdown_screen(void)
1141 int button;
1142 bool done = false;
1144 lcd_stop_scroll();
1146 splash(0, true, str(LANG_CONFIRM_SHUTDOWN));
1148 while(!done)
1150 button = button_get_w_tmo(HZ*2);
1151 switch(button)
1153 case BUTTON_OFF:
1154 clean_shutdown();
1155 break;
1157 default:
1158 if(default_event_handler(button) == SYS_USB_CONNECTED)
1159 return true;
1161 /* Return if any other button was pushed, or if there
1162 was a timeout. We ignore RELEASE events, since we may
1163 have been called by a button down event, and the user might
1164 not have released the button yet.
1165 We also ignore REPEAT events, since we don't want to
1166 remove the splash when the user holds OFF to shut down. */
1167 if(!(button & (BUTTON_REL | BUTTON_REPEAT)))
1168 done = true;
1169 break;
1172 return false;
1174 #endif
1176 bool browse_id3(void)
1178 struct mp3entry* id3 = mpeg_current_track();
1179 int button;
1180 int menu_pos = 0;
1181 int menu_max = 8;
1182 bool exit = false;
1183 char scroll_text[MAX_PATH];
1185 if (!(mpeg_status() & MPEG_STATUS_PLAY))
1186 return false;
1188 while (!exit)
1190 lcd_clear_display();
1192 switch (menu_pos)
1194 case 0:
1195 lcd_puts(0, 0, str(LANG_ID3_TITLE));
1196 lcd_puts_scroll(0, 1, id3->title ? id3->title :
1197 (char*)str(LANG_ID3_NO_TITLE));
1198 break;
1200 case 1:
1201 lcd_puts(0, 0, str(LANG_ID3_ARTIST));
1202 lcd_puts_scroll(0, 1,
1203 id3->artist ? id3->artist :
1204 (char*)str(LANG_ID3_NO_ARTIST));
1205 break;
1207 case 2:
1208 lcd_puts(0, 0, str(LANG_ID3_ALBUM));
1209 lcd_puts_scroll(0, 1, id3->album ? id3->album :
1210 (char*)str(LANG_ID3_NO_ALBUM));
1211 break;
1213 case 3:
1214 lcd_puts(0, 0, str(LANG_ID3_TRACKNUM));
1216 if (id3->tracknum) {
1217 snprintf(scroll_text,sizeof(scroll_text), "%d",
1218 id3->tracknum);
1219 lcd_puts_scroll(0, 1, scroll_text);
1221 else
1222 lcd_puts_scroll(0, 1, str(LANG_ID3_NO_TRACKNUM));
1223 break;
1225 case 4:
1226 lcd_puts(0, 0, str(LANG_ID3_GENRE));
1227 lcd_puts_scroll(0, 1,
1228 id3_get_genre(id3) ?
1229 id3_get_genre(id3) :
1230 (char*)str(LANG_ID3_NO_INFO));
1231 break;
1233 case 5:
1234 lcd_puts(0, 0, str(LANG_ID3_YEAR));
1235 if (id3->year) {
1236 snprintf(scroll_text,sizeof(scroll_text), "%d",
1237 id3->year);
1238 lcd_puts_scroll(0, 1, scroll_text);
1240 else
1241 lcd_puts_scroll(0, 1, str(LANG_ID3_NO_INFO));
1242 break;
1244 case 6:
1245 lcd_puts(0, 0, str(LANG_ID3_LENGHT));
1246 snprintf(scroll_text,sizeof(scroll_text), "%d:%02d",
1247 id3->length / 60000,
1248 id3->length % 60000 / 1000 );
1249 lcd_puts(0, 1, scroll_text);
1250 break;
1252 case 7:
1253 lcd_puts(0, 0, str(LANG_ID3_PLAYLIST));
1254 snprintf(scroll_text,sizeof(scroll_text), "%d/%d",
1255 playlist_get_display_index(), playlist_amount());
1256 lcd_puts_scroll(0, 1, scroll_text);
1257 break;
1260 case 8:
1261 lcd_puts(0, 0, str(LANG_ID3_BITRATE));
1262 snprintf(scroll_text,sizeof(scroll_text), "%d kbps",
1263 id3->bitrate);
1264 lcd_puts(0, 1, scroll_text);
1265 break;
1267 case 9:
1268 lcd_puts(0, 0, str(LANG_ID3_FRECUENCY));
1269 snprintf(scroll_text,sizeof(scroll_text), "%d Hz",
1270 id3->frequency);
1271 lcd_puts(0, 1, scroll_text);
1272 break;
1274 case 10:
1275 lcd_puts(0, 0, str(LANG_ID3_PATH));
1276 lcd_puts_scroll(0, 1, id3->path);
1277 break;
1279 lcd_update();
1281 button = button_get(true);
1283 switch(button)
1285 case SETTINGS_DEC:
1286 if (menu_pos > 0)
1287 menu_pos--;
1288 else
1289 menu_pos = menu_max;
1290 break;
1292 case SETTINGS_INC:
1293 if (menu_pos < menu_max)
1294 menu_pos++;
1295 else
1296 menu_pos = 0;
1297 break;
1299 case SETTINGS_CANCEL:
1300 lcd_stop_scroll();
1301 /* eat release event */
1302 button_get(true);
1303 exit = true;
1304 break;
1306 default:
1307 if(default_event_handler(button) == SYS_USB_CONNECTED)
1308 return true;
1309 break;
1312 return false;