diff options
author | Björn Stenberg <bjorn@haxx.se> | 2005-01-17 11:39:46 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2005-01-17 11:39:46 +0000 |
commit | 8a5de5fec96171e739442b0601047d93079e3179 (patch) | |
tree | 5d0a66bea94f7296aaaacc6d42ceecb84e736242 /apps/tree.c | |
parent | fc53fd708fc12e1a67217c102ea8180b2bde6a6f (diff) | |
download | rockbox-8a5de5fec96171e739442b0601047d93079e3179.tar.gz rockbox-8a5de5fec96171e739442b0601047d93079e3179.zip |
Added ID3 database support. Still very early.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5575 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/tree.c')
-rw-r--r-- | apps/tree.c | 1221 |
1 files changed, 418 insertions, 803 deletions
diff --git a/apps/tree.c b/apps/tree.c index 9b4f6898de..eb1f7c3b74 100644 --- a/apps/tree.c +++ b/apps/tree.c | |||
@@ -57,18 +57,13 @@ | |||
57 | #include "talk.h" | 57 | #include "talk.h" |
58 | #include "filetypes.h" | 58 | #include "filetypes.h" |
59 | #include "misc.h" | 59 | #include "misc.h" |
60 | #include "filetree.h" | ||
61 | #include "dbtree.h" | ||
60 | 62 | ||
61 | #ifdef HAVE_LCD_BITMAP | 63 | #ifdef HAVE_LCD_BITMAP |
62 | #include "widgets.h" | 64 | #include "widgets.h" |
63 | #define BOOTFILE "ajbrec.ajz" | ||
64 | #else | ||
65 | #define BOOTFILE "archos.mod" | ||
66 | #endif | 65 | #endif |
67 | 66 | ||
68 | /* This flag is set by dirbrowse() if a new language is loaded. | ||
69 | It is defined in settings_menu.c */ | ||
70 | extern bool language_changed; | ||
71 | |||
72 | /* a table for the know file types */ | 67 | /* a table for the know file types */ |
73 | const struct filetype filetypes[] = { | 68 | const struct filetype filetypes[] = { |
74 | { ".mp3", TREE_ATTR_MPA, File, VOICE_EXT_MPA }, | 69 | { ".mp3", TREE_ATTR_MPA, File, VOICE_EXT_MPA }, |
@@ -92,33 +87,17 @@ const struct filetype filetypes[] = { | |||
92 | #endif /* #ifndef SIMULATOR */ | 87 | #endif /* #ifndef SIMULATOR */ |
93 | }; | 88 | }; |
94 | 89 | ||
95 | /* Boot value of global_settings.max_files_in_dir */ | 90 | static struct tree_context tc; |
96 | static int max_files_in_dir; | 91 | |
97 | 92 | bool boot_changed = false; | |
98 | static char *name_buffer; | 93 | |
99 | static int name_buffer_size; /* Size of allocated buffer */ | 94 | char lastfile[MAX_PATH]; |
100 | static int name_buffer_length; /* Currently used amount */ | 95 | char lastdir[MAX_PATH]; |
101 | 96 | ||
102 | static struct entry *dircache; | ||
103 | |||
104 | static int dircursor; | ||
105 | static int dirstart; | ||
106 | static int dirlevel; | ||
107 | static int filesindir; | ||
108 | static int dirsindir; /* how many of the dircache entries are directories */ | ||
109 | static int dirpos[MAX_DIR_LEVELS]; | ||
110 | static int cursorpos[MAX_DIR_LEVELS]; | ||
111 | static char lastdir[MAX_PATH]; | ||
112 | static char lastfile[MAX_PATH]; | ||
113 | static char currdir[MAX_PATH]; | ||
114 | static char currdir_save[MAX_PATH]; | ||
115 | static bool reload_dir = false; | 97 | static bool reload_dir = false; |
116 | static int boot_size = 0; | ||
117 | static int boot_cluster; | ||
118 | static bool boot_changed = false; | ||
119 | 98 | ||
120 | static bool start_wps = false; | 99 | static bool start_wps = false; |
121 | static bool dirbrowse(const char *root, const int *dirfilter); | 100 | static bool dirbrowse(void); |
122 | 101 | ||
123 | bool check_rockboxdir(void) | 102 | bool check_rockboxdir(void) |
124 | { | 103 | { |
@@ -140,11 +119,13 @@ void browse_root(void) | |||
140 | filetype_init(); | 119 | filetype_init(); |
141 | check_rockboxdir(); | 120 | check_rockboxdir(); |
142 | 121 | ||
122 | strcpy(tc.currdir, "/"); | ||
123 | |||
143 | #ifndef SIMULATOR | 124 | #ifndef SIMULATOR |
144 | dirbrowse("/", &global_settings.dirfilter); | 125 | dirbrowse(); |
145 | 126 | ||
146 | #else | 127 | #else |
147 | if (!dirbrowse("/", &global_settings.dirfilter)) { | 128 | if (!dirbrowse()) { |
148 | DEBUGF("No filesystem found. Have you forgotten to create it?\n"); | 129 | DEBUGF("No filesystem found. Have you forgotten to create it?\n"); |
149 | } | 130 | } |
150 | #endif | 131 | #endif |
@@ -156,11 +137,16 @@ void tree_get_filetypes(const struct filetype** types, int* count) | |||
156 | *count = sizeof(filetypes) / sizeof(*filetypes); | 137 | *count = sizeof(filetypes) / sizeof(*filetypes); |
157 | } | 138 | } |
158 | 139 | ||
140 | struct tree_context* tree_get_context(void) | ||
141 | { | ||
142 | return &tc; | ||
143 | } | ||
144 | |||
159 | #ifdef HAVE_LCD_BITMAP | 145 | #ifdef HAVE_LCD_BITMAP |
160 | 146 | ||
161 | /* pixel margins */ | 147 | /* pixel margins */ |
162 | #define MARGIN_X (global_settings.scrollbar && \ | 148 | #define MARGIN_X (global_settings.scrollbar && \ |
163 | filesindir > tree_max_on_screen ? SCROLLBAR_WIDTH : 0) + \ | 149 | tc.filesindir > tree_max_on_screen ? SCROLLBAR_WIDTH : 0) + \ |
164 | CURSOR_WIDTH + (global_settings.show_icons && ICON_WIDTH > 0 ? ICON_WIDTH :0) | 150 | CURSOR_WIDTH + (global_settings.show_icons && ICON_WIDTH > 0 ? ICON_WIDTH :0) |
165 | #define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0) | 151 | #define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0) |
166 | 152 | ||
@@ -169,7 +155,7 @@ void tree_get_filetypes(const struct filetype** types, int* count) | |||
169 | #define LINE_Y (global_settings.statusbar ? 1 : 0) | 155 | #define LINE_Y (global_settings.statusbar ? 1 : 0) |
170 | 156 | ||
171 | #define CURSOR_X (global_settings.scrollbar && \ | 157 | #define CURSOR_X (global_settings.scrollbar && \ |
172 | filesindir > tree_max_on_screen ? 1 : 0) | 158 | tc.filesindir > tree_max_on_screen ? 1 : 0) |
173 | #define CURSOR_Y 0 /* the cursor is not positioned in regard to | 159 | #define CURSOR_Y 0 /* the cursor is not positioned in regard to |
174 | the margins, so this is the amount of lines | 160 | the margins, so this is the amount of lines |
175 | we add to the cursor Y position to position | 161 | we add to the cursor Y position to position |
@@ -197,158 +183,8 @@ void tree_get_filetypes(const struct filetype** types, int* count) | |||
197 | /* talkbox hovering delay, to avoid immediate disk activity */ | 183 | /* talkbox hovering delay, to avoid immediate disk activity */ |
198 | #define HOVER_DELAY (HZ/2) | 184 | #define HOVER_DELAY (HZ/2) |
199 | 185 | ||
200 | static int build_playlist(int start_index) | 186 | static void showfileline(int line, char* name, int attr, bool scroll) |
201 | { | ||
202 | int i; | ||
203 | int start=start_index; | ||
204 | |||
205 | for(i = 0;i < filesindir;i++) | ||
206 | { | ||
207 | if((dircache[i].attr & TREE_ATTR_MASK) == TREE_ATTR_MPA) | ||
208 | { | ||
209 | DEBUGF("Adding %s\n", dircache[i].name); | ||
210 | if (playlist_add(dircache[i].name) < 0) | ||
211 | break; | ||
212 | } | ||
213 | else | ||
214 | { | ||
215 | /* Adjust the start index when se skip non-MP3 entries */ | ||
216 | if(i < start) | ||
217 | start_index--; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | return start_index; | ||
222 | } | ||
223 | |||
224 | static int play_filenumber(int pos, int attr) | ||
225 | { | ||
226 | /* try to find a voice ID for the extension, if known */ | ||
227 | unsigned int j; | ||
228 | int ext_id = -1; /* default to none */ | ||
229 | for (j=0; j<sizeof(filetypes)/sizeof(*filetypes); j++) | ||
230 | { | ||
231 | if (attr == filetypes[j].tree_attr) | ||
232 | { | ||
233 | ext_id = filetypes[j].voiceclip; | ||
234 | break; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | talk_id(VOICE_FILE, false); | ||
239 | talk_number(pos, true); | ||
240 | talk_id(ext_id, true); | ||
241 | return 1; | ||
242 | } | ||
243 | |||
244 | static int play_dirname(int start_index) | ||
245 | { | 187 | { |
246 | int fd; | ||
247 | char dirname_mp3_filename[MAX_PATH+1]; | ||
248 | |||
249 | if (mpeg_status() & MPEG_STATUS_PLAY) | ||
250 | return 0; | ||
251 | |||
252 | snprintf(dirname_mp3_filename, sizeof(dirname_mp3_filename), "%s/%s/%s", | ||
253 | currdir, dircache[start_index].name, dir_thumbnail_name); | ||
254 | |||
255 | DEBUGF("Checking for %s\n", dirname_mp3_filename); | ||
256 | |||
257 | fd = open(dirname_mp3_filename, O_RDONLY); | ||
258 | if (fd < 0) | ||
259 | { | ||
260 | DEBUGF("Failed to find: %s\n", dirname_mp3_filename); | ||
261 | return -1; | ||
262 | } | ||
263 | |||
264 | close(fd); | ||
265 | |||
266 | DEBUGF("Found: %s\n", dirname_mp3_filename); | ||
267 | |||
268 | talk_file(dirname_mp3_filename, false); | ||
269 | return 1; | ||
270 | } | ||
271 | |||
272 | static void play_filename(char *dir, char *file) | ||
273 | { | ||
274 | char name_mp3_filename[MAX_PATH+1]; | ||
275 | |||
276 | if (mpeg_status() & MPEG_STATUS_PLAY) | ||
277 | return; | ||
278 | |||
279 | if (strcasecmp(&file[strlen(file) - strlen(file_thumbnail_ext)], | ||
280 | file_thumbnail_ext)) | ||
281 | { /* file has no .talk extension */ | ||
282 | snprintf(name_mp3_filename, sizeof(name_mp3_filename), | ||
283 | "%s/%s%s", dir, file, file_thumbnail_ext); | ||
284 | |||
285 | talk_file(name_mp3_filename, false); | ||
286 | } | ||
287 | else | ||
288 | { /* it already is a .talk file, play this directly */ | ||
289 | snprintf(name_mp3_filename, sizeof(name_mp3_filename), | ||
290 | "%s/%s", dir, file); | ||
291 | talk_id(LANG_VOICE_DIR_HOVER, false); /* prefix it */ | ||
292 | talk_file(name_mp3_filename, true); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | static int compare(const void* p1, const void* p2) | ||
297 | { | ||
298 | struct entry* e1 = (struct entry*)p1; | ||
299 | struct entry* e2 = (struct entry*)p2; | ||
300 | int criteria; | ||
301 | |||
302 | if (e1->attr & ATTR_DIRECTORY && e2->attr & ATTR_DIRECTORY) | ||
303 | { /* two directories */ | ||
304 | criteria = global_settings.sort_dir; | ||
305 | if (e1->attr & ATTR_VOLUME || e2->attr & ATTR_VOLUME) | ||
306 | { /* a volume identifier is involved */ | ||
307 | if (e1->attr & ATTR_VOLUME && e2->attr & ATTR_VOLUME) | ||
308 | criteria = 0; /* two volumes: sort alphabetically */ | ||
309 | else /* only one is a volume: volume first */ | ||
310 | return (e2->attr & ATTR_VOLUME) - (e1->attr & ATTR_VOLUME); | ||
311 | } | ||
312 | } | ||
313 | else if (!(e1->attr & ATTR_DIRECTORY) && !(e2->attr & ATTR_DIRECTORY)) | ||
314 | { /* two files */ | ||
315 | criteria = global_settings.sort_file; | ||
316 | } | ||
317 | else /* dir and file, dir goes first */ | ||
318 | return ( e2->attr & ATTR_DIRECTORY ) - ( e1->attr & ATTR_DIRECTORY ); | ||
319 | |||
320 | switch(criteria) | ||
321 | { | ||
322 | case 3: /* sort type */ | ||
323 | { | ||
324 | int t1 = e1->attr & TREE_ATTR_MASK; | ||
325 | int t2 = e2->attr & TREE_ATTR_MASK; | ||
326 | |||
327 | if (!t1) /* unknown type */ | ||
328 | t1 = 0x7FFFFFFF; /* gets a high number, to sort after known */ | ||
329 | if (!t2) /* unknown type */ | ||
330 | t2 = 0x7FFFFFFF; /* gets a high number, to sort after known */ | ||
331 | |||
332 | if (t1 - t2) /* if different */ | ||
333 | return t1 - t2; | ||
334 | /* else fall through to alphabetical sorting */ | ||
335 | } | ||
336 | case 0: /* sort alphabetically */ | ||
337 | if (global_settings.sort_case) | ||
338 | return strncmp(e1->name, e2->name, MAX_PATH); | ||
339 | else | ||
340 | return strncasecmp(e1->name, e2->name, MAX_PATH); | ||
341 | case 1: /* sort date */ | ||
342 | return e1->time_write - e2->time_write; | ||
343 | case 2: /* sort date, newest first */ | ||
344 | return e2->time_write - e1->time_write; | ||
345 | } | ||
346 | return 0; /* never reached */ | ||
347 | } | ||
348 | |||
349 | static void showfileline(int line, int direntry, bool scroll, const int *dirfilter) | ||
350 | { | ||
351 | char* name = dircache[direntry].name; | ||
352 | int xpos = LINE_X; | 188 | int xpos = LINE_X; |
353 | char* dotpos = NULL; | 189 | char* dotpos = NULL; |
354 | 190 | ||
@@ -358,8 +194,9 @@ static void showfileline(int line, int direntry, bool scroll, const int *dirfilt | |||
358 | #endif | 194 | #endif |
359 | 195 | ||
360 | /* if any file filter is on, strip the extension */ | 196 | /* if any file filter is on, strip the extension */ |
361 | if (*dirfilter != SHOW_ALL && | 197 | if (*tc.dirfilter != SHOW_ID3DB && |
362 | !(dircache[direntry].attr & ATTR_DIRECTORY)) | 198 | *tc.dirfilter != SHOW_ALL && |
199 | !(attr & ATTR_DIRECTORY)) | ||
363 | { | 200 | { |
364 | dotpos = strrchr(name, '.'); | 201 | dotpos = strrchr(name, '.'); |
365 | if (dotpos) { | 202 | if (dotpos) { |
@@ -383,207 +220,6 @@ static void showfileline(int line, int direntry, bool scroll, const int *dirfilt | |||
383 | *dotpos = '.'; | 220 | *dotpos = '.'; |
384 | } | 221 | } |
385 | 222 | ||
386 | /* walk a directory and check all dircache entries if a .talk file exists */ | ||
387 | void check_file_thumbnails(const char *dirname, int num_files) | ||
388 | { | ||
389 | int i; | ||
390 | struct dirent *entry; | ||
391 | DIR *dir; | ||
392 | |||
393 | dir = opendir(dirname); | ||
394 | if(!dir) | ||
395 | return; | ||
396 | |||
397 | for (i=0; i<num_files; i++) /* mark all files as non talking, except the .talk ones */ | ||
398 | { | ||
399 | if (dircache[i].attr & ATTR_DIRECTORY) | ||
400 | continue; /* we're not touching directories */ | ||
401 | |||
402 | if (strcasecmp(file_thumbnail_ext, | ||
403 | &dircache[i].name[strlen(dircache[i].name) | ||
404 | - strlen(file_thumbnail_ext)])) | ||
405 | { /* no .talk file */ | ||
406 | dircache[i].attr &= ~TREE_ATTR_THUMBNAIL; /* clear */ | ||
407 | } | ||
408 | else | ||
409 | { /* .talk file, we later let them speak themselves */ | ||
410 | dircache[i].attr |= TREE_ATTR_THUMBNAIL; /* set */ | ||
411 | } | ||
412 | } | ||
413 | |||
414 | while((entry = readdir(dir)) != 0) /* walk directory */ | ||
415 | { | ||
416 | int ext_pos; | ||
417 | |||
418 | ext_pos = strlen(entry->d_name) - strlen(file_thumbnail_ext); | ||
419 | if (ext_pos <= 0 /* too short to carry ".talk" */ | ||
420 | || (entry->attribute & ATTR_DIRECTORY) /* no file */ | ||
421 | || strcasecmp(&entry->d_name[ext_pos], file_thumbnail_ext)) | ||
422 | { /* or doesn't end with ".talk", no candidate */ | ||
423 | continue; | ||
424 | } | ||
425 | |||
426 | /* terminate the (disposable) name in dir buffer, | ||
427 | this truncates off the ".talk" without needing an extra buffer */ | ||
428 | entry->d_name[ext_pos] = '\0'; | ||
429 | |||
430 | /* search corresponding file in dir cache */ | ||
431 | for (i=0; i<num_files; i++) | ||
432 | { | ||
433 | if (!strcasecmp(dircache[i].name, entry->d_name)) | ||
434 | { /* match */ | ||
435 | dircache[i].attr |= TREE_ATTR_THUMBNAIL; /* set the flag */ | ||
436 | break; /* exit search loop, because we found it */ | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | closedir(dir); | ||
441 | } | ||
442 | |||
443 | /* check all dircache directories if they contain a "_dirname.talk" file */ | ||
444 | #if 0 /* not practical, this is too slow */ | ||
445 | void check_dir_thumbnails(const char *dirname, int num_files) | ||
446 | { | ||
447 | int i; | ||
448 | int fd; | ||
449 | char clipfile[MAX_PATH]; | ||
450 | |||
451 | for (i=0; i<num_files; i++) | ||
452 | { | ||
453 | if (!(dircache[i].attr & ATTR_DIRECTORY)) | ||
454 | continue; /* only directories are interesting */ | ||
455 | |||
456 | /* compose pathname of directory name clip file */ | ||
457 | snprintf(clipfile, sizeof(clipfile), "%s%s/%s", | ||
458 | dirname, dircache[i].name, dir_thumbnail_name); | ||
459 | |||
460 | fd = open(clipfile, O_RDONLY); /* check if exists */ | ||
461 | if (fd >= 0) | ||
462 | { /* there is one */ | ||
463 | dircache[i].attr |= TREE_ATTR_THUMBNAIL; /* set the flag */ | ||
464 | close(fd); | ||
465 | } | ||
466 | else | ||
467 | { /* none found, clear the flag */ | ||
468 | dircache[i].attr &= ~TREE_ATTR_THUMBNAIL; | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | #endif /* #if 0 */ | ||
473 | |||
474 | /* load sorted directory into dircache. returns NULL on failure. */ | ||
475 | struct entry* load_and_sort_directory(const char *dirname, const int *dirfilter, | ||
476 | int *num_files, bool *buffer_full) | ||
477 | { | ||
478 | int i; | ||
479 | |||
480 | DIR *dir = opendir(dirname); | ||
481 | if(!dir) | ||
482 | return NULL; /* not a directory */ | ||
483 | |||
484 | name_buffer_length = 0; | ||
485 | dirsindir = 0; | ||
486 | *buffer_full = false; | ||
487 | |||
488 | for ( i=0; i < max_files_in_dir; i++ ) { | ||
489 | int len; | ||
490 | struct dirent *entry = readdir(dir); | ||
491 | struct entry* dptr = &dircache[i]; | ||
492 | if (!entry) | ||
493 | break; | ||
494 | |||
495 | len = strlen(entry->d_name); | ||
496 | |||
497 | /* skip directories . and .. */ | ||
498 | if ((entry->attribute & ATTR_DIRECTORY) && | ||
499 | (((len == 1) && | ||
500 | (!strncmp(entry->d_name, ".", 1))) || | ||
501 | ((len == 2) && | ||
502 | (!strncmp(entry->d_name, "..", 2))))) { | ||
503 | i--; | ||
504 | continue; | ||
505 | } | ||
506 | |||
507 | /* Skip FAT volume ID */ | ||
508 | if (entry->attribute & ATTR_VOLUME_ID) { | ||
509 | i--; | ||
510 | continue; | ||
511 | } | ||
512 | |||
513 | /* filter out dotfiles and hidden files */ | ||
514 | if (*dirfilter != SHOW_ALL && | ||
515 | ((entry->d_name[0]=='.') || | ||
516 | (entry->attribute & ATTR_HIDDEN))) { | ||
517 | i--; | ||
518 | continue; | ||
519 | } | ||
520 | |||
521 | dptr->attr = entry->attribute; | ||
522 | |||
523 | /* check for known file types */ | ||
524 | if ( !(dptr->attr & ATTR_DIRECTORY) && (len > 4) ) | ||
525 | dptr->attr |= filetype_get_attr(entry->d_name); | ||
526 | |||
527 | /* memorize/compare details about the boot file */ | ||
528 | if ((currdir[1] == 0) && !strcasecmp(entry->d_name, BOOTFILE)) { | ||
529 | if (boot_size) { | ||
530 | if ((entry->size != boot_size) || | ||
531 | (entry->startcluster != boot_cluster)) | ||
532 | boot_changed = true; | ||
533 | } | ||
534 | boot_size = entry->size; | ||
535 | boot_cluster = entry->startcluster; | ||
536 | } | ||
537 | |||
538 | /* filter out non-visible files */ | ||
539 | if (!(dptr->attr & ATTR_DIRECTORY) && ( | ||
540 | (*dirfilter == SHOW_PLAYLIST && | ||
541 | (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_M3U) || | ||
542 | ((*dirfilter == SHOW_MUSIC && | ||
543 | (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_MPA) && | ||
544 | (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_M3U) || | ||
545 | (*dirfilter == SHOW_SUPPORTED && !filetype_supported(dptr->attr)) || | ||
546 | (*dirfilter == SHOW_WPS && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_WPS) || | ||
547 | (*dirfilter == SHOW_CFG && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_CFG) || | ||
548 | (*dirfilter == SHOW_LNG && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_LNG) || | ||
549 | (*dirfilter == SHOW_MOD && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_MOD) || | ||
550 | (*dirfilter == SHOW_FONT && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_FONT) || | ||
551 | (*dirfilter == SHOW_PLUGINS && (dptr->attr & TREE_ATTR_MASK) != TREE_ATTR_ROCK))) | ||
552 | { | ||
553 | i--; | ||
554 | continue; | ||
555 | } | ||
556 | |||
557 | if (len > name_buffer_size - name_buffer_length - 1) { | ||
558 | /* Tell the world that we ran out of buffer space */ | ||
559 | *buffer_full = true; | ||
560 | break; | ||
561 | } | ||
562 | dptr->name = &name_buffer[name_buffer_length]; | ||
563 | dptr->time_write = entry->wrtdate<<16 | entry->wrttime; /* in one # */ | ||
564 | strcpy(dptr->name,entry->d_name); | ||
565 | name_buffer_length += len + 1; | ||
566 | |||
567 | if (dptr->attr & ATTR_DIRECTORY) /* count the remaining dirs */ | ||
568 | dirsindir++; | ||
569 | } | ||
570 | *num_files = i; | ||
571 | closedir(dir); | ||
572 | strncpy(lastdir,dirname,sizeof(lastdir)); | ||
573 | lastdir[sizeof(lastdir)-1] = 0; | ||
574 | qsort(dircache,i,sizeof(struct entry),compare); | ||
575 | |||
576 | /* If thumbnail talking is enabled, make an extra run to mark files with | ||
577 | associated thumbnails, so we don't do unsuccessful spinups later. */ | ||
578 | if (global_settings.talk_file == 3) | ||
579 | check_file_thumbnails(dirname, i); /* map .talk to ours */ | ||
580 | #if 0 /* not practical, this is too slow */ | ||
581 | if (global_settings.talk_dir == 3) | ||
582 | check_dir_thumbnails(dirname, i); /* try in the directories */ | ||
583 | #endif /* #if 0 */ | ||
584 | return dircache; | ||
585 | } | ||
586 | |||
587 | #ifdef HAVE_LCD_BITMAP | 223 | #ifdef HAVE_LCD_BITMAP |
588 | static int recalc_screen_height(void) | 224 | static int recalc_screen_height(void) |
589 | { | 225 | { |
@@ -604,11 +240,12 @@ static int recalc_screen_height(void) | |||
604 | } | 240 | } |
605 | #endif | 241 | #endif |
606 | 242 | ||
607 | static int showdir(const char *path, int start, const int *dirfilter) | 243 | static int showdir(void) |
608 | { | 244 | { |
245 | struct entry *dircache = tc.dircache; | ||
609 | int i; | 246 | int i; |
610 | int tree_max_on_screen; | 247 | int tree_max_on_screen; |
611 | bool dir_buffer_full; | 248 | bool dir_buffer_full = false; |
612 | 249 | ||
613 | #ifdef HAVE_LCD_BITMAP | 250 | #ifdef HAVE_LCD_BITMAP |
614 | const char* icon; | 251 | const char* icon; |
@@ -622,24 +259,31 @@ static int showdir(const char *path, int start, const int *dirfilter) | |||
622 | int icon; | 259 | int icon; |
623 | tree_max_on_screen = TREE_MAX_ON_SCREEN; | 260 | tree_max_on_screen = TREE_MAX_ON_SCREEN; |
624 | #endif | 261 | #endif |
262 | int start = tc.dirstart; | ||
263 | bool id3db = global_settings.dirfilter == SHOW_ID3DB; | ||
625 | 264 | ||
626 | /* new dir? cache it */ | 265 | /* new file dir? load it */ |
627 | if (strncmp(path,lastdir,sizeof(lastdir)) || reload_dir) { | 266 | if (id3db) { |
628 | if (!load_and_sort_directory(path, dirfilter, | 267 | if (db_load(&tc, &dir_buffer_full) < 0) |
629 | &filesindir, &dir_buffer_full)) | ||
630 | return -1; | 268 | return -1; |
269 | } | ||
270 | else { | ||
271 | if (strncmp(tc.currdir, lastdir, sizeof(lastdir)) || reload_dir) { | ||
272 | if (ft_load(&tc, &dir_buffer_full) < 0) | ||
273 | return -1; | ||
274 | } | ||
275 | } | ||
631 | 276 | ||
632 | if ( dir_buffer_full || filesindir == max_files_in_dir ) { | 277 | if ( dir_buffer_full || tc.filesindir == global_settings.max_files_in_dir ) { |
633 | #ifdef HAVE_LCD_CHARCELLS | 278 | #ifdef HAVE_LCD_CHARCELLS |
634 | lcd_double_height(false); | 279 | lcd_double_height(false); |
635 | #endif | 280 | #endif |
636 | lcd_clear_display(); | 281 | lcd_clear_display(); |
637 | lcd_puts(0,0,str(LANG_SHOWDIR_ERROR_BUFFER)); | 282 | lcd_puts(0,0,str(LANG_SHOWDIR_ERROR_BUFFER)); |
638 | lcd_puts(0,1,str(LANG_SHOWDIR_ERROR_FULL)); | 283 | lcd_puts(0,1,str(LANG_SHOWDIR_ERROR_FULL)); |
639 | lcd_update(); | 284 | lcd_update(); |
640 | sleep(HZ*2); | 285 | sleep(HZ*2); |
641 | lcd_clear_display(); | 286 | lcd_clear_display(); |
642 | } | ||
643 | } | 287 | } |
644 | 288 | ||
645 | if (start == -1) | 289 | if (start == -1) |
@@ -649,8 +293,10 @@ static int showdir(const char *path, int start, const int *dirfilter) | |||
649 | /* use lastfile to determine start (default=0) */ | 293 | /* use lastfile to determine start (default=0) */ |
650 | start = 0; | 294 | start = 0; |
651 | 295 | ||
652 | for (i=0; i<filesindir; i++) | 296 | for (i=0; i < tc.filesindir; i++) |
653 | { | 297 | { |
298 | struct entry *dircache = tc.dircache; | ||
299 | |||
654 | if (!strcasecmp(dircache[i].name, lastfile)) | 300 | if (!strcasecmp(dircache[i].name, lastfile)) |
655 | { | 301 | { |
656 | start = i; | 302 | start = i; |
@@ -658,7 +304,7 @@ static int showdir(const char *path, int start, const int *dirfilter) | |||
658 | } | 304 | } |
659 | } | 305 | } |
660 | 306 | ||
661 | diff_files = filesindir - start; | 307 | diff_files = tc.filesindir - start; |
662 | if (diff_files < tree_max_on_screen) | 308 | if (diff_files < tree_max_on_screen) |
663 | { | 309 | { |
664 | int oldstart = start; | 310 | int oldstart = start; |
@@ -667,25 +313,25 @@ static int showdir(const char *path, int start, const int *dirfilter) | |||
667 | if (start < 0) | 313 | if (start < 0) |
668 | start = 0; | 314 | start = 0; |
669 | 315 | ||
670 | dircursor = oldstart - start; | 316 | tc.dircursor = oldstart - start; |
671 | } | 317 | } |
672 | 318 | ||
673 | dirstart = start; | 319 | tc.dirstart = start; |
674 | } | 320 | } |
675 | 321 | ||
676 | /* The cursor might point to an invalid line, for example if someone | 322 | /* The cursor might point to an invalid line, for example if someone |
677 | deleted the last file in the dir */ | 323 | deleted the last file in the dir */ |
678 | if(filesindir) | 324 | if (tc.filesindir) |
679 | { | 325 | { |
680 | while(start + dircursor >= filesindir) | 326 | while (start + tc.dircursor >= tc.filesindir) |
681 | { | 327 | { |
682 | if(start) | 328 | if (start) |
683 | start--; | 329 | start--; |
684 | else | 330 | else |
685 | if(dircursor) | 331 | if (tc.dircursor) |
686 | dircursor--; | 332 | tc.dircursor--; |
687 | } | 333 | } |
688 | dirstart = start; | 334 | tc.dirstart = start; |
689 | } | 335 | } |
690 | 336 | ||
691 | #ifdef HAVE_LCD_CHARCELLS | 337 | #ifdef HAVE_LCD_CHARCELLS |
@@ -698,11 +344,24 @@ static int showdir(const char *path, int start, const int *dirfilter) | |||
698 | lcd_setfont(FONT_UI); | 344 | lcd_setfont(FONT_UI); |
699 | #endif | 345 | #endif |
700 | 346 | ||
701 | for ( i=start; i < start+tree_max_on_screen; i++ ) { | ||
702 | if ( i >= filesindir ) | ||
703 | break; | ||
704 | 347 | ||
705 | icon = filetype_get_icon(dircache[i].attr); | 348 | for ( i=start; i < start+tree_max_on_screen && i < tc.filesindir; i++ ) { |
349 | int line = i - start; | ||
350 | char* name; | ||
351 | int attr = 0; | ||
352 | |||
353 | if (id3db) { | ||
354 | name = ((char**)tc.dircache)[i * 2]; | ||
355 | icon = db_get_icon(&tc); | ||
356 | } | ||
357 | else { | ||
358 | struct entry* dc = tc.dircache; | ||
359 | struct entry* e = &dc[i]; | ||
360 | name = e->name; | ||
361 | attr = e->attr; | ||
362 | icon = filetype_get_icon(dircache[i].attr); | ||
363 | } | ||
364 | |||
706 | 365 | ||
707 | if (icon && global_settings.show_icons) { | 366 | if (icon && global_settings.show_icons) { |
708 | #ifdef HAVE_LCD_BITMAP | 367 | #ifdef HAVE_LCD_BITMAP |
@@ -720,18 +379,18 @@ static int showdir(const char *path, int start, const int *dirfilter) | |||
720 | #endif | 379 | #endif |
721 | } | 380 | } |
722 | 381 | ||
723 | showfileline(i-start, i, false, dirfilter); /* no scroll */ | 382 | showfileline(line, name, attr, false); /* no scroll */ |
724 | } | 383 | } |
725 | 384 | ||
726 | #ifdef HAVE_LCD_BITMAP | 385 | #ifdef HAVE_LCD_BITMAP |
727 | if (global_settings.scrollbar && (filesindir > tree_max_on_screen)) | 386 | if (global_settings.scrollbar && (tc.filesindir > tree_max_on_screen)) |
728 | scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1, | 387 | scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1, |
729 | tree_max_on_screen * line_height, filesindir, start, | 388 | tree_max_on_screen * line_height, tc.filesindir, start, |
730 | start + tree_max_on_screen, VERTICAL); | 389 | start + tree_max_on_screen, VERTICAL); |
731 | 390 | ||
732 | #if CONFIG_KEYPAD == RECORDER_PAD | 391 | #if CONFIG_KEYPAD == RECORDER_PAD |
733 | if(global_settings.buttonbar) { | 392 | if(global_settings.buttonbar) { |
734 | buttonbar_set(*dirfilter < NUM_FILTER_MODES ? | 393 | buttonbar_set(*tc.dirfilter < NUM_FILTER_MODES ? |
735 | str(LANG_DIRBROWSE_F1) : (unsigned char *) "", | 394 | str(LANG_DIRBROWSE_F1) : (unsigned char *) "", |
736 | str(LANG_DIRBROWSE_F2), | 395 | str(LANG_DIRBROWSE_F2), |
737 | str(LANG_DIRBROWSE_F3)); | 396 | str(LANG_DIRBROWSE_F3)); |
@@ -741,7 +400,7 @@ static int showdir(const char *path, int start, const int *dirfilter) | |||
741 | #endif | 400 | #endif |
742 | status_draw(true); | 401 | status_draw(true); |
743 | 402 | ||
744 | return filesindir; | 403 | return tc.filesindir; |
745 | } | 404 | } |
746 | 405 | ||
747 | static bool ask_resume(bool ask_once) | 406 | static bool ask_resume(bool ask_once) |
@@ -826,12 +485,12 @@ void resume_directory(const char *dir) | |||
826 | { | 485 | { |
827 | bool buffer_full; | 486 | bool buffer_full; |
828 | 487 | ||
829 | if (!load_and_sort_directory(dir, &global_settings.dirfilter, &filesindir, | 488 | strcpy(tc.currdir, dir); |
830 | &buffer_full)) | 489 | if (!ft_load(&tc, &buffer_full)) |
831 | return; | 490 | return; |
832 | lastdir[0] = 0; | 491 | lastdir[0] = 0; |
833 | 492 | ||
834 | build_playlist(0); | 493 | ft_build_playlist(&tc, 0); |
835 | } | 494 | } |
836 | 495 | ||
837 | /* Returns the current working directory and also writes cwd to buf if | 496 | /* Returns the current working directory and also writes cwd to buf if |
@@ -839,10 +498,10 @@ void resume_directory(const char *dir) | |||
839 | char *getcwd(char *buf, int size) | 498 | char *getcwd(char *buf, int size) |
840 | { | 499 | { |
841 | if (!buf) | 500 | if (!buf) |
842 | return currdir; | 501 | return tc.currdir; |
843 | else if (size > 0) | 502 | else if (size > 0) |
844 | { | 503 | { |
845 | strncpy(buf, currdir, size); | 504 | strncpy(buf, tc.currdir, size); |
846 | return buf; | 505 | return buf; |
847 | } | 506 | } |
848 | else | 507 | else |
@@ -888,41 +547,54 @@ void set_current_file(char *path) | |||
888 | if (name) | 547 | if (name) |
889 | { | 548 | { |
890 | *name = 0; | 549 | *name = 0; |
891 | strcpy(currdir, path); | 550 | strcpy(tc.currdir, path); |
892 | *name = '/'; | 551 | *name = '/'; |
893 | name++; | 552 | name++; |
894 | } | 553 | } |
895 | else | 554 | else |
896 | { | 555 | { |
897 | strcpy(currdir, "/"); | 556 | strcpy(tc.currdir, "/"); |
898 | name = path+1; | 557 | name = path+1; |
899 | } | 558 | } |
900 | 559 | ||
901 | strcpy(lastfile, name); | 560 | strcpy(lastfile, name); |
902 | 561 | ||
903 | dircursor = 0; | 562 | tc.dircursor = 0; |
904 | dirstart = -1; | 563 | tc.dirstart = -1; |
905 | 564 | ||
906 | if (strncmp(currdir,lastdir,sizeof(lastdir))) | 565 | if (strncmp(tc.currdir,lastdir,sizeof(lastdir))) |
907 | { | 566 | { |
908 | dirlevel = 0; | 567 | tc.dirlevel = 0; |
909 | dirpos[dirlevel] = -1; | 568 | tc.dirpos[tc.dirlevel] = -1; |
910 | cursorpos[dirlevel] = 0; | 569 | tc.cursorpos[tc.dirlevel] = 0; |
911 | 570 | ||
912 | /* use '/' to calculate dirlevel */ | 571 | /* use '/' to calculate dirlevel */ |
913 | for (i=1; i<strlen(path)+1; i++) | 572 | for (i=1; i<strlen(path)+1; i++) |
914 | { | 573 | { |
915 | if (path[i] == '/') | 574 | if (path[i] == '/') |
916 | { | 575 | { |
917 | dirlevel++; | 576 | tc.dirlevel++; |
918 | dirpos[dirlevel] = -1; | 577 | tc.dirpos[tc.dirlevel] = -1; |
919 | cursorpos[dirlevel] = 0; | 578 | tc.cursorpos[tc.dirlevel] = 0; |
920 | } | 579 | } |
921 | } | 580 | } |
922 | } | 581 | } |
923 | } | 582 | } |
924 | 583 | ||
925 | static bool dirbrowse(const char *root, const int *dirfilter) | 584 | static bool check_changed_id3mode(bool currmode) |
585 | { | ||
586 | if (currmode != (global_settings.dirfilter == SHOW_ID3DB)) { | ||
587 | currmode = global_settings.dirfilter == SHOW_ID3DB; | ||
588 | if (currmode) { | ||
589 | db_load(&tc, NULL); | ||
590 | } | ||
591 | else | ||
592 | ft_load(&tc, NULL); | ||
593 | } | ||
594 | return currmode; | ||
595 | } | ||
596 | |||
597 | static bool dirbrowse(void) | ||
926 | { | 598 | { |
927 | int numentries=0; | 599 | int numentries=0; |
928 | char buf[MAX_PATH]; | 600 | char buf[MAX_PATH]; |
@@ -931,7 +603,7 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
931 | int button; | 603 | int button; |
932 | int tree_max_on_screen; | 604 | int tree_max_on_screen; |
933 | bool reload_root = false; | 605 | bool reload_root = false; |
934 | int lastfilter = *dirfilter; | 606 | int lastfilter = *tc.dirfilter; |
935 | bool lastsortcase = global_settings.sort_case; | 607 | bool lastsortcase = global_settings.sort_case; |
936 | int lastdircursor=-1; | 608 | int lastdircursor=-1; |
937 | bool need_update = true; | 609 | bool need_update = true; |
@@ -940,6 +612,8 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
940 | bool update_all = false; /* set this to true when the whole file list | 612 | bool update_all = false; /* set this to true when the whole file list |
941 | has been refreshed on screen */ | 613 | has been refreshed on screen */ |
942 | int lastbutton = 0; | 614 | int lastbutton = 0; |
615 | char* currdir = tc.currdir; /* just a shortcut */ | ||
616 | bool id3db = global_settings.dirfilter == SHOW_ID3DB; | ||
943 | 617 | ||
944 | #ifdef HAVE_LCD_BITMAP | 618 | #ifdef HAVE_LCD_BITMAP |
945 | tree_max_on_screen = recalc_screen_height(); | 619 | tree_max_on_screen = recalc_screen_height(); |
@@ -947,31 +621,28 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
947 | tree_max_on_screen = TREE_MAX_ON_SCREEN; | 621 | tree_max_on_screen = TREE_MAX_ON_SCREEN; |
948 | #endif | 622 | #endif |
949 | 623 | ||
950 | dircursor=0; | 624 | tc.dircursor=0; |
951 | dirstart=0; | 625 | tc.dirstart=0; |
952 | dirlevel=0; | 626 | tc.dirlevel=0; |
953 | 627 | ||
954 | memcpy(currdir,root,sizeof(currdir)); | 628 | if (*tc.dirfilter < NUM_FILTER_MODES) |
955 | |||
956 | if (*dirfilter < NUM_FILTER_MODES) | ||
957 | start_resume(true); | 629 | start_resume(true); |
958 | 630 | ||
959 | numentries = showdir(currdir, dirstart, dirfilter); | 631 | numentries = showdir(); |
960 | if (numentries == -1) | 632 | if (numentries == -1) |
961 | return false; /* currdir is not a directory */ | 633 | return false; /* currdir is not a directory */ |
962 | 634 | ||
963 | if (*dirfilter > NUM_FILTER_MODES && numentries==0) | 635 | if (*tc.dirfilter > NUM_FILTER_MODES && numentries==0) |
964 | { | 636 | { |
965 | splash(HZ*2, true, str(LANG_NO_FILES)); | 637 | splash(HZ*2, true, str(LANG_NO_FILES)); |
966 | return false; /* No files found for rockbox_browser() */ | 638 | return false; /* No files found for rockbox_browser() */ |
967 | } | 639 | } |
968 | |||
969 | update_all = true; | 640 | update_all = true; |
970 | 641 | ||
971 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, true); | 642 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); |
972 | 643 | ||
973 | while(1) { | 644 | while(1) { |
974 | struct entry* file = &dircache[dircursor+dirstart]; | 645 | struct entry *dircache = tc.dircache; |
975 | 646 | ||
976 | bool restore = false; | 647 | bool restore = false; |
977 | 648 | ||
@@ -1003,7 +674,7 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1003 | (button & BUTTON_REL)) | 674 | (button & BUTTON_REL)) |
1004 | stop = true; | 675 | stop = true; |
1005 | break; | 676 | break; |
1006 | } | 677 | } |
1007 | } | 678 | } |
1008 | 679 | ||
1009 | restore = true; | 680 | restore = true; |
@@ -1012,48 +683,71 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1012 | #endif | 683 | #endif |
1013 | 684 | ||
1014 | switch ( button ) { | 685 | switch ( button ) { |
1015 | case TREE_EXIT: | 686 | #ifdef TREE_ENTER |
1016 | case TREE_EXIT | BUTTON_REPEAT: | 687 | case TREE_ENTER: |
1017 | #ifdef TREE_RC_EXIT | 688 | case TREE_ENTER | BUTTON_REPEAT: |
1018 | case TREE_RC_EXIT: | ||
1019 | #endif | 689 | #endif |
1020 | i=strlen(currdir); | 690 | #ifdef TREE_RC_ENTER |
1021 | if (i>1) { | 691 | case TREE_RC_ENTER: |
1022 | while (currdir[i-1]!='/') | 692 | #endif |
1023 | i--; | 693 | case TREE_RUN: |
1024 | strcpy(buf,&currdir[i]); | 694 | #ifdef TREE_RUN_PRE |
1025 | if (i==1) | 695 | if ((button == TREE_RUN) && |
1026 | currdir[i]=0; | 696 | (lastbutton != TREE_RUN_PRE)) |
1027 | else | 697 | break; |
1028 | currdir[i-1]=0; | 698 | #endif |
1029 | 699 | if ( !numentries ) | |
1030 | if (*dirfilter > NUM_FILTER_MODES && dirlevel < 1) | 700 | break; |
1031 | exit_func = true; | ||
1032 | 701 | ||
1033 | dirlevel--; | 702 | if (id3db) |
1034 | if ( dirlevel < MAX_DIR_LEVELS ) { | 703 | db_enter(&tc); |
1035 | dirstart = dirpos[dirlevel]; | 704 | else { |
1036 | dircursor = cursorpos[dirlevel]; | 705 | switch (ft_enter(&tc)) |
706 | { | ||
707 | case 1: reload_dir = true; break; | ||
708 | case 2: reload_root = true; break; | ||
709 | case 3: start_wps = true; break; | ||
710 | case 4: exit_func = true; break; | ||
711 | default: break; | ||
1037 | } | 712 | } |
1038 | else | ||
1039 | dirstart = dircursor = 0; | ||
1040 | 713 | ||
1041 | if (dirstart == -1) | 714 | #ifdef HAVE_LCD_BITMAP |
1042 | strcpy(lastfile, buf); | 715 | /* maybe we have a new font */ |
716 | tree_max_on_screen = recalc_screen_height(); | ||
717 | #endif | ||
718 | } | ||
1043 | 719 | ||
1044 | restore = true; | 720 | /* make sure cursor is on screen */ |
721 | while ( tc.dircursor > tree_max_on_screen ) | ||
722 | { | ||
723 | tc.dircursor--; | ||
724 | tc.dirstart++; | ||
1045 | } | 725 | } |
726 | |||
727 | restore = true; | ||
728 | break; | ||
729 | |||
730 | case TREE_EXIT: | ||
731 | case TREE_EXIT | BUTTON_REPEAT: | ||
732 | #ifdef TREE_RC_EXIT | ||
733 | case TREE_RC_EXIT: | ||
734 | #endif | ||
735 | if (!tc.dirlevel) | ||
736 | break; | ||
737 | |||
738 | if (id3db) | ||
739 | db_exit(&tc); | ||
1046 | else | 740 | else |
1047 | { | 741 | if (ft_exit(&tc) == 4) |
1048 | if (*dirfilter > NUM_FILTER_MODES && dirlevel < 1) | ||
1049 | exit_func = true; | 742 | exit_func = true; |
1050 | } | 743 | |
744 | restore = true; | ||
1051 | break; | 745 | break; |
1052 | 746 | ||
1053 | #ifdef TREE_OFF | 747 | #ifdef TREE_OFF |
1054 | #ifndef HAVE_SW_POWEROFF | 748 | #ifndef HAVE_SW_POWEROFF |
1055 | case TREE_OFF: | 749 | case TREE_OFF: |
1056 | if (*dirfilter < NUM_FILTER_MODES) | 750 | if (*tc.dirfilter < NUM_FILTER_MODES) |
1057 | { | 751 | { |
1058 | /* Stop the music if it is playing, else show the shutdown | 752 | /* Stop the music if it is playing, else show the shutdown |
1059 | screen */ | 753 | screen */ |
@@ -1078,238 +772,37 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1078 | break; | 772 | break; |
1079 | #endif | 773 | #endif |
1080 | 774 | ||
1081 | #ifdef TREE_ENTER | ||
1082 | case TREE_ENTER: | ||
1083 | case TREE_ENTER | BUTTON_REPEAT: | ||
1084 | #endif | ||
1085 | #ifdef TREE_RC_ENTER | ||
1086 | case TREE_RC_ENTER: | ||
1087 | #endif | ||
1088 | case TREE_RUN: | ||
1089 | #ifdef TREE_RUN_PRE | ||
1090 | if ((button == TREE_RUN) && | ||
1091 | (lastbutton != TREE_RUN_PRE)) | ||
1092 | break; | ||
1093 | #endif | ||
1094 | if ( !numentries ) | ||
1095 | break; | ||
1096 | if (currdir[1]) | ||
1097 | snprintf(buf,sizeof(buf),"%s/%s",currdir, file->name); | ||
1098 | else | ||
1099 | snprintf(buf,sizeof(buf),"/%s",file->name); | ||
1100 | |||
1101 | if (file->attr & ATTR_DIRECTORY) { | ||
1102 | memcpy(currdir,buf,sizeof(currdir)); | ||
1103 | if ( dirlevel < MAX_DIR_LEVELS ) { | ||
1104 | dirpos[dirlevel] = dirstart; | ||
1105 | cursorpos[dirlevel] = dircursor; | ||
1106 | } | ||
1107 | dirlevel++; | ||
1108 | dircursor=0; | ||
1109 | dirstart=0; | ||
1110 | } | ||
1111 | else { | ||
1112 | int seed = current_tick; | ||
1113 | bool play = false; | ||
1114 | int start_index=0; | ||
1115 | |||
1116 | lcd_stop_scroll(); | ||
1117 | switch ( file->attr & TREE_ATTR_MASK ) { | ||
1118 | case TREE_ATTR_M3U: | ||
1119 | if (bookmark_autoload(buf)) | ||
1120 | { | ||
1121 | restore = true; | ||
1122 | break; | ||
1123 | } | ||
1124 | |||
1125 | if (playlist_create(currdir, file->name) != -1) | ||
1126 | { | ||
1127 | if (global_settings.playlist_shuffle) | ||
1128 | playlist_shuffle(seed, -1); | ||
1129 | start_index = 0; | ||
1130 | playlist_start(start_index,0); | ||
1131 | play = true; | ||
1132 | } | ||
1133 | break; | ||
1134 | |||
1135 | case TREE_ATTR_MPA: | ||
1136 | if (bookmark_autoload(currdir)) | ||
1137 | { | ||
1138 | restore = true; | ||
1139 | break; | ||
1140 | } | ||
1141 | |||
1142 | if (playlist_create(currdir, NULL) != -1) | ||
1143 | { | ||
1144 | start_index = | ||
1145 | build_playlist(dircursor+dirstart); | ||
1146 | if (global_settings.playlist_shuffle) | ||
1147 | { | ||
1148 | start_index = | ||
1149 | playlist_shuffle(seed,start_index); | ||
1150 | |||
1151 | /* when shuffling dir.: play all files | ||
1152 | even if the file selected by user is | ||
1153 | not the first one */ | ||
1154 | if (!global_settings.play_selected) | ||
1155 | start_index = 0; | ||
1156 | } | ||
1157 | |||
1158 | playlist_start(start_index, 0); | ||
1159 | play = true; | ||
1160 | } | ||
1161 | break; | ||
1162 | |||
1163 | /* wps config file */ | ||
1164 | case TREE_ATTR_WPS: | ||
1165 | wps_load(buf,true); | ||
1166 | set_file(buf, global_settings.wps_file, | ||
1167 | MAX_FILENAME); | ||
1168 | restore = true; | ||
1169 | break; | ||
1170 | |||
1171 | case TREE_ATTR_CFG: | ||
1172 | if (!settings_load_config(buf)) | ||
1173 | break; | ||
1174 | lcd_clear_display(); | ||
1175 | lcd_puts(0,0,str(LANG_SETTINGS_LOADED1)); | ||
1176 | lcd_puts(0,1,str(LANG_SETTINGS_LOADED2)); | ||
1177 | #ifdef HAVE_LCD_BITMAP | ||
1178 | lcd_update(); | ||
1179 | |||
1180 | /* maybe we have a new font */ | ||
1181 | tree_max_on_screen = recalc_screen_height(); | ||
1182 | /* make sure cursor is on screen */ | ||
1183 | while ( dircursor > tree_max_on_screen ) | ||
1184 | { | ||
1185 | dircursor--; | ||
1186 | dirstart++; | ||
1187 | } | ||
1188 | #endif | ||
1189 | sleep(HZ/2); | ||
1190 | restore = true; | ||
1191 | break; | ||
1192 | |||
1193 | case TREE_ATTR_BMARK: | ||
1194 | bookmark_load(buf, false); | ||
1195 | restore = true; | ||
1196 | reload_dir = true; | ||
1197 | break; | ||
1198 | |||
1199 | case TREE_ATTR_LNG: | ||
1200 | if(!lang_load(buf)) { | ||
1201 | set_file(buf, global_settings.lang_file, | ||
1202 | MAX_FILENAME); | ||
1203 | talk_init(); /* use voice of same language */ | ||
1204 | splash(HZ, true, str(LANG_LANGUAGE_LOADED)); | ||
1205 | restore = true; | ||
1206 | |||
1207 | language_changed = true; | ||
1208 | } | ||
1209 | break; | ||
1210 | |||
1211 | #ifdef HAVE_LCD_BITMAP | ||
1212 | case TREE_ATTR_FONT: | ||
1213 | font_load(buf); | ||
1214 | set_file(buf, global_settings.font_file, | ||
1215 | MAX_FILENAME); | ||
1216 | |||
1217 | tree_max_on_screen = recalc_screen_height(); | ||
1218 | /* make sure cursor is on screen */ | ||
1219 | while ( dircursor > tree_max_on_screen ) { | ||
1220 | dircursor--; | ||
1221 | dirstart++; | ||
1222 | } | ||
1223 | restore = true; | ||
1224 | break; | ||
1225 | #endif | ||
1226 | |||
1227 | #ifndef SIMULATOR | ||
1228 | /* firmware file */ | ||
1229 | case TREE_ATTR_MOD: | ||
1230 | rolo_load(buf); | ||
1231 | break; | ||
1232 | #endif | ||
1233 | |||
1234 | /* plugin file */ | ||
1235 | case TREE_ATTR_ROCK: | ||
1236 | if (plugin_load(buf,NULL) == PLUGIN_USB_CONNECTED) | ||
1237 | { | ||
1238 | if(*dirfilter > NUM_FILTER_MODES) | ||
1239 | /* leave sub-browsers after usb, doing | ||
1240 | otherwise might be confusing to the user */ | ||
1241 | exit_func = true; | ||
1242 | else | ||
1243 | reload_root = true; | ||
1244 | } | ||
1245 | else | ||
1246 | restore = true; | ||
1247 | break; | ||
1248 | |||
1249 | default: | ||
1250 | { | ||
1251 | char* plugin = filetype_get_plugin(file); | ||
1252 | if (plugin) | ||
1253 | { | ||
1254 | if (plugin_load(plugin,buf) == PLUGIN_USB_CONNECTED) | ||
1255 | reload_root = true; | ||
1256 | else | ||
1257 | restore = true; | ||
1258 | } | ||
1259 | break; | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1263 | if ( play ) { | ||
1264 | if ( global_settings.resume ) { | ||
1265 | /* the resume_index must always be the index in the | ||
1266 | shuffled list in case shuffle is enabled */ | ||
1267 | global_settings.resume_index = start_index; | ||
1268 | global_settings.resume_offset = 0; | ||
1269 | settings_save(); | ||
1270 | } | ||
1271 | |||
1272 | start_wps = true; | ||
1273 | } | ||
1274 | else if (*dirfilter > NUM_FILTER_MODES && | ||
1275 | *dirfilter != SHOW_FONT && | ||
1276 | *dirfilter != SHOW_PLUGINS) | ||
1277 | exit_func = true; | ||
1278 | } | ||
1279 | restore = true; | ||
1280 | break; | ||
1281 | |||
1282 | case TREE_PREV: | 775 | case TREE_PREV: |
1283 | case TREE_PREV | BUTTON_REPEAT: | 776 | case TREE_PREV | BUTTON_REPEAT: |
1284 | #ifdef TREE_RC_PREV | 777 | #ifdef TREE_RC_PREV |
1285 | case TREE_RC_PREV: | 778 | case TREE_RC_PREV: |
1286 | case TREE_RC_PREV | BUTTON_REPEAT: | 779 | case TREE_RC_PREV | BUTTON_REPEAT: |
1287 | #endif | 780 | #endif |
1288 | if(filesindir) { | 781 | if(tc.filesindir) { |
1289 | if(dircursor) { | 782 | if(tc.dircursor) { |
1290 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, false); | 783 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); |
1291 | dircursor--; | 784 | tc.dircursor--; |
1292 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, true); | 785 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); |
1293 | } | 786 | } |
1294 | else { | 787 | else { |
1295 | if (dirstart) { | 788 | if (tc.dirstart) { |
1296 | dirstart--; | 789 | tc.dirstart--; |
1297 | numentries = showdir(currdir, dirstart, dirfilter); | 790 | numentries = showdir(); |
1298 | update_all=true; | 791 | update_all=true; |
1299 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, true); | 792 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); |
1300 | } | 793 | } |
1301 | else { | 794 | else { |
1302 | if (numentries < tree_max_on_screen) { | 795 | if (numentries < tree_max_on_screen) { |
1303 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, | 796 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, |
1304 | false); | 797 | false); |
1305 | dircursor = numentries - 1; | 798 | tc.dircursor = numentries - 1; |
1306 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, | 799 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, |
1307 | true); | 800 | true); |
1308 | } | 801 | } |
1309 | else { | 802 | else { |
1310 | dirstart = numentries - tree_max_on_screen; | 803 | tc.dirstart = numentries - tree_max_on_screen; |
1311 | dircursor = tree_max_on_screen - 1; | 804 | tc.dircursor = tree_max_on_screen - 1; |
1312 | numentries = showdir(currdir, dirstart, dirfilter); | 805 | numentries = showdir(); |
1313 | update_all = true; | 806 | update_all = true; |
1314 | put_cursorxy(CURSOR_X, CURSOR_Y + | 807 | put_cursorxy(CURSOR_X, CURSOR_Y + |
1315 | tree_max_on_screen - 1, true); | 808 | tree_max_on_screen - 1, true); |
@@ -1326,32 +819,32 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1326 | case TREE_RC_NEXT: | 819 | case TREE_RC_NEXT: |
1327 | case TREE_RC_NEXT | BUTTON_REPEAT: | 820 | case TREE_RC_NEXT | BUTTON_REPEAT: |
1328 | #endif | 821 | #endif |
1329 | if(filesindir) | 822 | if(tc.filesindir) |
1330 | { | 823 | { |
1331 | if (dircursor + dirstart + 1 < numentries ) { | 824 | if (tc.dircursor + tc.dirstart + 1 < numentries ) { |
1332 | if(dircursor+1 < tree_max_on_screen) { | 825 | if(tc.dircursor+1 < tree_max_on_screen) { |
1333 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, false); | 826 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); |
1334 | dircursor++; | 827 | tc.dircursor++; |
1335 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, true); | 828 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); |
1336 | } | 829 | } |
1337 | else { | 830 | else { |
1338 | dirstart++; | 831 | tc.dirstart++; |
1339 | numentries = showdir(currdir, dirstart, dirfilter); | 832 | numentries = showdir(); |
1340 | update_all = true; | 833 | update_all = true; |
1341 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, true); | 834 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); |
1342 | } | 835 | } |
1343 | } | 836 | } |
1344 | else { | 837 | else { |
1345 | if(numentries < tree_max_on_screen) { | 838 | if(numentries < tree_max_on_screen) { |
1346 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, false); | 839 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, false); |
1347 | dirstart = dircursor = 0; | 840 | tc.dirstart = tc.dircursor = 0; |
1348 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, true); | 841 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); |
1349 | } | 842 | } |
1350 | else { | 843 | else { |
1351 | dirstart = dircursor = 0; | 844 | tc.dirstart = tc.dircursor = 0; |
1352 | numentries = showdir(currdir, dirstart, dirfilter); | 845 | numentries = showdir(); |
1353 | update_all=true; | 846 | update_all=true; |
1354 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, true); | 847 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); |
1355 | } | 848 | } |
1356 | } | 849 | } |
1357 | need_update = true; | 850 | need_update = true; |
@@ -1361,26 +854,26 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1361 | #ifdef TREE_PGUP | 854 | #ifdef TREE_PGUP |
1362 | case TREE_PGUP: | 855 | case TREE_PGUP: |
1363 | case TREE_PGUP | BUTTON_REPEAT: | 856 | case TREE_PGUP | BUTTON_REPEAT: |
1364 | if ( dirstart ) { | 857 | if ( tc.dirstart ) { |
1365 | dirstart -= tree_max_on_screen; | 858 | tc.dirstart -= tree_max_on_screen; |
1366 | if ( dirstart < 0 ) | 859 | if ( tc.dirstart < 0 ) |
1367 | dirstart = 0; | 860 | tc.dirstart = 0; |
1368 | } | 861 | } |
1369 | else | 862 | else |
1370 | dircursor = 0; | 863 | tc.dircursor = 0; |
1371 | restore = true; | 864 | restore = true; |
1372 | break; | 865 | break; |
1373 | 866 | ||
1374 | case TREE_PGDN: | 867 | case TREE_PGDN: |
1375 | case TREE_PGDN | BUTTON_REPEAT: | 868 | case TREE_PGDN | BUTTON_REPEAT: |
1376 | if ( dirstart < numentries - tree_max_on_screen ) { | 869 | if ( tc.dirstart < numentries - tree_max_on_screen ) { |
1377 | dirstart += tree_max_on_screen; | 870 | tc.dirstart += tree_max_on_screen; |
1378 | if ( dirstart > | 871 | if ( tc.dirstart > |
1379 | numentries - tree_max_on_screen ) | 872 | numentries - tree_max_on_screen ) |
1380 | dirstart = numentries - tree_max_on_screen; | 873 | tc.dirstart = numentries - tree_max_on_screen; |
1381 | } | 874 | } |
1382 | else | 875 | else |
1383 | dircursor = numentries - dirstart - 1; | 876 | tc.dircursor = numentries - tc.dirstart - 1; |
1384 | restore = true; | 877 | restore = true; |
1385 | break; | 878 | break; |
1386 | #endif | 879 | #endif |
@@ -1390,12 +883,15 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1390 | if (lastbutton != TREE_MENU_PRE) | 883 | if (lastbutton != TREE_MENU_PRE) |
1391 | break; | 884 | break; |
1392 | #endif | 885 | #endif |
1393 | if (*dirfilter < NUM_FILTER_MODES) | 886 | /* don't enter menu from plugin browser */ |
887 | if (*tc.dirfilter < NUM_FILTER_MODES) | ||
1394 | { | 888 | { |
1395 | lcd_stop_scroll(); | 889 | lcd_stop_scroll(); |
1396 | if (main_menu()) | 890 | if (main_menu()) |
1397 | reload_root = true; | 891 | reload_root = true; |
1398 | restore = true; | 892 | restore = true; |
893 | |||
894 | id3db = check_changed_id3mode(id3db); | ||
1399 | } | 895 | } |
1400 | break; | 896 | break; |
1401 | 897 | ||
@@ -1405,7 +901,7 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1405 | break; | 901 | break; |
1406 | #endif | 902 | #endif |
1407 | /* don't enter wps from plugin browser etc */ | 903 | /* don't enter wps from plugin browser etc */ |
1408 | if (*dirfilter < NUM_FILTER_MODES) | 904 | if (*tc.dirfilter < NUM_FILTER_MODES) |
1409 | { | 905 | { |
1410 | if (mpeg_status() & MPEG_STATUS_PLAY) | 906 | if (mpeg_status() & MPEG_STATUS_PLAY) |
1411 | { | 907 | { |
@@ -1421,16 +917,20 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1421 | 917 | ||
1422 | #ifdef BUTTON_F2 | 918 | #ifdef BUTTON_F2 |
1423 | case BUTTON_F2: | 919 | case BUTTON_F2: |
1424 | if (*dirfilter < NUM_FILTER_MODES) | 920 | /* don't enter f2 from plugin browser */ |
921 | if (*tc.dirfilter < NUM_FILTER_MODES) | ||
1425 | { | 922 | { |
1426 | if (quick_screen(CONTEXT_TREE, BUTTON_F2)) | 923 | if (quick_screen(CONTEXT_TREE, BUTTON_F2)) |
1427 | reload_root = true; | 924 | reload_root = true; |
1428 | restore = true; | 925 | restore = true; |
926 | |||
927 | id3db = check_changed_id3mode(id3db); | ||
1429 | break; | 928 | break; |
1430 | } | 929 | } |
1431 | 930 | ||
1432 | case BUTTON_F3: | 931 | case BUTTON_F3: |
1433 | if (*dirfilter < NUM_FILTER_MODES) | 932 | /* don't enter f3 from plugin browser */ |
933 | if (*tc.dirfilter < NUM_FILTER_MODES) | ||
1434 | { | 934 | { |
1435 | if (quick_screen(CONTEXT_TREE, BUTTON_F3)) | 935 | if (quick_screen(CONTEXT_TREE, BUTTON_F3)) |
1436 | reload_root = true; | 936 | reload_root = true; |
@@ -1452,12 +952,12 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1452 | else { | 952 | else { |
1453 | if (currdir[1]) | 953 | if (currdir[1]) |
1454 | snprintf(buf, sizeof buf, "%s/%s", | 954 | snprintf(buf, sizeof buf, "%s/%s", |
1455 | currdir, dircache[dircursor+dirstart].name); | 955 | currdir, dircache[tc.dircursor+tc.dirstart].name); |
1456 | else | 956 | else |
1457 | snprintf(buf, sizeof buf, "/%s", | 957 | snprintf(buf, sizeof buf, "/%s", |
1458 | dircache[dircursor+dirstart].name); | 958 | dircache[tc.dircursor+tc.dirstart].name); |
1459 | onplay_result = onplay(buf, | 959 | onplay_result = onplay(buf, |
1460 | dircache[dircursor+dirstart].attr); | 960 | dircache[tc.dircursor+tc.dirstart].attr); |
1461 | } | 961 | } |
1462 | 962 | ||
1463 | switch (onplay_result) | 963 | switch (onplay_result) |
@@ -1485,7 +985,7 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1485 | if (dircache[lasti].attr & ATTR_DIRECTORY) | 985 | if (dircache[lasti].attr & ATTR_DIRECTORY) |
1486 | { | 986 | { |
1487 | DEBUGF("Playing directory thumbnail: %s", currdir); | 987 | DEBUGF("Playing directory thumbnail: %s", currdir); |
1488 | res = play_dirname(lasti); | 988 | res = ft_play_dirname(lasti); |
1489 | if (res < 0) /* failed, not existing */ | 989 | if (res < 0) /* failed, not existing */ |
1490 | { /* say the number instead, as a fallback */ | 990 | { /* say the number instead, as a fallback */ |
1491 | talk_id(VOICE_DIR, false); | 991 | talk_id(VOICE_DIR, false); |
@@ -1495,10 +995,10 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1495 | else | 995 | else |
1496 | { | 996 | { |
1497 | DEBUGF("Playing file thumbnail: %s/%s%s\n", | 997 | DEBUGF("Playing file thumbnail: %s/%s%s\n", |
1498 | currdir, dircache[lasti].name, file_thumbnail_ext); | 998 | currdir, dircache[lasti].name, file_thumbnail_ext); |
1499 | /* no fallback necessary, we knew in advance | 999 | /* no fallback necessary, we knew in advance |
1500 | that the file exists */ | 1000 | that the file exists */ |
1501 | play_filename(currdir, dircache[lasti].name); | 1001 | ft_play_filename(currdir, dircache[lasti].name); |
1502 | } | 1002 | } |
1503 | thumbnail_time = -1; /* job done */ | 1003 | thumbnail_time = -1; /* job done */ |
1504 | } | 1004 | } |
@@ -1508,7 +1008,7 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1508 | default: | 1008 | default: |
1509 | if(default_event_handler(button) == SYS_USB_CONNECTED) | 1009 | if(default_event_handler(button) == SYS_USB_CONNECTED) |
1510 | { | 1010 | { |
1511 | if(*dirfilter > NUM_FILTER_MODES) | 1011 | if(*tc.dirfilter > NUM_FILTER_MODES) |
1512 | /* leave sub-browsers after usb, doing otherwise | 1012 | /* leave sub-browsers after usb, doing otherwise |
1513 | might be confusing to the user */ | 1013 | might be confusing to the user */ |
1514 | exit_func = true; | 1014 | exit_func = true; |
@@ -1538,22 +1038,22 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1538 | 1038 | ||
1539 | /* do we need to rescan dir? */ | 1039 | /* do we need to rescan dir? */ |
1540 | if (reload_dir || reload_root || | 1040 | if (reload_dir || reload_root || |
1541 | lastfilter != *dirfilter || | 1041 | lastfilter != *tc.dirfilter || |
1542 | lastsortcase != global_settings.sort_case) | 1042 | lastsortcase != global_settings.sort_case) |
1543 | { | 1043 | { |
1544 | if ( reload_root ) { | 1044 | if ( reload_root ) { |
1545 | strcpy(currdir, "/"); | 1045 | strcpy(currdir, "/"); |
1546 | dirlevel = 0; | 1046 | tc.dirlevel = 0; |
1547 | reload_root = false; | 1047 | reload_root = false; |
1548 | } | 1048 | } |
1549 | if (! reload_dir ) | 1049 | if (! reload_dir ) |
1550 | { | 1050 | { |
1551 | dircursor = 0; | 1051 | tc.dircursor = 0; |
1552 | dirstart = 0; | 1052 | tc.dirstart = 0; |
1553 | lastdir[0] = 0; | 1053 | lastdir[0] = 0; |
1554 | } | 1054 | } |
1555 | 1055 | ||
1556 | lastfilter = *dirfilter; | 1056 | lastfilter = *tc.dirfilter; |
1557 | lastsortcase = global_settings.sort_case; | 1057 | lastsortcase = global_settings.sort_case; |
1558 | restore = true; | 1058 | restore = true; |
1559 | while (button_get(false)); /* clear button queue */ | 1059 | while (button_get(false)); /* clear button queue */ |
@@ -1571,9 +1071,9 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1571 | 1071 | ||
1572 | /* We need to adjust if the number of lines on screen have | 1072 | /* We need to adjust if the number of lines on screen have |
1573 | changed because of a status bar change */ | 1073 | changed because of a status bar change */ |
1574 | if(CURSOR_Y+LINE_Y+dircursor>tree_max_on_screen) { | 1074 | if(CURSOR_Y+LINE_Y+tc.dircursor>tree_max_on_screen) { |
1575 | dirstart++; | 1075 | tc.dirstart++; |
1576 | dircursor--; | 1076 | tc.dircursor--; |
1577 | } | 1077 | } |
1578 | #ifdef HAVE_LCD_BITMAP | 1078 | #ifdef HAVE_LCD_BITMAP |
1579 | /* the sub-screen might've ruined the margins */ | 1079 | /* the sub-screen might've ruined the margins */ |
@@ -1581,72 +1081,98 @@ static bool dirbrowse(const char *root, const int *dirfilter) | |||
1581 | icon */ | 1081 | icon */ |
1582 | lcd_setfont(FONT_UI); | 1082 | lcd_setfont(FONT_UI); |
1583 | #endif | 1083 | #endif |
1584 | numentries = showdir(currdir, dirstart, dirfilter); | 1084 | numentries = showdir(); |
1585 | update_all = true; | 1085 | update_all = true; |
1586 | put_cursorxy(CURSOR_X, CURSOR_Y + dircursor, true); | 1086 | put_cursorxy(CURSOR_X, CURSOR_Y + tc.dircursor, true); |
1587 | 1087 | ||
1588 | need_update = true; | 1088 | need_update = true; |
1589 | reload_dir = false; | 1089 | reload_dir = false; |
1590 | } | 1090 | } |
1591 | 1091 | ||
1592 | if ( numentries && need_update) { | 1092 | if ( numentries && need_update) { |
1593 | i = dirstart+dircursor; | 1093 | i = tc.dirstart+tc.dircursor; |
1594 | 1094 | ||
1595 | /* if MP3 filter is on, cut off the extension */ | 1095 | /* if MP3 filter is on, cut off the extension */ |
1596 | if(lasti!=i || restore) { | 1096 | if(lasti!=i || restore) { |
1097 | char* name; | ||
1098 | int attr = 0; | ||
1099 | |||
1100 | if (id3db) | ||
1101 | name = ((char**)tc.dircache)[lasti * 2]; | ||
1102 | else { | ||
1103 | struct entry* dc = tc.dircache; | ||
1104 | struct entry* e = &dc[lasti]; | ||
1105 | name = e->name; | ||
1106 | attr = e->attr; | ||
1107 | } | ||
1108 | |||
1597 | lcd_stop_scroll(); | 1109 | lcd_stop_scroll(); |
1598 | 1110 | ||
1599 | /* So if lastdircursor and dircursor differ, and then full | 1111 | /* So if lastdircursor and dircursor differ, and then full |
1600 | screen was not refreshed, restore the previous line */ | 1112 | screen was not refreshed, restore the previous line */ |
1601 | if ((lastdircursor != dircursor) && !update_all ) { | 1113 | if ((lastdircursor != tc.dircursor) && !update_all ) { |
1602 | showfileline(lastdircursor, lasti, false, dirfilter); /* no scroll */ | 1114 | showfileline(lastdircursor, name, attr, false); /* no scroll */ |
1603 | } | 1115 | } |
1604 | lasti=i; | 1116 | lasti=i; |
1605 | lastdircursor=dircursor; | 1117 | lastdircursor=tc.dircursor; |
1606 | thumbnail_time = -1; /* cancel whatever we were about to say */ | 1118 | thumbnail_time = -1; /* cancel whatever we were about to say */ |
1607 | 1119 | ||
1608 | showfileline(dircursor, i, true, dirfilter); /* scroll please */ | 1120 | if (id3db) |
1121 | name = ((char**)tc.dircache)[lasti * 2]; | ||
1122 | else { | ||
1123 | struct entry* dc = tc.dircache; | ||
1124 | struct entry* e = &dc[lasti]; | ||
1125 | name = e->name; | ||
1126 | attr = e->attr; | ||
1127 | } | ||
1128 | showfileline(tc.dircursor, name, attr, true); /* scroll please */ | ||
1609 | need_update = true; | 1129 | need_update = true; |
1610 | 1130 | ||
1611 | if (dircache[i].attr & ATTR_DIRECTORY) /* directory? */ | 1131 | if (dircache[i].attr & ATTR_DIRECTORY) /* directory? */ |
1612 | { | 1132 | { |
1613 | /* play directory thumbnail */ | 1133 | /* play directory thumbnail */ |
1614 | if (global_settings.talk_dir == 3) /* hover */ | 1134 | switch (global_settings.talk_dir) { |
1615 | { /* "schedule" a thumbnail, to have a little dalay */ | 1135 | case 1: /* dirs as numbers */ |
1616 | thumbnail_time = current_tick + HOVER_DELAY; | 1136 | talk_id(VOICE_DIR, false); |
1617 | } | 1137 | talk_number(i+1, true); |
1618 | else if (global_settings.talk_dir == 1) /* dirs as numbers */ | 1138 | break; |
1619 | { | 1139 | |
1620 | talk_id(VOICE_DIR, false); | 1140 | case 2: /* dirs spelled */ |
1621 | talk_number(i+1, true); | 1141 | talk_spell(dircache[i].name, false); |
1622 | } | 1142 | break; |
1623 | else if (global_settings.talk_dir == 2) /* dirs spelled */ | 1143 | |
1624 | { | 1144 | case 3: /* thumbnail clip */ |
1625 | talk_spell(dircache[i].name, false); | 1145 | /* "schedule" a thumbnail, to have a little dalay */ |
1146 | thumbnail_time = current_tick + HOVER_DELAY; | ||
1147 | break; | ||
1148 | |||
1149 | default: | ||
1150 | break; | ||
1626 | } | 1151 | } |
1627 | } | 1152 | } |
1628 | else /* file */ | 1153 | else /* file */ |
1629 | { | 1154 | { |
1630 | int voicemethod = global_settings.talk_file; | 1155 | switch (global_settings.talk_file) { |
1631 | if (voicemethod == 3) /* thumbnail clip */ | 1156 | case 1: /* files as numbers */ |
1632 | { /* "schedule" a thumbnail, to have a little delay */ | 1157 | ft_play_filenumber(i-tc.dirsindir+1, |
1633 | if (dircache[i].attr & TREE_ATTR_THUMBNAIL) | 1158 | dircache[i].attr & TREE_ATTR_MASK); |
1634 | { | 1159 | break; |
1635 | thumbnail_time = current_tick + HOVER_DELAY; | 1160 | |
1636 | } | 1161 | case 2: /* files spelled */ |
1637 | else | 1162 | talk_spell(dircache[i].name, false); |
1638 | { /* say the number as fallback */ | 1163 | break; |
1639 | voicemethod = 1; | 1164 | |
1640 | } | 1165 | case 3: /* thumbnail clip */ |
1641 | } | 1166 | /* "schedule" a thumbnail, to have a little delay */ |
1642 | if (voicemethod == 1) /* files as numbers */ | 1167 | if (dircache[i].attr & TREE_ATTR_THUMBNAIL) |
1643 | { | 1168 | thumbnail_time = current_tick + HOVER_DELAY; |
1644 | play_filenumber(i-dirsindir+1, | 1169 | else |
1645 | dircache[i].attr & TREE_ATTR_MASK); | 1170 | /* spell the number as fallback */ |
1646 | } | 1171 | talk_spell(dircache[i].name, false); |
1647 | else if (voicemethod == 2) /* files spelled */ | 1172 | break; |
1648 | { | 1173 | |
1649 | talk_spell(dircache[i].name, false); | 1174 | default: |
1175 | break; | ||
1650 | } | 1176 | } |
1651 | } | 1177 | } |
1652 | } | 1178 | } |
@@ -1752,7 +1278,7 @@ bool create_playlist(void) | |||
1752 | char filename[MAX_PATH]; | 1278 | char filename[MAX_PATH]; |
1753 | 1279 | ||
1754 | snprintf(filename, sizeof filename, "%s.m3u", | 1280 | snprintf(filename, sizeof filename, "%s.m3u", |
1755 | currdir[1] ? currdir : "/root"); | 1281 | tc.currdir[1] ? tc.currdir : "/root"); |
1756 | 1282 | ||
1757 | lcd_clear_display(); | 1283 | lcd_clear_display(); |
1758 | lcd_puts(0,0,str(LANG_CREATING)); | 1284 | lcd_puts(0,0,str(LANG_CREATING)); |
@@ -1763,7 +1289,8 @@ bool create_playlist(void) | |||
1763 | if (fd < 0) | 1289 | if (fd < 0) |
1764 | return false; | 1290 | return false; |
1765 | 1291 | ||
1766 | snprintf(filename, sizeof(filename), "%s", currdir[1] ? currdir : "/"); | 1292 | snprintf(filename, sizeof(filename), "%s", |
1293 | tc.currdir[1] ? tc.currdir : "/"); | ||
1767 | plsize = 0; | 1294 | plsize = 0; |
1768 | add_dir(filename, sizeof(filename), fd); | 1295 | add_dir(filename, sizeof(filename), fd); |
1769 | close(fd); | 1296 | close(fd); |
@@ -1775,37 +1302,51 @@ bool create_playlist(void) | |||
1775 | bool rockbox_browse(const char *root, int dirfilter) | 1302 | bool rockbox_browse(const char *root, int dirfilter) |
1776 | { | 1303 | { |
1777 | bool rc; | 1304 | bool rc; |
1778 | int dircursor_save = dircursor; | 1305 | int dircursor_save = tc.dircursor; |
1779 | int dirstart_save = dirstart; | 1306 | int dirstart_save = tc.dirstart; |
1780 | int dirlevel_save = dirlevel; | 1307 | int dirlevel_save = tc.dirlevel; |
1781 | int dirpos_save = dirpos[0]; | 1308 | int dirpos_save = tc.dirpos[0]; |
1782 | int cursorpos_save = cursorpos[0]; | 1309 | int cursorpos_save = tc.cursorpos[0]; |
1783 | 1310 | int* dirfilter_save = tc.dirfilter; | |
1784 | memcpy(currdir_save, currdir, sizeof(currdir)); | 1311 | static char currdir_save[MAX_PATH]; |
1312 | |||
1313 | memcpy(currdir_save, tc.currdir, sizeof(tc.currdir)); | ||
1785 | reload_dir = true; | 1314 | reload_dir = true; |
1315 | memcpy(tc.currdir, root, sizeof(tc.currdir)); | ||
1786 | start_wps = false; | 1316 | start_wps = false; |
1787 | rc = dirbrowse(root, &dirfilter); | 1317 | tc.dirfilter = &dirfilter; |
1788 | memcpy(currdir, currdir_save, sizeof(currdir)); | 1318 | |
1319 | rc = dirbrowse(); | ||
1789 | 1320 | ||
1321 | memcpy(tc.currdir, currdir_save, sizeof(tc.currdir)); | ||
1790 | reload_dir = true; | 1322 | reload_dir = true; |
1791 | dirstart = dirstart_save; | 1323 | tc.dirstart = dirstart_save; |
1792 | cursorpos[0] = cursorpos_save; | 1324 | tc.cursorpos[0] = cursorpos_save; |
1793 | dirlevel = dirlevel_save; | 1325 | tc.dirlevel = dirlevel_save; |
1794 | dircursor = dircursor_save; | 1326 | tc.dircursor = dircursor_save; |
1795 | dirpos[0] = dirpos_save; | 1327 | tc.dirpos[0] = dirpos_save; |
1328 | tc.dirfilter = dirfilter_save; | ||
1796 | 1329 | ||
1797 | return false; | 1330 | return false; |
1798 | } | 1331 | } |
1799 | 1332 | ||
1800 | void tree_init(void) | 1333 | void tree_init(void) |
1801 | { | 1334 | { |
1335 | /* initialize tree context struct */ | ||
1336 | memset(&tc, 0, sizeof(tc)); | ||
1337 | tc.dirfilter = &global_settings.dirfilter; | ||
1338 | |||
1339 | db_init(); | ||
1340 | |||
1802 | /* We copy the settings value in case it is changed by the user. We can't | 1341 | /* We copy the settings value in case it is changed by the user. We can't |
1803 | use it until the next reboot. */ | 1342 | use it until the next reboot. */ |
1804 | max_files_in_dir = global_settings.max_files_in_dir; | 1343 | int max_files = global_settings.max_files_in_dir; |
1805 | name_buffer_size = AVERAGE_FILENAME_LENGTH * max_files_in_dir; | ||
1806 | 1344 | ||
1807 | name_buffer = buffer_alloc(name_buffer_size); | 1345 | tc.name_buffer_size = AVERAGE_FILENAME_LENGTH * max_files; |
1808 | dircache = buffer_alloc(max_files_in_dir * sizeof(struct entry)); | 1346 | tc.name_buffer = buffer_alloc(tc.name_buffer_size); |
1347 | |||
1348 | tc.dircache_size = max_files * sizeof(struct entry); | ||
1349 | tc.dircache = buffer_alloc(tc.dircache_size); | ||
1809 | } | 1350 | } |
1810 | 1351 | ||
1811 | void bookmark_play(char *resume_file, int index, int offset, int seed, | 1352 | void bookmark_play(char *resume_file, int index, int offset, int seed, |
@@ -1875,3 +1416,77 @@ void bookmark_play(char *resume_file, int index, int offset, int seed, | |||
1875 | 1416 | ||
1876 | start_wps=true; | 1417 | start_wps=true; |
1877 | } | 1418 | } |
1419 | |||
1420 | int ft_play_filenumber(int pos, int attr) | ||
1421 | { | ||
1422 | /* try to find a voice ID for the extension, if known */ | ||
1423 | unsigned int j; | ||
1424 | int ext_id = -1; /* default to none */ | ||
1425 | for (j=0; j<sizeof(filetypes)/sizeof(*filetypes); j++) | ||
1426 | { | ||
1427 | if (attr == filetypes[j].tree_attr) | ||
1428 | { | ||
1429 | ext_id = filetypes[j].voiceclip; | ||
1430 | break; | ||
1431 | } | ||
1432 | } | ||
1433 | |||
1434 | talk_id(VOICE_FILE, false); | ||
1435 | talk_number(pos, true); | ||
1436 | talk_id(ext_id, true); | ||
1437 | return 1; | ||
1438 | } | ||
1439 | |||
1440 | int ft_play_dirname(int start_index) | ||
1441 | { | ||
1442 | int fd; | ||
1443 | char dirname_mp3_filename[MAX_PATH+1]; | ||
1444 | struct entry *dircache = tc.dircache; | ||
1445 | |||
1446 | if (mpeg_status() & MPEG_STATUS_PLAY) | ||
1447 | return 0; | ||
1448 | |||
1449 | snprintf(dirname_mp3_filename, sizeof(dirname_mp3_filename), "%s/%s/%s", | ||
1450 | tc.currdir, dircache[start_index].name, dir_thumbnail_name); | ||
1451 | |||
1452 | DEBUGF("Checking for %s\n", dirname_mp3_filename); | ||
1453 | |||
1454 | fd = open(dirname_mp3_filename, O_RDONLY); | ||
1455 | if (fd < 0) | ||
1456 | { | ||
1457 | DEBUGF("Failed to find: %s\n", dirname_mp3_filename); | ||
1458 | return -1; | ||
1459 | } | ||
1460 | |||
1461 | close(fd); | ||
1462 | |||
1463 | DEBUGF("Found: %s\n", dirname_mp3_filename); | ||
1464 | |||
1465 | talk_file(dirname_mp3_filename, false); | ||
1466 | return 1; | ||
1467 | } | ||
1468 | |||
1469 | void ft_play_filename(char *dir, char *file) | ||
1470 | { | ||
1471 | char name_mp3_filename[MAX_PATH+1]; | ||
1472 | |||
1473 | if (mpeg_status() & MPEG_STATUS_PLAY) | ||
1474 | return; | ||
1475 | |||
1476 | if (strcasecmp(&file[strlen(file) - strlen(file_thumbnail_ext)], | ||
1477 | file_thumbnail_ext)) | ||
1478 | { /* file has no .talk extension */ | ||
1479 | snprintf(name_mp3_filename, sizeof(name_mp3_filename), | ||
1480 | "%s/%s%s", dir, file, file_thumbnail_ext); | ||
1481 | |||
1482 | talk_file(name_mp3_filename, false); | ||
1483 | } | ||
1484 | else | ||
1485 | { /* it already is a .talk file, play this directly */ | ||
1486 | snprintf(name_mp3_filename, sizeof(name_mp3_filename), | ||
1487 | "%s/%s", dir, file); | ||
1488 | talk_id(LANG_VOICE_DIR_HOVER, false); /* prefix it */ | ||
1489 | talk_file(name_mp3_filename, true); | ||
1490 | } | ||
1491 | } | ||
1492 | |||