From 27ad51fb15d6ba753ee8f7d7d9dafd43d20e6551 Mon Sep 17 00:00:00 2001 From: Jonathan Gordon Date: Mon, 9 Oct 2006 10:54:17 +0000 Subject: [PATCH] Adds random folder advance option. RESETS SETTINGS. Refer to random_folder_advance_config wiki page for more info git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11158 a1c6a512-1295-4272-9138-f99709370657 --- apps/lang/english.lang | 13 + apps/playlist.c | 23 ++ apps/plugins/SOURCES | 1 + apps/plugins/random_folder_advance_config.c | 319 ++++++++++++++++++++ apps/settings.c | 4 +- apps/settings.h | 6 +- apps/settings_menu.c | 9 +- 7 files changed, 371 insertions(+), 4 deletions(-) create mode 100644 apps/plugins/random_folder_advance_config.c diff --git a/apps/lang/english.lang b/apps/lang/english.lang index f93ce0a0ac..eee33b7d08 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -9927,3 +9927,16 @@ *: "Korea" + + id: LANG_RANOOM + desc: random folder + + *: "Random" + + + *: "Random" + + + *: "Random" + + diff --git a/apps/playlist.c b/apps/playlist.c index 9d844e3b84..5a5313b736 100644 --- a/apps/playlist.c +++ b/apps/playlist.c @@ -1313,6 +1313,29 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion) struct tree_context* tc = tree_get_context(); int dirfilter = *(tc->dirfilter); + if (global_settings.next_folder == FOLDER_ADVANCE_RANDOM) + { + int fd = open(ROCKBOX_DIR "/folder_advance_list.dat",O_RDONLY); + char buffer[MAX_PATH]; + int folder_count = 0,i; + srand(current_tick); + if (fd >= 0) + { + read(fd,&folder_count,sizeof(int)); + while (!exit) + { + i = rand()%folder_count; + lseek(fd,sizeof(int) + (MAX_PATH*i),SEEK_SET); + read(fd,buffer,MAX_PATH); + if (check_subdir_for_music(buffer,"") ==0) + exit = true; + } + strcpy(dir,buffer); + close(fd); + return 0; + } + } + /* not random folder advance */ if (recursion){ /* start with root */ dir[0] = '\0'; diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index d2ccf81f62..b0e5f70e0a 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -9,6 +9,7 @@ firmware_flash.c logo.c metronome.c mosaique.c +random_folder_advance_config.c #if (LCD_WIDTH != 240) && ((LCD_WIDTH != 128) || (LCD_HEIGHT != 64)) rockblox.c #endif diff --git a/apps/plugins/random_folder_advance_config.c b/apps/plugins/random_folder_advance_config.c new file mode 100644 index 0000000000..033232a29e --- /dev/null +++ b/apps/plugins/random_folder_advance_config.c @@ -0,0 +1,319 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Jonathan Gordon + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "plugin.h" + +PLUGIN_HEADER + +static struct plugin_api* rb; +static bool abort; +static int fd; +static int dirs_count; +static int lasttick; +#define RFA_FILE ROCKBOX_DIR "/folder_advance_list.dat" +char *buffer = NULL; +int buffer_size; +struct file_format { + int count; + char folder[][MAX_PATH]; +}; +struct file_format *list = NULL; +#if CONFIG_KEYPAD == PLAYER_PAD + +#elif (CONFIG_KEYPAD == RECORDER_PAD) \ + || (CONFIG_KEYPAD == ONDIO_PAD) + +#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) \ + || (CONFIG_KEYPAD == IRIVER_H300_PAD) + +#elif (CONFIG_KEYPAD == IPOD_4G_PAD) \ + || (CONFIG_KEYPAD == IPOD_3G_PAD) + +#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD + +#elif CONFIG_KEYPAD == IAUDIO_X5_PAD + +#elif CONFIG_KEYPAD == GIGABEAT_PAD + +#elif CONFIG_KEYPAD == IRIVER_H10_PAD + +#endif + +void update_screen(void) +{ + char buf[15]; + int i; + FOR_NB_SCREENS(i) + { + rb->snprintf(buf,15,"Folders: %d",dirs_count); + rb->screens[i]->clear_display(); + rb->screens[i]->putsxy(0,0,buf); + rb->screens[i]->update(); + } +} + +void traversedir(char* location, char* name) +{ + struct dirent *entry; + DIR* dir; + char fullpath[MAX_PATH]; + bool check = false; + + rb->snprintf(fullpath, sizeof(fullpath), "%s/%s", location, name); + dir = rb->opendir(fullpath); + if (dir) { + entry = rb->readdir(dir); + while (entry) { + if (abort == true) + break; + /* Skip .. and . */ + if (entry->d_name[0] == '.') + { + if ( !rb->strcmp(entry->d_name,".") + || !rb->strcmp(entry->d_name,"..") + || !rb->strcmp(entry->d_name,".rockbox")) + check = false; + else check = true; + } + else check = true; + + if (check) + { + if (entry->attribute & ATTR_DIRECTORY) { + char *start, path[MAX_PATH]; + dirs_count++; + rb->snprintf(path,MAX_PATH,"%s/%s",fullpath,entry->d_name); + start = &path[rb->strlen(path)]; + rb->memset(start,0,&path[MAX_PATH-1]-start); + rb->write(fd,path,MAX_PATH); + traversedir(fullpath, entry->d_name); + } + } + if (*rb->current_tick - lasttick > (HZ/2)) { + update_screen(); + lasttick = *rb->current_tick; + if (rb->action_userabort(TIMEOUT_NOBLOCK)) + { + abort = true; + break; + } + } + + entry = rb->readdir(dir); + } + rb->closedir(dir); + } +} +void generate(void) +{ + dirs_count = 0; + abort = false; + fd = rb->open(RFA_FILE,O_CREAT|O_WRONLY); + rb->write(fd,&dirs_count,sizeof(int)); + if (fd < 0) + { + rb->splash(HZ, true, "Couldnt open %s", RFA_FILE); + return; + } + update_screen(); + lasttick = *rb->current_tick; + + traversedir("", ""); + rb->lseek(fd,0,SEEK_SET); + rb->write(fd,&dirs_count,sizeof(int)); + rb->close(fd); +} +char *list_get_name_cb(int selected_item,void* data,char* buf) +{ + (void)data; + rb->strcpy(buf,list->folder[selected_item]); + return buf; +} + +void edit_list(void) +{ + struct gui_synclist lists; + bool exit = false; + int button,i; + int selection; + fd = rb->open(RFA_FILE,O_RDONLY); + if (fd < 0) + return; + buffer = rb->plugin_get_audio_buffer(&buffer_size); + if (!buffer) + return; + rb->read(fd,buffer,buffer_size); + rb->close(fd); + list = (struct file_format *)buffer; + + rb->gui_synclist_init(&lists,list_get_name_cb,0, false, 1); + rb->gui_synclist_set_icon_callback(&lists,NULL); + rb->gui_synclist_set_nb_items(&lists,list->count); + rb->gui_synclist_limit_scroll(&lists,true); + rb->gui_synclist_select_item(&lists, 0); + + while (!exit) + { + rb->gui_synclist_draw(&lists); + rb->lcd_update(); + button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); + if (rb->gui_synclist_do_button(&lists,button)) + continue; + selection = rb->gui_synclist_get_sel_pos(&lists); + switch (button) + { + case ACTION_STD_OK: + list->folder[selection][0] = ' '; + list->folder[selection][1] = '\0'; + break; + case ACTION_STD_CONTEXT: + { + int m, len; + static const struct menu_item items[] = { + { "Remove Folder", NULL }, + { "Remove Folder Tree", NULL }, + }; + m = rb->menu_init(items, sizeof(items) / sizeof(*items), + NULL, NULL, NULL, NULL); + + switch (rb->menu_show(m)) + { + case 0: + list->folder[selection][0] = ' '; + list->folder[selection][1] = '\0'; + break; + case 1: + { + char temp[MAX_PATH]; + rb->strcpy(temp,list->folder[selection]); + len = rb->strlen(temp); + for (i=0;icount;i++) + { + if (!rb->strncmp(list->folder[i],temp,len)) + { + list->folder[i][0] = ' '; + list->folder[i][1] = '\0'; + } + } + } + break; + } + rb->menu_exit(m); + } + break; + case ACTION_STD_CANCEL: + { + int m; + static const struct menu_item items[] = { + { "Save and Exit", NULL }, + { "Ignore Changes and Exit", NULL }, + }; + m = rb->menu_init(items, sizeof(items) / sizeof(*items), + NULL, NULL, NULL, NULL); + + switch (rb->menu_show(m)) + { + case 0: + exit = true; + rb->splash(HZ*2, true, "Saving " RFA_FILE); + fd = rb->open(RFA_FILE, O_CREAT|O_WRONLY); + if (fd < 0) + { + rb->splash(HZ, true, "Could Not Open " RFA_FILE); + break; + } + dirs_count = 0; + rb->write(fd,&dirs_count,sizeof(int)); + for (i=0;icount;i++) + { + if (list->folder[i][0] != ' ') + { + dirs_count++; + rb->write(fd,list->folder[i],MAX_PATH); + } + } + rb->lseek(fd,0,SEEK_SET); + rb->write(fd,&dirs_count,sizeof(int)); + rb->close(fd); + case 1: + exit = true; + } + rb->menu_exit(m); + } + break; + } + } +} +int main_menu(void) +{ + int m; + static const struct menu_item items[] = { + { "Generate Folder List", NULL }, + { "Edit Folder List", NULL }, + { "Quit", NULL }, + }; + m = rb->menu_init(items, sizeof(items) / sizeof(*items), + NULL, NULL, NULL, NULL); + + switch (rb->menu_show(m)) + { + case 0: /* generate */ +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); +#endif + generate(); +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); +#endif +#ifdef HAVE_REMOTE_LCD + rb->remote_backlight_on(); +#endif + rb->backlight_on(); + break; + case 1: +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); +#endif + edit_list(); +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); +#endif +#ifdef HAVE_REMOTE_LCD + rb->remote_backlight_on(); +#endif + rb->backlight_on(); + break; + case 2: + rb->menu_exit(m); + return 1; + } + rb->menu_exit(m); + return 0; +} + +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + (void)parameter; + + rb = api; + abort = false; + + while (!main_menu()) + ; + return PLUGIN_OK; +} diff --git a/apps/settings.c b/apps/settings.c index ebe0d1e4cd..63f85f0608 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -96,7 +96,7 @@ const char rec_base_directory[] = REC_BASE_DIR; #include "eq_menu.h" #endif -#define CONFIG_BLOCK_VERSION 52 +#define CONFIG_BLOCK_VERSION 53 #define CONFIG_BLOCK_SIZE 512 #define RTC_BLOCK_SIZE 44 @@ -544,7 +544,7 @@ static const struct bit_entry hd_bits[] = {1, S_O(spdif_enable), false, "spdif enable", off_on}, #endif - {1, S_O(next_folder), false, "folder navigation", off_on }, + {2, S_O(next_folder), false, "folder navigation", "off,on,random" }, {1, S_O(runtimedb), false, "gather runtime data", off_on }, #if CONFIG_CODEC == SWCODEC diff --git a/apps/settings.h b/apps/settings.h index b29a219733..5313fe37b1 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -80,6 +80,10 @@ extern const char * const trig_durations[TRIG_DURATION_COUNT]; #define CROSSFADE_ENABLE_SHUFFLE 1 #define CROSSFADE_ENABLE_ALWAYS 2 +#define FOLDER_ADVANCE_OFF 0 +#define FOLDER_ADVANCE_NEXT 1 +#define FOLDER_ADVANCE_RANDOM 2 + /* These define "virtual pointers", which could either be a literal string, or a mean a string ID if the pointer is in a certain range. This helps to save space for menus and options. */ @@ -363,7 +367,7 @@ struct user_settings #endif #endif /* HAVE_REMOTE_LCD */ - bool next_folder; /* move to next folder */ + int next_folder; /* move to next folder */ bool runtimedb; /* runtime database active? */ #if CONFIG_CODEC == SWCODEC diff --git a/apps/settings_menu.c b/apps/settings_menu.c index b2d261492e..9c19f19fb1 100644 --- a/apps/settings_menu.c +++ b/apps/settings_menu.c @@ -1377,7 +1377,14 @@ static bool id3_order(void) static bool next_folder(void) { - return set_bool( str(LANG_NEXT_FOLDER), &global_settings.next_folder ); + static const struct opt_items names[] = { + { STR(LANG_SET_BOOL_NO) }, + { STR(LANG_SET_BOOL_YES) }, + { STR(LANG_RANOOM) }, + }; + return set_option(str(LANG_NEXT_FOLDER), + &global_settings.next_folder, + INT, names, 3, NULL ); } static bool codepage_setting(void)