Add OF LCD init
[kugel-rb.git] / apps / gui / gwps.c
blob2e72813d73a0bba9de0cf1b6fb23bb635f562555
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Jerome Kuptz
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 <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include "config.h"
24 #include "system.h"
25 #include "file.h"
26 #include "lcd.h"
27 #include "font.h"
28 #include "backlight.h"
29 #include "action.h"
30 #include "kernel.h"
31 #include "filetypes.h"
32 #include "debug.h"
33 #include "sprintf.h"
34 #include "settings.h"
35 #include "gwps.h"
36 #include "gwps-common.h"
37 #include "audio.h"
38 #include "usb.h"
39 #include "status.h"
40 #include "ata.h"
41 #include "screens.h"
42 #include "playlist.h"
43 #ifdef HAVE_LCD_BITMAP
44 #include "icons.h"
45 #include "peakmeter.h"
46 #endif
47 #include "action.h"
48 #include "lang.h"
49 #include "bookmark.h"
50 #include "misc.h"
51 #include "sound.h"
52 #include "onplay.h"
53 #include "abrepeat.h"
54 #include "playback.h"
55 #include "splash.h"
56 #include "cuesheet.h"
57 #include "ata_idle_notify.h"
58 #include "root_menu.h"
59 #include "backdrop.h"
60 #include "quickscreen.h"
62 /* currently only on wps_state is needed */
63 struct wps_state wps_state;
64 struct gui_wps gui_wps[NB_SCREENS];
65 static struct wps_data wps_datas[NB_SCREENS];
67 /* change the path to the current played track */
68 static void wps_state_update_ctp(const char *path);
69 /* initial setup of wps_data */
70 static void wps_state_init(void);
71 /* initial setup of a wps */
72 static void gui_wps_init(struct gui_wps *gui_wps);
73 /* connects a wps with a format-description of the displayed content */
74 static void gui_wps_set_data(struct gui_wps *gui_wps, struct wps_data *data);
75 /* connects a wps with a screen */
76 static void gui_wps_set_disp(struct gui_wps *gui_wps, struct screen *display);
77 /* connects a wps with a statusbar*/
78 static void gui_wps_set_statusbar(struct gui_wps *gui_wps, struct gui_statusbar *statusbar);
80 #ifdef HAVE_LCD_BITMAP
81 static void gui_wps_set_margin(struct gui_wps *gwps)
83 int offset = 0;
84 struct wps_data *data = gwps->data;
85 if(data->wps_sb_tag && data->show_sb_on_wps)
86 offset = STATUSBAR_HEIGHT;
87 else if ( global_settings.statusbar && !data->wps_sb_tag)
88 offset = STATUSBAR_HEIGHT;
89 gwps->display->setmargins(0, offset);
91 #endif
93 long gui_wps_show(void)
95 long button = 0;
96 bool restore = false;
97 long restoretimer = 0; /* timer to delay screen redraw temporarily */
98 bool exit = false;
99 bool bookmark = false;
100 bool update_track = false;
101 int i;
102 long last_left = 0, last_right = 0;
104 wps_state_init();
106 #ifdef HAVE_LCD_CHARCELLS
107 status_set_audio(true);
108 status_set_param(false);
109 #else
110 FOR_NB_SCREENS(i)
112 gui_wps_set_margin(&gui_wps[i]);
114 #if LCD_DEPTH > 1
115 show_wps_backdrop();
116 #endif /* LCD_DEPTH > 1 */
117 #endif
119 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
120 show_remote_wps_backdrop();
121 #endif
123 #ifdef AB_REPEAT_ENABLE
124 ab_repeat_init();
125 ab_reset_markers();
126 #endif
128 if(audio_status() & AUDIO_STATUS_PLAY)
130 wps_state.id3 = audio_current_track();
131 wps_state.nid3 = audio_next_track();
132 if (wps_state.id3) {
133 if (gui_wps_display())
134 return 0;
135 FOR_NB_SCREENS(i)
136 gui_wps_refresh(&gui_wps[i], 0, WPS_REFRESH_ALL);
137 wps_state_update_ctp(wps_state.id3->path);
140 restore = true;
142 while ( 1 )
144 bool audio_paused = (audio_status() & AUDIO_STATUS_PAUSE)?true:false;
146 /* did someone else (i.e power thread) change audio pause mode? */
147 if (wps_state.paused != audio_paused) {
148 wps_state.paused = audio_paused;
150 /* if another thread paused audio, we are probably in car mode,
151 about to shut down. lets save the settings. */
152 if (wps_state.paused) {
153 settings_save();
154 #if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
155 call_ata_idle_notifys(true);
156 #endif
160 #ifdef HAVE_LCD_BITMAP
161 /* when the peak meter is enabled we want to have a
162 few extra updates to make it look smooth. On the
163 other hand we don't want to waste energy if it
164 isn't displayed */
165 bool pm=false;
166 FOR_NB_SCREENS(i)
168 if(gui_wps[i].data->peak_meter_enabled)
169 pm = true;
172 if (pm) {
173 long next_refresh = current_tick;
174 long next_big_refresh = current_tick + HZ / 5;
175 button = BUTTON_NONE;
176 while (TIME_BEFORE(current_tick, next_big_refresh)) {
177 button = get_action(CONTEXT_WPS|ALLOW_SOFTLOCK,TIMEOUT_NOBLOCK);
178 if (button != ACTION_NONE) {
179 break;
181 peak_meter_peek();
182 sleep(0); /* Sleep until end of current tick. */
184 if (TIME_AFTER(current_tick, next_refresh)) {
185 FOR_NB_SCREENS(i)
187 if(gui_wps[i].data->peak_meter_enabled)
188 gui_wps_refresh(&gui_wps[i], 0,
189 WPS_REFRESH_PEAK_METER);
190 next_refresh += HZ / PEAK_METER_FPS;
197 /* The peak meter is disabled
198 -> no additional screen updates needed */
199 else {
200 button = get_action(CONTEXT_WPS|ALLOW_SOFTLOCK,HZ/5);
202 #else
203 button = get_action(CONTEXT_WPS|ALLOW_SOFTLOCK,HZ/5);
204 #endif
206 /* Exit if audio has stopped playing. This can happen if using the
207 sleep timer with the charger plugged or if starting a recording
208 from F1 */
209 if (!audio_status())
210 exit = true;
211 #ifdef ACTION_WPSAB_SINGLE
212 if (!global_settings.party_mode && ab_repeat_mode_enabled())
214 static int wps_ab_state = 0;
215 if (button == ACTION_WPSAB_SINGLE)
217 switch (wps_ab_state)
219 case 0: /* set the A spot */
220 button = ACTION_WPS_ABSETA_PREVDIR;
221 break;
222 case 1: /* set the B spot */
223 button = ACTION_WPS_ABSETB_NEXTDIR;
224 break;
225 case 2:
226 button = ACTION_WPS_ABRESET;
227 break;
229 wps_ab_state = (wps_ab_state+1) % 3;
232 #endif
233 switch(button)
235 case ACTION_WPS_CONTEXT:
236 #if LCD_DEPTH > 1
237 show_main_backdrop();
238 #endif
239 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
240 show_remote_main_backdrop();
241 #endif
242 /* if music is stopped in the context menu we want to exit the wps */
243 if (onplay(wps_state.id3->path,
244 FILE_ATTR_AUDIO, CONTEXT_WPS) == ONPLAY_MAINMENU
245 || !audio_status())
246 return GO_TO_ROOT;
248 /* track might have changed */
249 update_track = true;
251 #if LCD_DEPTH > 1
252 show_wps_backdrop();
253 #endif
254 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
255 show_remote_wps_backdrop();
256 #endif
257 #ifdef HAVE_LCD_BITMAP
258 FOR_NB_SCREENS(i)
260 gui_wps_set_margin(&gui_wps[i]);
262 #endif
263 restore = true;
264 break;
266 case ACTION_WPS_BROWSE:
267 #ifdef HAVE_LCD_CHARCELLS
268 status_set_record(false);
269 status_set_audio(false);
270 #endif
271 FOR_NB_SCREENS(i)
272 gui_wps[i].display->stop_scroll();
273 return GO_TO_PREVIOUS_BROWSER;
274 break;
276 /* play/pause */
277 case ACTION_WPS_PLAY:
278 if (global_settings.party_mode)
279 break;
280 if ( wps_state.paused )
282 wps_state.paused = false;
283 if ( global_settings.fade_on_stop )
284 fade(1);
285 else
286 audio_resume();
288 else
290 wps_state.paused = true;
291 if ( global_settings.fade_on_stop )
292 fade(0);
293 else
294 audio_pause();
295 settings_save();
296 #if !defined(HAVE_RTC_RAM) && !defined(HAVE_SW_POWEROFF)
297 call_ata_idle_notifys(true); /* make sure resume info is saved */
298 #endif
300 break;
302 /* volume up */
303 case ACTION_WPS_VOLUP:
305 global_settings.volume++;
306 bool res = false;
307 setvol();
308 FOR_NB_SCREENS(i)
310 if(update_onvol_change(&gui_wps[i]))
311 res = true;
313 if (res) {
314 restore = true;
315 restoretimer = current_tick + HZ;
318 break;
320 /* volume down */
321 case ACTION_WPS_VOLDOWN:
323 global_settings.volume--;
324 setvol();
325 bool res = false;
326 FOR_NB_SCREENS(i)
328 if(update_onvol_change(&gui_wps[i]))
329 res = true;
331 if (res) {
332 restore = true;
333 restoretimer = current_tick + HZ;
336 break;
337 /* fast forward
338 OR next dir if this is straight after ACTION_WPS_SKIPNEXT */
339 case ACTION_WPS_SEEKFWD:
340 if (global_settings.party_mode)
341 break;
342 if (current_tick -last_right < HZ)
344 if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type)
346 audio_next();
348 else
350 audio_next_dir();
353 else ffwd_rew(ACTION_WPS_SEEKFWD);
354 last_right = 0;
355 break;
356 /* fast rewind
357 OR prev dir if this is straight after ACTION_WPS_SKIPPREV */
358 case ACTION_WPS_SEEKBACK:
359 if (global_settings.party_mode)
360 break;
361 if (current_tick -last_left < HZ)
363 if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type)
365 if (!wps_state.paused)
366 #if (CONFIG_CODEC == SWCODEC)
367 audio_pre_ff_rewind();
368 #else
369 audio_pause();
370 #endif
371 audio_ff_rewind(0);
373 else
375 audio_prev_dir();
378 else ffwd_rew(ACTION_WPS_SEEKBACK);
379 last_left = 0;
380 break;
382 /* prev / restart */
383 case ACTION_WPS_SKIPPREV:
384 if (global_settings.party_mode)
385 break;
386 last_left = current_tick;
387 update_track = true;
389 #ifdef AB_REPEAT_ENABLE
390 /* if we're in A/B repeat mode and the current position
391 is past the A marker, jump back to the A marker... */
392 if ( ab_repeat_mode_enabled() )
394 if ( ab_after_A_marker(wps_state.id3->elapsed) )
396 ab_jump_to_A_marker();
397 break;
398 #if (AB_REPEAT_ENABLE == 2)
399 } else {
400 ab_reset_markers();
401 #endif
404 /* ...otherwise, do it normally */
405 #endif
407 if (!wps_state.id3 || (wps_state.id3->elapsed < 3*1000)) {
408 audio_prev();
410 else {
412 if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type)
414 curr_cuesheet_skip(-1, wps_state.id3->elapsed);
415 break;
418 if (!wps_state.paused)
419 #if (CONFIG_CODEC == SWCODEC)
420 audio_pre_ff_rewind();
421 #else
422 audio_pause();
423 #endif
425 audio_ff_rewind(0);
427 #if (CONFIG_CODEC != SWCODEC)
428 if (!wps_state.paused)
429 audio_resume();
430 #endif
432 break;
434 /* next */
435 case ACTION_WPS_SKIPNEXT:
436 if (global_settings.party_mode)
437 break;
438 last_right = current_tick;
439 update_track = true;
441 #ifdef AB_REPEAT_ENABLE
442 /* if we're in A/B repeat mode and the current position is
443 before the A marker, jump to the A marker... */
444 if ( ab_repeat_mode_enabled() )
446 if ( ab_before_A_marker(wps_state.id3->elapsed) )
448 ab_jump_to_A_marker();
449 break;
450 #if (AB_REPEAT_ENABLE == 2)
451 } else {
452 ab_reset_markers();
453 #endif
456 /* ...otherwise, do it normally */
457 #endif
459 /* take care of if we're playing a cuesheet */
460 if (cuesheet_is_enabled() && wps_state.id3->cuesheet_type)
462 if (curr_cuesheet_skip(1, wps_state.id3->elapsed))
464 /* if the result was false, then we really want
465 to skip to the next track */
466 break;
470 audio_next();
471 break;
472 /* next / prev directories */
473 /* and set A-B markers if in a-b mode */
474 case ACTION_WPS_ABSETB_NEXTDIR:
475 if (global_settings.party_mode)
476 break;
477 #if defined(AB_REPEAT_ENABLE)
478 if (ab_repeat_mode_enabled())
480 ab_set_B_marker(wps_state.id3->elapsed);
481 ab_jump_to_A_marker();
482 update_track = true;
484 else
485 #endif
487 audio_next_dir();
489 break;
490 case ACTION_WPS_ABSETA_PREVDIR:
491 if (global_settings.party_mode)
492 break;
493 #if defined(AB_REPEAT_ENABLE)
494 if (ab_repeat_mode_enabled())
495 ab_set_A_marker(wps_state.id3->elapsed);
496 else
497 #endif
499 audio_prev_dir();
501 break;
502 /* menu key functions */
503 case ACTION_WPS_MENU:
504 FOR_NB_SCREENS(i)
505 gui_wps[i].display->stop_scroll();
506 return GO_TO_ROOT;
507 break;
510 #ifdef HAVE_QUICKSCREEN
511 case ACTION_WPS_QUICKSCREEN:
512 #if LCD_DEPTH > 1
513 show_main_backdrop();
514 #endif
515 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
516 show_remote_main_backdrop();
517 #endif
518 if (quick_screen_quick(button))
519 return SYS_USB_CONNECTED;
520 #if LCD_DEPTH > 1
521 show_wps_backdrop();
522 #endif
523 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
524 show_remote_wps_backdrop();
525 #endif
526 #ifdef HAVE_LCD_BITMAP
527 FOR_NB_SCREENS(i)
529 gui_wps_set_margin(&gui_wps[i]);
531 #endif
532 restore = true;
533 break;
534 #endif /* HAVE_QUICKSCREEN */
536 /* screen settings */
537 #ifdef BUTTON_F3
538 case ACTION_F3:
539 #if LCD_DEPTH > 1
540 show_main_backdrop();
541 #endif
542 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
543 show_remote_main_backdrop();
544 #endif
545 if (quick_screen_f3(BUTTON_F3))
546 return SYS_USB_CONNECTED;
547 #ifdef HAVE_LCD_BITMAP
548 FOR_NB_SCREENS(i)
550 gui_wps_set_margin(&gui_wps[i]);
552 #endif
553 restore = true;
554 break;
555 #endif /* BUTTON_F3 */
557 /* pitch screen */
558 #ifdef HAVE_PITCHSCREEN
559 case ACTION_WPS_PITCHSCREEN:
560 #if LCD_DEPTH > 1
561 show_main_backdrop();
562 #endif
563 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
564 show_remote_main_backdrop();
565 #endif
566 if (1 == pitch_screen())
567 return SYS_USB_CONNECTED;
568 #if LCD_DEPTH > 1
569 show_wps_backdrop();
570 #endif
571 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
572 show_remote_wps_backdrop();
573 #endif
574 restore = true;
575 break;
576 #endif /* HAVE_PITCHSCREEN */
578 #ifdef AB_REPEAT_ENABLE
579 /* reset A&B markers */
580 case ACTION_WPS_ABRESET:
581 if (ab_repeat_mode_enabled())
583 ab_reset_markers();
584 update_track = true;
586 break;
587 #endif /* AB_REPEAT_ENABLE */
589 /* stop and exit wps */
590 case ACTION_WPS_STOP:
591 if (global_settings.party_mode)
592 break;
593 bookmark = true;
594 exit = true;
595 break;
597 case ACTION_WPS_ID3SCREEN:
598 #if LCD_DEPTH > 1
599 show_main_backdrop();
600 #endif
601 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
602 show_remote_main_backdrop();
603 #endif
604 browse_id3();
605 #if LCD_DEPTH > 1
606 show_wps_backdrop();
607 #endif
608 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
609 show_remote_wps_backdrop();
610 #endif
611 #ifdef HAVE_LCD_BITMAP
612 FOR_NB_SCREENS(i)
614 gui_wps_set_margin(&gui_wps[i]);
616 #endif
617 restore = true;
618 break;
620 case ACTION_REDRAW: /* yes are locked, just redraw */
621 restore = true;
622 break;
623 case ACTION_NONE: /* Timeout */
624 update_track = true;
625 ffwd_rew(button); /* hopefully fix the ffw/rwd bug */
626 break;
627 #ifdef HAVE_RECORDING
628 case ACTION_WPS_REC:
629 exit = true;
630 break;
631 #endif
632 case SYS_POWEROFF:
633 #if LCD_DEPTH > 1
634 show_main_backdrop();
635 #endif
636 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
637 show_remote_main_backdrop();
638 #endif
639 default_event_handler(SYS_POWEROFF);
640 break;
642 default:
643 if(default_event_handler(button) == SYS_USB_CONNECTED)
644 return GO_TO_ROOT;
645 update_track = true;
646 break;
649 if (update_track)
651 FOR_NB_SCREENS(i)
653 if(update(&gui_wps[i]))
654 exit = true;
656 update_track = false;
659 if (restore &&
660 ((restoretimer == 0) ||
661 (restoretimer < current_tick)))
663 restore = false;
664 restoretimer = 0;
665 if (gui_wps_display()) {
666 exit = true;
668 else if (wps_state.id3){
669 FOR_NB_SCREENS(i)
670 gui_wps_refresh(&gui_wps[i], 0, WPS_REFRESH_NON_STATIC);
674 if (exit) {
675 #ifdef HAVE_LCD_CHARCELLS
676 status_set_record(false);
677 status_set_audio(false);
678 #endif
679 if (global_settings.fade_on_stop)
680 fade(0);
682 FOR_NB_SCREENS(i)
683 gui_wps[i].display->stop_scroll();
684 if (bookmark)
685 bookmark_autobookmark();
686 audio_stop();
687 #ifdef AB_REPEAT_ENABLE
688 ab_reset_markers();
689 #endif
690 #ifdef HAVE_RECORDING
691 if (button == ACTION_WPS_REC)
692 return GO_TO_RECSCREEN;
693 #endif
694 if (global_settings.browse_current)
695 return GO_TO_PREVIOUS_BROWSER;
696 return GO_TO_PREVIOUS;
699 if ( button )
700 ata_spin();
702 return GO_TO_ROOT; /* unreachable - just to reduce compiler warnings */
705 /* needs checking if needed end*/
707 /* wps_state */
709 static void wps_state_init(void)
711 wps_state.ff_rewind = false;
712 wps_state.paused = false;
713 wps_state.id3 = NULL;
714 wps_state.nid3 = NULL;
715 wps_state.current_track_path[0] = '\0';
718 #if 0
719 /* these are obviously not used? */
721 void wps_state_update_ff_rew(bool ff_rew)
723 wps_state.ff_rewind = ff_rew;
726 void wps_state_update_paused(bool paused)
728 wps_state.paused = paused;
730 void wps_state_update_id3_nid3(struct mp3entry *id3, struct mp3entry *nid3)
732 wps_state.id3 = id3;
733 wps_state.nid3 = nid3;
735 #endif
737 static void wps_state_update_ctp(const char *path)
739 strncpy(wps_state.current_track_path, path,
740 sizeof(wps_state.current_track_path));
741 wps_state.current_track_path[sizeof(wps_state.current_track_path)-1] = '\0';
743 /* wps_state end*/
745 /* initial setup of a wps */
746 static void gui_wps_init(struct gui_wps *gui_wps)
748 gui_wps->data = NULL;
749 gui_wps->display = NULL;
750 gui_wps->statusbar = NULL;
751 /* Currently no seperate wps_state needed/possible
752 so use the only aviable ( "global" ) one */
753 gui_wps->state = &wps_state;
756 /* connects a wps with a format-description of the displayed content */
757 static void gui_wps_set_data(struct gui_wps *gui_wps, struct wps_data *data)
759 gui_wps->data = data;
762 /* connects a wps with a screen */
763 static void gui_wps_set_disp(struct gui_wps *gui_wps, struct screen *display)
765 gui_wps->display = display;
768 static void gui_wps_set_statusbar(struct gui_wps *gui_wps, struct gui_statusbar *statusbar)
770 gui_wps->statusbar = statusbar;
772 /* gui_wps end */
774 void gui_sync_wps_screen_init(void)
776 int i;
777 FOR_NB_SCREENS(i)
778 gui_wps_set_disp(&gui_wps[i], &screens[i]);
781 void gui_sync_wps_init(void)
783 int i;
784 FOR_NB_SCREENS(i)
786 wps_data_init(&wps_datas[i]);
787 #ifdef HAVE_REMOTE_LCD
788 wps_datas[i].remote_wps = (i != 0);
789 #endif
790 gui_wps_init(&gui_wps[i]);
791 gui_wps_set_data(&gui_wps[i], &wps_datas[i]);
792 gui_wps_set_statusbar(&gui_wps[i], &statusbars.statusbars[i]);
794 #if LCD_DEPTH > 1
795 unload_wps_backdrop();
796 #endif
797 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
798 unload_remote_wps_backdrop();
799 #endif
802 #ifdef HAVE_ALBUMART
803 /* Returns true if at least one of the gui_wps screens has an album art
804 tag in its wps structure */
805 bool gui_sync_wps_uses_albumart(void)
807 int i;
808 FOR_NB_SCREENS(i) {
809 struct gui_wps *gwps = &gui_wps[i];
810 if (gwps->data && (gwps->data->wps_uses_albumart != WPS_ALBUMART_NONE))
811 return true;
813 return false;
815 #endif