diff --git a/apps/filetree.c b/apps/filetree.c index 1dc510f8c7..6fb0ed5469 100644 --- a/apps/filetree.c +++ b/apps/filetree.c @@ -269,12 +269,16 @@ int ft_load(struct tree_context* c, const char* tempdir) { int i; int name_buffer_used = 0; + bool (*callback_show_item)(char *, int, struct tree_context *) = NULL; DIR *dir; if (tempdir) dir = opendir(tempdir); else + { dir = opendir(c->currdir); + callback_show_item = c->browse? c->browse->callback_show_item: NULL; + } if(!dir) return -1; /* not a directory */ @@ -351,7 +355,8 @@ int ft_load(struct tree_context* c, const char* tempdir) (*c->dirfilter == SHOW_LNG && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_LNG) || (*c->dirfilter == SHOW_MOD && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_MOD) || (*c->dirfilter == SHOW_PLUGINS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_ROCK && - (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_LUA)) + (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_LUA) || + (callback_show_item && !callback_show_item(entry->d_name, dptr->attr, c))) { i--; continue; diff --git a/apps/menus/theme_menu.c b/apps/menus/theme_menu.c index 983eca9445..b483a7ef11 100644 --- a/apps/menus/theme_menu.c +++ b/apps/menus/theme_menu.c @@ -246,9 +246,85 @@ static struct browse_folder_info themes = {THEME_DIR, SHOW_CFG}; int browse_folder(void *param) { + const char *ext, *setting; + int lang_id = -1; + char selected[MAX_FILENAME+10]; const struct browse_folder_info *info = (const struct browse_folder_info*)param; - return rockbox_browse(info->dir, info->show_options); + struct browse_context browse; + browse_context_init(&browse, info->show_options, 0, + NULL, NOICON, info->dir, NULL); + + /* if we are in a special settings folder, center the current setting */ + switch(info->show_options) + { + case SHOW_LNG: + ext = "lng"; + if (global_settings.lang_file[0]) + setting = global_settings.lang_file; + else + setting = "english"; + lang_id = LANG_LANGUAGE; + break; + case SHOW_WPS: + ext = "wps"; + setting = global_settings.wps_file; + lang_id = LANG_WHILE_PLAYING; + break; +#ifdef HAVE_LCD_BITMAP + case SHOW_FONT: + ext = "fnt"; + setting = global_settings.font_file; + lang_id = LANG_CUSTOM_FONT; + break; + case SHOW_SBS: + ext = "sbs"; + setting = global_settings.sbs_file; + lang_id = LANG_BASE_SKIN; + break; +#if CONFIG_TUNER + case SHOW_FMS: + ext = "fms"; + setting = global_settings.fms_file; + lang_id = LANG_RADIOSCREEN; + break; +#endif /* CONFIG_TUNER */ +#endif +#ifdef HAVE_REMOTE_LCD + case SHOW_RWPS: + ext = "rwps"; + setting = global_settings.rwps_file; + lang_id = LANG_REMOTE_WHILE_PLAYING; + break; + case SHOW_RSBS: + ext = "rsbs"; + setting = global_settings.rsbs_file; + lang_id = LANG_REMOTE_BASE_SKIN; + break; +#if CONFIG_TUNER + case SHOW_RFMS: + ext = "rfms"; + setting = global_settings.rfms_file; + lang_id = LANG_REMOTE_RADIOSCREEN; + break; +#endif /* CONFIG_TUNER */ +#endif + default: + ext = setting = NULL; + break; + } + + /* If we've found a file to center on, do it */ + if (setting) + { + /* if setting != NULL, ext is initialized */ + snprintf(selected, sizeof(selected), "%s.%s", setting, ext); + browse.selected = selected; + browse.icon = Icon_Questionmark; + browse.title = str(lang_id); + } + + return rockbox_browse(&browse); } #ifdef HAVE_LCD_BITMAP diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c index 4ef139a526..fc4621a805 100644 --- a/apps/plugins/rockpaint.c +++ b/apps/plugins/rockpaint.c @@ -731,6 +731,7 @@ static bool browse( char *dst, int dst_size, const char *start ) } rb->strcpy( a+1, dc[tree->selected_item].name ); tree->dirfilter = &dirfilter; + tree->browse = NULL; while( 1 ) { if( reload ) @@ -880,6 +881,7 @@ static bool browse_fonts( char *dst, int dst_size ) } rb->strcpy( a+1, dc[tree->selected_item].name ); tree->dirfilter = &dirfilter; + tree->browse = NULL; rb->strcpy( bbuf, FONT_DIR "/" ); rb->set_current_file( bbuf ); diff --git a/apps/plugins/text_viewer/tv_menu.c b/apps/plugins/text_viewer/tv_menu.c index 1d1e07f3e8..5e79fd469a 100644 --- a/apps/plugins/text_viewer/tv_menu.c +++ b/apps/plugins/text_viewer/tv_menu.c @@ -234,6 +234,7 @@ static bool tv_font_setting(void) rb->strlcat(backup.currdir, "/", MAX_PATH); rb->strlcat(backup.currdir, dc[tree->selected_item].name, MAX_PATH); tree->dirfilter = &dirfilter; + tree->browse = NULL; rb->snprintf(font_path, MAX_PATH, "%s/", FONT_DIR); rb->set_current_file(font_path); count = tree->filesindir; diff --git a/apps/radio/presets.c b/apps/radio/presets.c index e900afe734..9c6fedecc7 100644 --- a/apps/radio/presets.c +++ b/apps/radio/presets.c @@ -353,7 +353,13 @@ static int radio_delete_preset(void) int preset_list_load(void) { - return !rockbox_browse(FMPRESET_PATH, SHOW_FMR); + char selected[MAX_PATH]; + struct browse_context browse; + snprintf(selected, sizeof(selected), "%s.%s", global_settings.fmr_file, "fmr"); + browse_context_init(&browse, SHOW_FMR, 0, + str(LANG_FM_PRESET_LOAD), NOICON, + FMPRESET_PATH, selected); + return !rockbox_browse(&browse); } int preset_list_save(void) diff --git a/apps/root_menu.c b/apps/root_menu.c index a65ceb51b9..27242c9797 100644 --- a/apps/root_menu.c +++ b/apps/root_menu.c @@ -96,6 +96,7 @@ static int browser(void* param) #ifdef HAVE_TAGCACHE struct tree_context* tc = tree_get_context(); #endif + struct browse_context browse; int filter = SHOW_SUPPORTED; char folder[MAX_PATH] = "/"; /* stuff needed to remember position in file browser */ @@ -104,7 +105,7 @@ static int browser(void* param) #ifdef HAVE_TAGCACHE static int last_db_dirlevel = 0, last_db_selection = 0; #endif - + switch ((intptr_t)param) { case GO_TO_FILEBROWSER: @@ -247,12 +248,10 @@ static int browser(void* param) tc->selected_item = last_db_selection; break; #endif - case GO_TO_BROWSEPLUGINS: - filter = SHOW_PLUGINS; - strlcpy(folder, PLUGIN_DIR, MAX_PATH); - break; } - ret_val = rockbox_browse(folder, filter); + + browse_context_init(&browse, filter, 0, NULL, NOICON, folder, NULL); + ret_val = rockbox_browse(&browse); switch ((intptr_t)param) { case GO_TO_FILEBROWSER: @@ -352,8 +351,11 @@ static int plugins_menu(void* param) ID2P(LANG_PLUGIN_GAMES), ID2P(LANG_PLUGIN_APPS), ID2P(LANG_PLUGIN_DEMOS)); const char *folder; + struct browse_context browse; + char *title; int retval = GO_TO_PREVIOUS; int selection = 0, current = 0; + while (retval == GO_TO_PREVIOUS) { selection = do_menu(&plugins_menu_items, ¤t, NULL, false); @@ -361,17 +363,22 @@ static int plugins_menu(void* param) { case 0: folder = PLUGIN_GAMES_DIR; + title = str(LANG_PLUGIN_GAMES); break; case 1: folder = PLUGIN_APPS_DIR; + title = str(LANG_PLUGIN_APPS); break; case 2: folder = PLUGIN_DEMOS_DIR; + title = str(LANG_PLUGIN_DEMOS); break; default: return selection; } - retval = rockbox_browse(folder, SHOW_PLUGINS); + browse_context_init(&browse, SHOW_PLUGINS, 0, + title, Icon_Plugin, folder, NULL); + retval = rockbox_browse(&browse); } return retval; } diff --git a/apps/tree.c b/apps/tree.c index 98880f001a..b0e94bf936 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -417,18 +417,12 @@ static int update_dir(void) #endif { #ifdef HAVE_LCD_BITMAP - if (global_settings.show_path_in_browser && - *(tc.dirfilter) == SHOW_PLUGINS) + if (tc.browse && tc.browse->title) { - char *title; - if (!strcmp(tc.currdir, PLUGIN_GAMES_DIR)) - title = str(LANG_PLUGIN_GAMES); - else if (!strcmp(tc.currdir, PLUGIN_APPS_DIR)) - title = str(LANG_PLUGIN_APPS); - else if (!strcmp(tc.currdir, PLUGIN_DEMOS_DIR)) - title = str(LANG_PLUGIN_DEMOS); - else title = str(LANG_PLUGINS); - gui_synclist_set_title(&tree_lists, title, Icon_Plugin); + int icon = tc.browse->icon; + if (icon == NOICON) + icon = filetype_get_icon(ATTR_DIRECTORY); + gui_synclist_set_title(&tree_lists, tc.browse->title, icon); } else if (global_settings.show_path_in_browser == SHOW_PATH_FULL) { @@ -616,7 +610,7 @@ void set_current_file(const char *path) /* main loop, handles key events */ -static int dirbrowse() +static int dirbrowse(void) { int numentries=0; char buf[MAX_PATH]; @@ -653,7 +647,7 @@ static int dirbrowse() if (*tc.dirfilter > NUM_FILTER_MODES && numentries==0) { splash(HZ*2, ID2P(LANG_NO_FILES)); - return GO_TO_PREVIOUS; /* No files found for rockbox_browser() */ + return GO_TO_PREVIOUS; /* No files found for rockbox_browse() */ } gui_synclist_draw(&tree_lists); @@ -683,6 +677,14 @@ static int dirbrowse() if ( numentries == 0 ) break; + if ((tc.browse->flags & BROWSE_SELECTONLY) && + !(dircache[tc.selected_item].attr & ATTR_DIRECTORY)) + { + tc.browse->flags |= BROWSE_SELECTED; + get_current_file(tc.browse->buf, tc.browse->bufsize); + return GO_TO_PREVIOUS; + } + #ifdef HAVE_TAGCACHE switch (id3db?tagtree_enter(&tc):ft_enter(&tc)) #else @@ -781,6 +783,11 @@ static int dirbrowse() int onplay_result; int attr = 0; + /* no context menu while in select only mode + to prevent recursive call */ + if ((tc.browse->flags & BROWSE_SELECTONLY)) + break; + if(!numentries) onplay_result = onplay(NULL, 0, curr_context, hotkey); else { @@ -924,108 +931,77 @@ bool create_playlist(void) return true; } -int rockbox_browse(const char *root, int dirfilter) +void browse_context_init(struct browse_context *browse, + int dirfilter, unsigned flags, + char *title, enum themable_icons icon, + const char *root, const char *selected) +{ + browse->dirfilter = dirfilter; + browse->flags = flags; + browse->callback_show_item = NULL; + browse->title = title; + browse->icon = icon; + browse->root = root; + browse->selected = selected; + browse->buf = NULL; + browse->bufsize = 0; +} + +#define NUM_TC_BACKUP 3 +static struct tree_context backups[NUM_TC_BACKUP]; +/* do not make backup if it is not recursive call */ +static int backup_count = -1; +int rockbox_browse(struct browse_context *browse) { static char current[MAX_PATH]; int ret_val = 0; - int *last_filter = tc.dirfilter; + int dirfilter = browse->dirfilter; + + if (backup_count >= NUM_TC_BACKUP) + return GO_TO_PREVIOUS; + if (backup_count >= 0) + backups[backup_count] = tc; + backup_count++; + tc.dirfilter = &dirfilter; tc.sort_dir = global_settings.sort_dir; - + reload_dir = true; - if (dirfilter >= NUM_FILTER_MODES) + if (*tc.dirfilter >= NUM_FILTER_MODES) { - static struct tree_context backup; int last_context; - const char *ext, *setting; - - backup = tc; + + tc.browse = browse; tc.selected_item = 0; tc.dirlevel = 0; - memcpy(tc.currdir, root, sizeof(tc.currdir)); + strlcpy(tc.currdir, browse->root, sizeof(tc.currdir)); start_wps = false; last_context = curr_context; - /* if we are in a special settings folder, center the current setting */ - switch(dirfilter) + if (browse->selected) { - case SHOW_LNG: - ext = "lng"; - if (global_settings.lang_file[0]) - setting = global_settings.lang_file; - else - setting = "english"; - break; - case SHOW_WPS: - ext = "wps"; - setting = global_settings.wps_file; - break; -#ifdef HAVE_REMOTE_LCD - case SHOW_RWPS: - ext = "rwps"; - setting = global_settings.rwps_file; - break; - case SHOW_RSBS: - ext = "rsbs"; - setting = global_settings.rsbs_file; - break; -#if CONFIG_TUNER - case SHOW_RFMS: - ext = "rfms"; - setting = global_settings.rfms_file; - break; -#endif /* CONFIG_TUNER */ -#endif -#ifdef HAVE_LCD_BITMAP - case SHOW_FONT: - ext = "fnt"; - setting = global_settings.font_file; - break; - case SHOW_SBS: - ext = "sbs"; - setting = global_settings.sbs_file; - break; -#if CONFIG_TUNER - case SHOW_FMS: - ext = "fms"; - setting = global_settings.fms_file; - break; -#endif /* CONFIG_TUNER */ -#endif -#if CONFIG_TUNER - case SHOW_FMR: - ext = "fmr"; - setting = global_settings.fmr_file; - break; -#endif - default: - ext = setting = NULL; - break; - } - - /* If we've found a file to center on, do it */ - if (setting) - { - /* if setting != NULL, ext is initialized */ - snprintf(current, sizeof(current), "%s/%s.%s", root, setting, ext); + snprintf(current, sizeof(current), "%s/%s", + browse->root, browse->selected); set_current_file(current); /* set_current_file changes dirlevel, change it back */ tc.dirlevel = 0; } ret_val = dirbrowse(); - tc = backup; curr_context = last_context; } else { if (dirfilter != SHOW_ID3DB) tc.dirfilter = &global_settings.dirfilter; - strcpy(current,root); + tc.browse = browse; + strcpy(current, browse->root); set_current_file(current); ret_val = dirbrowse(); } - tc.dirfilter = last_filter; + backup_count--; + if (backup_count >= 0) + tc = backups[backup_count]; return ret_val; } diff --git a/apps/tree.h b/apps/tree.h index a74960f7a5..103a20eea6 100644 --- a/apps/tree.h +++ b/apps/tree.h @@ -24,6 +24,7 @@ #include #include #include +#include "icon.h" struct entry { short attr; /* FAT attributes + file type flags */ @@ -32,6 +33,26 @@ struct entry { }; +#define BROWSE_SELECTONLY 0x0001 /* exit on selecting a file */ +#define BROWSE_SELECTED 0x0100 /* this bit is set if user selected item */ + +struct tree_context; + +struct browse_context { + int dirfilter; + unsigned flags; /* ored BROWSE_* */ + bool (*callback_show_item)(char *name, int attr, struct tree_context *tc); + /* callback function to determine to show/hide + the item for custom browser */ + char *title; /* title of the browser. if set to NULL, + directory name is used. */ + enum themable_icons icon; /* title icon */ + const char *root; /* full path of start directory */ + const char *selected; /* name of selected file in the root */ + char *buf; /* buffer to store selected file */ + size_t bufsize; /* size of the buffer */ +}; + /* browser context for file or db */ struct tree_context { /* The directory we are browsing */ @@ -68,6 +89,7 @@ struct tree_context { int dentry_size; bool dirfull; int sort_dir; /* directory sort order */ + struct browse_context *browse; }; void tree_drawlists(void); @@ -76,7 +98,11 @@ void tree_gui_init(void) INIT_ATTR; char* get_current_file(char* buffer, size_t buffer_len); void set_dirfilter(int l_dirfilter); void set_current_file(const char *path); -int rockbox_browse(const char *root, int dirfilter); +void browse_context_init(struct browse_context *browse, + int dirfilter, unsigned flags, + char *title, enum themable_icons icon, + const char *root, const char *selected); +int rockbox_browse(struct browse_context *browse); bool create_playlist(void); void resume_directory(const char *dir); #ifdef WIN32