rendered paste bodystatic bool dirbrowse(void)
{
int numentries=0;
char buf[MAX_PATH];
int lasti = -1;
unsigned button, returned_button;
bool reload_root = false;
int lastfilter = *tc.dirfilter;
bool lastsortcase = global_settings.sort_case;
bool need_update = true;
bool exit_func = false;
long thumbnail_time = -1; /* for delaying a thumbnail */
char* currdir = tc.currdir; /* just a shortcut */
#ifdef HAVE_TAGCACHE
bool id3db = *tc.dirfilter == SHOW_ID3DB;
if (id3db)
curr_context=CONTEXT_ID3DB;
else
#endif
curr_context=CONTEXT_TREE;
tc.selected_item = 0;
tc.dirlevel=0;
tc.firstpos=0;
lasttable = -1;
lastextra = -1;
lastfirstpos = 0;
if (*tc.dirfilter < NUM_FILTER_MODES) {
#ifdef HAVE_RECORDING
#ifndef SIMULATOR
if (global_settings.rec_startup) {
/* We fake being in the menu structure by calling
the appropriate parent when we drop out of each screen */
#if CONFIG_CODEC == SWCODEC
/* Put in a 1 sec pause to slow bootup or the recording codecs
won't initialize */
sleep(HZ);
#endif
recording_screen(false);
rec_menu();
main_menu();
}
else
#endif
#endif
start_resume(true);
}
/* If we don't need to show the wps, draw the dir */
if (!start_wps) {
numentries = update_dir();
if (numentries == -1)
return false; /* currdir is not a directory */
if (*tc.dirfilter > NUM_FILTER_MODES && numentries==0)
{
gui_syncsplash(HZ*2, true, str(LANG_NO_FILES));
return false; /* No files found for rockbox_browser() */
}
}
while(1) {
struct entry *dircache = tc.dircache;
bool restore = false;
#ifdef BOOTFILE
if (boot_changed) {
char *lines[]={str(LANG_BOOT_CHANGED), str(LANG_REBOOT_NOW)};
struct text_message message={lines, 2};
if(gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES)
rolo_load("/" BOOTFILE);
restore = true;
boot_changed = false;
}
#endif
button = get_action(CONTEXT_TREE,HZ/5);
returned_button = gui_synclist_do_button(&tree_lists, button);
if (returned_button)
need_update = true;
if (returned_button == ACTION_STD_CANCEL)
button = ACTION_STD_CANCEL;
switch ( button ) {
case ACTION_STD_OK:
/* nothing to do if no files to display */
if ( numentries == 0 )
break;
#ifdef HAVE_TAGCACHE
switch (id3db?tagtree_enter(&tc):ft_enter(&tc))
{
case 1: reload_dir = true; break;
case 2: start_wps = true; break;
case 3: exit_func = true; break;
default: break;
}
restore = true;
break;
#endif
case ACTION_STD_CANCEL:
if (*tc.dirfilter > NUM_FILTER_MODES && tc.dirlevel < 1) {
exit_func = true;
break;
}
/* if we are in /, nothing to do */
if (tc.dirlevel == 0 && !strcmp(currdir,"/"))
break;
#ifdef HAVE_TAGCACHE
if (id3db)
tagtree_exit(&tc);
else
if (ft_exit(&tc) == 3)
exit_func = true;
restore = true;
break;
#endif
case ACTION_TREE_STOP:
if (*tc.dirfilter < NUM_FILTER_MODES)
{
/* Stop the music if it is playing */
if(audio_status()) {
if (!global_settings.party_mode) {
if (global_settings.fade_on_stop)
fade(0);
bookmark_autobookmark();
audio_stop();
}
}
#if defined(CONFIG_CHARGING) && \
(CONFIG_KEYPAD == RECORDER_PAD) && !defined(HAVE_SW_POWEROFF)
else {
if (!charger_inserted()) {
if(shutdown_screen())
reload_dir = true;
} else {
charging_splash();
}
restore = true;
}
#endif
}
#if defined(CONFIG_CHARGING) && !defined(HAVE_POWEROFF_WHILE_CHARGING)
{
static int last_off = 0;
if (current_tick - last_off < 50) {
if (charger_inserted()) {
charging_splash();
restore = true;
}
}
last_off = current_tick;
}
#endif
break; /* case ACTION_TREE_STOP: */
case ACTION_STD_MENU:
/* don't enter menu from plugin browser */
if (*tc.dirfilter < NUM_FILTER_MODES)
{
int i;
FOR_NB_SCREENS(i)
screens[i].stop_scroll();
action_signalscreenchange();
if (main_menu())
reload_dir = true;
restore = true;
#ifdef HAVE_TAGCACHE
id3db = check_changed_id3mode(id3db);
if(id3db)
reload_dir = true;
}
else /* use it as a quick exit instead */
exit_func = true;
break;
#endif
case ACTION_TREE_WPS:
/* don't enter wps from plugin browser etc */
if (*tc.dirfilter < NUM_FILTER_MODES)
{
if (audio_status() & AUDIO_STATUS_PLAY)
{
start_wps=true;
}
else
{
start_resume(false);
restore = true;
}
}
break;
#ifdef HAVE_QUICKSCREEN
case ACTION_STD_QUICKSCREEN:
/* don't enter f2 from plugin browser */
if (*tc.dirfilter < NUM_FILTER_MODES)
{
if (quick_screen_quick(button))
reload_dir = true;
restore = true;
#ifdef HAVE_TAGCACHE
id3db = check_changed_id3mode(id3db);
reload_dir = true;
}
break;
#endif
#endif
#ifdef BUTTON_F3
case ACTION_F3:
/* don't enter f3 from plugin browser */
if (*tc.dirfilter < NUM_FILTER_MODES)
{
if (quick_screen_f3(BUTTON_F3))
reload_dir = true;
restore = true;
}
break;
#endif
case ACTION_STD_CONTEXT:
{
int onplay_result;
int attr = 0;
if(!numentries)
onplay_result = onplay(NULL, 0, curr_context);
else {
#ifdef HAVE_TAGCACHE
if (id3db)
{
if (tagtree_get_attr(&tc) == TREE_ATTR_MPA)
{
attr = TREE_ATTR_MPA;
tagtree_get_filename(&tc, buf, sizeof(buf));
}
else
attr = ATTR_DIRECTORY;
}
else
#endif
{
attr = dircache[tc.selected_item].attr;
if (currdir[1]) /* Not in / */
snprintf(buf, sizeof buf, "%s/%s",
currdir,
dircache[tc.selected_item].name);
else /* In / */
snprintf(buf, sizeof buf, "/%s",
dircache[tc.selected_item].name);
}
onplay_result = onplay(buf, attr, curr_context);
}
switch (onplay_result)
{
case ONPLAY_OK:
restore = true;
break;
case ONPLAY_RELOAD_DIR:
reload_dir = true;
break;
case ONPLAY_START_PLAY:
start_wps = true;
break;
}
break;
}
case ACTION_NONE:
if (thumbnail_time != -1 &&
TIME_AFTER(current_tick, thumbnail_time))
{ /* a delayed hovering thumbnail is due now */
int res;
int attr;
char* name;
#ifdef HAVE_TAGCACHE
if (id3db)
{
attr = tagtree_get_attr(&tc);
name = tagtree_get_entry(&tc, lasti)->name;
}
else
#endif
{
attr = dircache[lasti].attr;
name = dircache[lasti].name;
}
if (attr & ATTR_DIRECTORY)
{
DEBUGF("Playing directory thumbnail: %s", currdir);
res = ft_play_dirname(name);
if (res < 0) /* failed, not existing */
{ /* say the number instead, as a fallback */
talk_id(VOICE_DIR, false);
talk_number(lasti+1, true);
}
}
else
{
DEBUGF("Playing file thumbnail: %s/%s%s\n",
currdir, name,
file_thumbnail_ext);
/* no fallback necessary, we knew in advance
that the file exists */
ft_play_filename(currdir, name);
}
thumbnail_time = -1; /* job done */
}
gui_syncstatusbar_draw(&statusbars, false);
break;
#ifdef HAVE_HOTSWAP
case SYS_FS_CHANGED:
if (!id3db)
reload_dir = true;
/* The 'dir no longer valid' situation will be caught later
* by checking the showdir() result. */
break;
#endif
default:
if (default_event_handler(button) == SYS_USB_CONNECTED)
{
if(*tc.dirfilter > NUM_FILTER_MODES)
/* leave sub-browsers after usb, doing otherwise
might be confusing to the user */
exit_func = true;
else
reload_dir = true;
}
break;
}
if ( button )
{
ata_spin();
}
if (start_wps && audio_status() )
{
int i;
FOR_NB_SCREENS(i)
screens[i].stop_scroll();
if (gui_wps_show() == SYS_USB_CONNECTED)
reload_dir = true;
#ifdef HAVE_HOTSWAP
else
if (!id3db) /* Try reload to catch 'no longer valid' case. */
reload_dir = true;
#endif
#ifdef HAVE_LCD_COLOR
show_main_backdrop();
#endif
#ifdef HAVE_TAGCACHE
id3db = check_changed_id3mode(id3db);
#endif
restore = true;
start_wps=false;
}
check_rescan:
/* do we need to rescan dir? */
if (reload_dir || reload_root ||
lastfilter != *tc.dirfilter ||
lastsortcase != global_settings.sort_case)
{
if ( reload_root ) {
strcpy(currdir, "/");
tc.dirlevel = 0;
tc.currtable = 0;
tc.currextra = 0;
lasttable = -1;
lastextra = -1;
reload_root = false;
}
if (! reload_dir )
{
gui_synclist_select_item(&tree_lists, 0);
gui_synclist_draw(&tree_lists);
tc.selected_item = 0;
lastdir[0] = 0;
}
lastfilter = *tc.dirfilter;
lastsortcase = global_settings.sort_case;
restore = true;
}
if (exit_func)
break;
if (restore || reload_dir) {
/* restore display */
numentries = update_dir();
if (currdir[1] && (numentries < 0))
{ /* not in root and reload failed */
reload_root = true; /* try root */
reload_dir = false;
goto check_rescan;
}
need_update = true;
reload_dir = false;
}
if(need_update) {
tc.selected_item = gui_synclist_get_sel_pos(&tree_lists);
need_update=false;
if ( numentries > 0 ) {
/* Voice the file if changed */
if(lasti != tc.selected_item || restore) {
int attr;
char* name;
lasti = tc.selected_item;
thumbnail_time = -1; /* Cancel whatever we were
about to say */
#ifdef HAVE_TAGCACHE
if (id3db)
{
attr = tagtree_get_attr(&tc);
name = tagtree_get_entry(&tc, tc.selected_item)->name;
}
else
#endif
{
attr = dircache[tc.selected_item].attr;
name = dircache[tc.selected_item].name;
}
/* Directory? */
if (attr & ATTR_DIRECTORY)
{
/* play directory thumbnail */
switch (global_settings.talk_dir) {
case 1: /* dirs as numbers */
talk_id(VOICE_DIR, false);
talk_number(tc.selected_item+1, true);
break;
case 2: /* dirs spelled */
talk_spell(name, false);
break;
case 3: /* thumbnail clip */
/* "schedule" a thumbnail, to have a little
delay */
thumbnail_time = current_tick + HOVER_DELAY;
break;
default:
break;
}
}
else /* file */
{
switch (global_settings.talk_file) {
case 1: /* files as numbers */
ft_play_filenumber(
tc.selected_item-tc.dirsindir+1,
attr & TREE_ATTR_MASK);
break;
case 2: /* files spelled */
talk_spell(name, false);
break;
case 3: /* thumbnail clip */
/* "schedule" a thumbnail, to have a little
delay */
if (attr & TREE_ATTR_THUMBNAIL)
thumbnail_time = current_tick + HOVER_DELAY;
else
/* spell the number as fallback */
talk_spell(name, false);
break;
default:
break;
}
}
}
}
}
}
action_signalscreenchange();
return true;
}
static int plsize = 0;
static long pltick;
static bool add_dir(char* dirname, int len, int fd)
{
bool abort = false;
DIRCACHED* dir;
/* check for user abort */
if (action_userabort(TIMEOUT_NOBLOCK))
return true;
dir = opendir_cached(dirname);
if(!dir)
return true;
while (true) {
struct dircache_entry *entry;
entry = readdir_cached(dir);
if (!entry)
break;
if (entry->attribute & ATTR_DIRECTORY) {
int dirlen = strlen(dirname);
bool result;
if (!strcmp((char *)entry->d_name, ".") ||
!strcmp((char *)entry->d_name, ".."))
continue;
if (dirname[1])
snprintf(dirname+dirlen, len-dirlen, "/%s", entry->d_name);
else
snprintf(dirname, len, "/%s", entry->d_name);
result = add_dir(dirname, len, fd);
dirname[dirlen] = '\0';
if (result) {
abort = true;
break;
}
}
else {
int x = strlen((char *)entry->d_name);
unsigned int i;
char *cp = strrchr((char *)entry->d_name,'.');
if (cp) {
cp++;
/* add all supported audio files to playlists */
for (i=0; i < sizeof(filetypes)/sizeof(struct filetype); i++) {
if (filetypes[i].tree_attr == TREE_ATTR_MPA) {
if (!strcasecmp(cp, filetypes[i].extension)) {
char buf[8];
int i;
write(fd, dirname, strlen(dirname));
write(fd, "/", 1);
write(fd, entry->d_name, x);
write(fd, "\n", 1);
plsize++;
if(TIME_AFTER(current_tick, pltick+HZ/4)) {
pltick = current_tick;
snprintf(buf, sizeof buf, "%d", plsize);
#ifdef HAVE_LCD_BITMAP
FOR_NB_SCREENS(i)
{
screens[i].puts(0, 4, (unsigned char *)buf);
gui_textarea_update(&screens[i]);
}
#else
x = 10;
if (plsize > 999)
x=7;
else {
if (plsize > 99)
x=8;
else {
if (plsize > 9)
x=9;
}
}
FOR_NB_SCREENS(i) {
screens[i].puts(x,0,buf);
}
#endif
}
break;
}
}
}
}
}
}
closedir_cached(dir);
return abort;
}