simple fix for FS#7274 - selected item might not be shown when a list is drawn in...
[Rockbox.git] / apps / root_menu.c
blob9858fed35d41e76f65f516292d82cdf98b098435
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Jonathan Gordon
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 <stdbool.h>
23 #include "config.h"
24 #include "menu.h"
25 #include "root_menu.h"
26 #include "lang.h"
27 #include "settings.h"
28 #include "screens.h"
29 #include "kernel.h"
30 #include "debug.h"
31 #include "misc.h"
32 #include "rolo.h"
33 #include "powermgmt.h"
34 #include "power.h"
35 #include "talk.h"
36 #include "audio.h"
38 #if (LCD_DEPTH > 1) || (defined(HAVE_LCD_REMOTE) && (LCD_REMOTE_DEPTH > 1))
39 #include "backdrop.h"
40 #endif
43 /* gui api */
44 #include "list.h"
45 #include "statusbar.h"
46 #include "splash.h"
47 #include "buttonbar.h"
48 #include "textarea.h"
49 #include "action.h"
50 #include "yesno.h"
52 #include "tree.h"
53 #if CONFIG_TUNER
54 #include "radio.h"
55 #endif
56 #ifdef HAVE_RECORDING
57 #include "recording.h"
58 #endif
59 #include "gwps-common.h"
60 #include "bookmark.h"
61 #include "tagtree.h"
62 #include "menus/exported_menus.h"
63 #ifdef HAVE_RTC_ALARM
64 #include "rtc.h"
65 #endif
66 #ifdef HAVE_TAGCACHE
67 #include "tagcache.h"
68 #endif
70 struct root_items {
71 int (*function)(void* param);
72 void* param;
73 const struct menu_item_ex *context_menu;
75 static int last_screen = GO_TO_ROOT; /* unfortunatly needed so we can resume
76 or goto current track based on previous
77 screen */
78 static int browser(void* param)
80 int ret_val;
81 #ifdef HAVE_TAGCACHE
82 struct tree_context* tc = tree_get_context();
83 #endif
84 int filter = SHOW_SUPPORTED;
85 char folder[MAX_PATH] = "/";
86 /* stuff needed to remember position in file browser */
87 static char last_folder[MAX_PATH] = "/";
88 /* and stuff for the database browser */
89 #ifdef HAVE_TAGCACHE
90 static int last_db_dirlevel = 0, last_db_selection = 0;
91 #endif
93 switch ((intptr_t)param)
95 case GO_TO_FILEBROWSER:
96 filter = global_settings.dirfilter;
97 if (global_settings.browse_current &&
98 last_screen == GO_TO_WPS && audio_status() &&
99 wps_state.current_track_path[0] != '\0')
101 strcpy(folder, wps_state.current_track_path);
103 else
104 strcpy(folder, last_folder);
105 break;
106 #ifdef HAVE_TAGCACHE
107 case GO_TO_DBBROWSER:
108 if (!tagcache_is_usable())
110 bool reinit_attempted = false;
112 /* Now display progress until it's ready or the user exits */
113 while(!tagcache_is_usable())
115 gui_syncstatusbar_draw(&statusbars, false);
116 struct tagcache_stat *stat = tagcache_get_stat();
118 /* Allow user to exit */
119 if (action_userabort(HZ/2))
120 break;
122 /* Maybe just needs to reboot due to delayed commit */
123 if (stat->commit_delayed)
125 gui_syncsplash(HZ*2, str(LANG_PLEASE_REBOOT));
126 break;
129 /* Check if ready status is known */
130 if (!stat->readyvalid)
132 gui_syncsplash(0, str(LANG_TAGCACHE_BUSY));
133 continue;
136 /* Re-init if required */
137 if (!reinit_attempted && !stat->ready &&
138 stat->processed_entries == 0 && stat->commit_step == 0)
140 /* Prompt the user */
141 reinit_attempted = true;
142 char *lines[]={str(LANG_TAGCACHE_BUSY), str(LANG_TAGCACHE_FORCE_UPDATE)};
143 struct text_message message={lines, 2};
144 if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO)
145 break;
146 int i;
147 FOR_NB_SCREENS(i)
148 screens[i].clear_display();
150 /* Start initialisation */
151 tagcache_rebuild();
154 /* Display building progress */
155 if (stat->commit_step > 0)
157 gui_syncsplash(0, "%s [%d/%d]",
158 str(LANG_TAGCACHE_INIT), stat->commit_step,
159 tagcache_get_max_commit_step());
161 else
163 gui_syncsplash(0, str(LANG_BUILDING_DATABASE),
164 stat->processed_entries);
168 if (!tagcache_is_usable())
169 return GO_TO_PREVIOUS;
170 filter = SHOW_ID3DB;
171 tc->dirlevel = last_db_dirlevel;
172 tc->selected_item = last_db_selection;
173 break;
174 #endif
175 case GO_TO_BROWSEPLUGINS:
176 filter = SHOW_PLUGINS;
177 snprintf(folder, MAX_PATH, "%s/", PLUGIN_DIR);
178 break;
180 ret_val = rockbox_browse(folder, filter);
181 switch ((intptr_t)param)
183 case GO_TO_FILEBROWSER:
184 get_current_file(last_folder, MAX_PATH);
185 break;
186 #ifdef HAVE_TAGCACHE
187 case GO_TO_DBBROWSER:
188 last_db_dirlevel = tc->dirlevel;
189 last_db_selection = tc->selected_item;
190 break;
191 #endif
193 return ret_val;
196 static int menu(void* param)
198 (void)param;
199 return do_menu(NULL, 0);
202 #ifdef HAVE_RECORDING
203 static int recscrn(void* param)
205 (void)param;
206 recording_screen(false);
207 return GO_TO_ROOT;
209 #endif
210 static int wpsscrn(void* param)
212 int ret_val = GO_TO_PREVIOUS;
213 (void)param;
214 if (audio_status())
216 ret_val = gui_wps_show();
218 else if ( global_status.resume_index != -1 )
220 DEBUGF("Resume index %X offset %lX\n",
221 global_status.resume_index,
222 (unsigned long)global_status.resume_offset);
223 if (playlist_resume() != -1)
225 playlist_start(global_status.resume_index,
226 global_status.resume_offset);
227 ret_val = gui_wps_show();
230 else
232 gui_syncsplash(HZ*2, str(LANG_NOTHING_TO_RESUME));
234 #if LCD_DEPTH > 1
235 show_main_backdrop();
236 #endif
237 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
238 show_remote_main_backdrop();
239 #endif
240 return ret_val;
242 #if CONFIG_TUNER
243 static int radio(void* param)
245 (void)param;
246 radio_screen();
247 return GO_TO_ROOT;
249 #endif
251 static int load_bmarks(void* param)
253 (void)param;
254 bookmark_mrb_load();
255 return GO_TO_PREVIOUS;
257 /* These are all static const'd from apps/menus/ *.c
258 so little hack so we can use them */
259 extern struct menu_item_ex
260 file_menu,
261 #ifdef HAVE_TAGCACHE
262 tagcache_menu,
263 #endif
264 manage_settings,
265 recording_setting_menu,
266 bookmark_settings_menu,
267 system_menu;
268 static const struct root_items items[] = {
269 [GO_TO_FILEBROWSER] = { browser, (void*)GO_TO_FILEBROWSER, &file_menu},
270 #ifdef HAVE_TAGCACHE
271 [GO_TO_DBBROWSER] = { browser, (void*)GO_TO_DBBROWSER, &tagcache_menu },
272 #endif
273 [GO_TO_WPS] = { wpsscrn, NULL, &playback_menu_item },
274 [GO_TO_MAINMENU] = { menu, NULL, &manage_settings },
276 #ifdef HAVE_RECORDING
277 [GO_TO_RECSCREEN] = { recscrn, NULL, &recording_setting_menu },
278 #endif
280 #if CONFIG_TUNER
281 [GO_TO_FM] = { radio, NULL, NULL },
282 #endif
284 [GO_TO_RECENTBMARKS] = { load_bmarks, NULL, &bookmark_settings_menu },
285 [GO_TO_BROWSEPLUGINS] = { browser, (void*)GO_TO_BROWSEPLUGINS, NULL },
288 static const int nb_items = sizeof(items)/sizeof(*items);
290 int item_callback(int action, const struct menu_item_ex *this_item) ;
292 MENUITEM_RETURNVALUE(file_browser, ID2P(LANG_DIR_BROWSER), GO_TO_FILEBROWSER,
293 NULL, Icon_file_view_menu);
294 #ifdef HAVE_TAGCACHE
295 MENUITEM_RETURNVALUE(db_browser, ID2P(LANG_TAGCACHE), GO_TO_DBBROWSER,
296 NULL, Icon_Audio);
297 #endif
298 MENUITEM_RETURNVALUE(rocks_browser, ID2P(LANG_PLUGINS), GO_TO_BROWSEPLUGINS,
299 NULL, Icon_Plugin);
300 char *get_wps_item_name(int selected_item, void * data, char *buffer)
302 (void)selected_item; (void)data; (void)buffer;
303 if (audio_status())
304 return ID2P(LANG_NOW_PLAYING);
305 return ID2P(LANG_RESUME_PLAYBACK);
307 MENUITEM_RETURNVALUE_DYNTEXT(wps_item, GO_TO_WPS, NULL, get_wps_item_name,
308 NULL, Icon_Playback_menu);
309 #ifdef HAVE_RECORDING
310 MENUITEM_RETURNVALUE(rec, ID2P(LANG_RECORDING_MENU), GO_TO_RECSCREEN,
311 NULL, Icon_Recording);
312 #endif
313 #if CONFIG_TUNER
314 MENUITEM_RETURNVALUE(fm, ID2P(LANG_FM_RADIO), GO_TO_FM,
315 item_callback, Icon_Radio_screen);
316 #endif
317 MENUITEM_RETURNVALUE(menu_, ID2P(LANG_SETTINGS_MENU), GO_TO_MAINMENU,
318 NULL, Icon_Submenu_Entered);
319 MENUITEM_RETURNVALUE(bookmarks, ID2P(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS),
320 GO_TO_RECENTBMARKS, item_callback,
321 Icon_Bookmark);
322 #ifdef HAVE_LCD_CHARCELLS
323 static int do_shutdown(void)
325 #if CONFIG_CHARGING
326 if (charger_inserted())
327 charging_splash();
328 else
329 #endif
330 sys_poweroff();
331 return 0;
333 MENUITEM_FUNCTION(do_shutdown_item, 0, ID2P(LANG_SHUTDOWN),
334 do_shutdown, NULL, NULL, Icon_NOICON);
335 #endif
336 MAKE_MENU(root_menu_, ID2P(LANG_ROCKBOX_TITLE),
337 NULL, Icon_Rockbox,
338 &bookmarks, &file_browser,
339 #ifdef HAVE_TAGCACHE
340 &db_browser,
341 #endif
342 &wps_item, &menu_,
343 #ifdef HAVE_RECORDING
344 &rec,
345 #endif
346 #if CONFIG_TUNER
347 &fm,
348 #endif
349 &playlist_options, &rocks_browser, &info_menu
351 #ifdef HAVE_LCD_CHARCELLS
352 ,&do_shutdown_item
353 #endif
356 int item_callback(int action, const struct menu_item_ex *this_item)
358 switch (action)
360 case ACTION_REQUEST_MENUITEM:
361 #if CONFIG_TUNER
362 if (this_item == &fm)
364 if (radio_hardware_present() == 0)
365 return ACTION_EXIT_MENUITEM;
367 else
368 #endif
369 if (this_item == &bookmarks)
371 if (global_settings.usemrb == 0)
372 return ACTION_EXIT_MENUITEM;
374 break;
376 return action;
378 static int get_selection(int last_screen)
380 unsigned int i;
381 for(i=0; i< sizeof(root_menu__)/sizeof(*root_menu__); i++)
383 if (((root_menu__[i]->flags&MENU_TYPE_MASK) == MT_RETURN_VALUE) &&
384 (root_menu__[i]->value == last_screen))
386 return i;
389 return 0;
392 static inline int load_screen(int screen)
394 /* set the global_status.last_screen before entering,
395 if we dont we will always return to the wrong screen on boot */
396 int old_previous = last_screen;
397 int ret_val;
398 if (screen <= GO_TO_ROOT)
399 return screen;
400 if (screen == old_previous)
401 old_previous = GO_TO_ROOT;
402 global_status.last_screen = (char)screen;
403 status_save();
404 action_signalscreenchange();
405 ret_val = items[screen].function(items[screen].param);
406 last_screen = screen;
407 if (ret_val == GO_TO_PREVIOUS)
408 last_screen = old_previous;
409 return ret_val;
411 static int load_context_screen(int selection)
413 const struct menu_item_ex *context_menu = NULL;
414 if ((root_menu__[selection]->flags&MENU_TYPE_MASK) == MT_RETURN_VALUE)
416 int item = root_menu__[selection]->value;
417 context_menu = items[item].context_menu;
419 /* special cases */
420 else if (root_menu__[selection] == &info_menu)
422 context_menu = &system_menu;
425 if (context_menu)
426 return do_menu(context_menu, NULL);
427 else
428 return GO_TO_PREVIOUS;
430 void root_menu(void)
432 int previous_browser = GO_TO_FILEBROWSER;
433 int previous_music = GO_TO_WPS;
434 int next_screen = GO_TO_ROOT;
435 int selected = 0;
437 if (global_settings.start_in_screen == 0)
438 next_screen = (int)global_status.last_screen;
439 else next_screen = global_settings.start_in_screen - 2;
441 #ifdef HAVE_RTC_ALARM
442 if ( rtc_check_alarm_started(true) )
444 rtc_enable_alarm(false);
445 next_screen = GO_TO_WPS;
446 #if CONFIG_TUNER
447 if (global_settings.alarm_wake_up_screen == ALARM_START_FM)
448 next_screen = GO_TO_FM;
449 #endif
450 #ifdef HAVE_RECORDING
451 if (global_settings.alarm_wake_up_screen == ALARM_START_REC)
453 recording_start_automatic = true;
454 next_screen = GO_TO_RECSCREEN;
456 #endif
458 #endif /* HAVE_RTC_ALARM */
460 #ifdef HAVE_HEADPHONE_DETECTION
461 if (next_screen == GO_TO_WPS &&
462 (global_settings.unplug_autoresume && !headphones_inserted() ))
463 next_screen = GO_TO_ROOT;
464 #endif
466 while (true)
468 switch (next_screen)
470 case MENU_ATTACHED_USB:
471 case MENU_SELECTED_EXIT:
472 /* fall through */
473 case GO_TO_ROOT:
474 if (last_screen != GO_TO_ROOT)
475 selected = get_selection(last_screen);
476 next_screen = do_menu(&root_menu_, &selected);
477 if (next_screen != GO_TO_PREVIOUS)
478 last_screen = GO_TO_ROOT;
479 break;
481 case GO_TO_PREVIOUS:
482 next_screen = last_screen;
483 break;
485 case GO_TO_PREVIOUS_BROWSER:
486 next_screen = previous_browser;
487 break;
489 case GO_TO_PREVIOUS_MUSIC:
490 next_screen = previous_music;
491 break;
492 case GO_TO_ROOTITEM_CONTEXT:
493 next_screen = load_context_screen(selected);
494 break;
495 default:
496 if (next_screen == GO_TO_FILEBROWSER
497 #ifdef HAVE_TAGCACHE
498 || next_screen == GO_TO_DBBROWSER
499 #endif
501 previous_browser = next_screen;
502 if (next_screen == GO_TO_WPS
503 #if CONFIG_TUNER
504 || next_screen == GO_TO_FM
505 #endif
507 previous_music = next_screen;
508 next_screen = load_screen(next_screen);
509 break;
510 } /* switch() */
512 return;