/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 Daniel Stenberg * * 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 #include #include #include #include "dir.h" #include "file.h" #include "lcd.h" #include "button.h" #include "kernel.h" #include "tree.h" #include "play.h" #include "main_menu.h" #include "sprintf.h" #include "mpeg.h" #ifdef HAVE_LCD_BITMAP #include "icons.h" #endif #define MAX_FILES_IN_DIR 200 #define TREE_MAX_FILENAMELEN 128 #define MAX_DIR_LEVELS 10 struct entry { bool file; /* true if file, false if dir */ char name[TREE_MAX_FILENAMELEN]; }; static struct entry dircache[MAX_FILES_IN_DIR]; static struct entry* dircacheptr[MAX_FILES_IN_DIR]; static int filesindir; void browse_root(void) { dirbrowse("/"); } #ifdef HAVE_LCD_BITMAP #define TREE_MAX_ON_SCREEN 7 #define TREE_MAX_LEN_DISPLAY 16 /* max length that fits on screen */ #define MARGIN_Y 8 /* Y pixel margin */ #define MARGIN_X 12 /* X pixel margin */ #define LINE_Y 0 /* Y position the entry-list starts at */ #define LINE_X 2 /* X position the entry-list starts at */ #define LINE_HEIGTH 8 /* pixels for each text line */ #define CURSOR_CHAR "-" extern unsigned char bitmap_icons_6x8[LastIcon][6]; #else /* HAVE_LCD_BITMAP */ #define TREE_MAX_ON_SCREEN 2 #define TREE_MAX_LEN_DISPLAY 11 /* max length that fits on screen */ #define LINE_Y 0 /* Y position the entry-list starts at */ #define LINE_X 1 /* X position the entry-list starts at */ #ifdef HAVE_NEW_CHARCELL_LCD #define CURSOR_CHAR "\x7e" #else #define CURSOR_CHAR "\x89" #endif #endif /* HAVE_LCD_BITMAP */ static int compare(const void* e1, const void* e2) { return strncmp((*(struct entry**)e1)->name, (*(struct entry**)e2)->name, TREE_MAX_FILENAMELEN); } static int showdir(char *path, int start) { static char lastdir[256] = {0}; #ifdef HAVE_LCD_BITMAP int icon_type = 0; #endif int i; /* new dir? cache it */ if (strncmp(path,lastdir,sizeof(lastdir))) { DIR *dir = opendir(path); if(!dir) return -1; /* not a directory */ memset(dircacheptr,0,sizeof(dircacheptr)); for ( i=0; id_name[0] == '.') { /* skip names starting with a dot */ i--; continue; } dircache[i].file = !(entry->attribute & ATTR_DIRECTORY); strncpy(dircache[i].name,entry->d_name,TREE_MAX_FILENAMELEN); dircache[i].name[TREE_MAX_FILENAMELEN-1]=0; dircacheptr[i] = &dircache[i]; } filesindir = i; closedir(dir); strncpy(lastdir,path,sizeof(lastdir)); lastdir[sizeof(lastdir)-1] = 0; qsort(dircacheptr,filesindir,sizeof(struct entry*),compare); } #ifdef HAVE_NEW_CHARCELL_LCD lcd_double_height(false); #endif lcd_clear_display(); #ifdef HAVE_LCD_BITMAP lcd_putsxy(0,0, "[Browse]",0); lcd_update(); #endif for ( i=start; i < start+TREE_MAX_ON_SCREEN; i++ ) { int len; if ( i >= filesindir ) break; len = strlen(dircacheptr[i]->name); #ifdef HAVE_LCD_BITMAP if ( dircacheptr[i]->file ) icon_type=File; else icon_type=Folder; lcd_bitmap(bitmap_icons_6x8[icon_type], 6, MARGIN_Y+(i-start)*LINE_HEIGTH, 6, 8, true); #endif if(len < TREE_MAX_LEN_DISPLAY) lcd_puts(LINE_X, LINE_Y+i-start, dircacheptr[i]->name); else { char storage = dircacheptr[i]->name[TREE_MAX_LEN_DISPLAY]; dircacheptr[i]->name[TREE_MAX_LEN_DISPLAY]=0; lcd_puts(LINE_X, LINE_Y+i-start, dircacheptr[i]->name); dircacheptr[i]->name[TREE_MAX_LEN_DISPLAY]=storage; } } return filesindir; } static int numentries=0; static int dircursor=0; static int start=0; static int dirpos[MAX_DIR_LEVELS]; static int cursorpos[MAX_DIR_LEVELS]; static int dirlevel=0; static int playing = 0; static char currdir[255]; /* QUICK HACK! this should be handled by the playlist code later */ char* peek_next_track(int type) { static char buf[256]; /* next-song only works when playing */ if (!playing) return NULL; switch(playing) { default: case 1: /* play-full-dir mode */ /* get next track in dir */ while (dircursor + start + 1 < numentries ) { if(dircursor+1 < TREE_MAX_ON_SCREEN) dircursor++; else start++; if ( dircacheptr[dircursor+start]->file && dircacheptr[dircursor+start]->name[strlen(dircacheptr[dircursor+start]->name)-1] == '3') { snprintf(buf,sizeof buf,"%s/%s", currdir, dircacheptr[dircursor+start]->name ); lcd_clear_display(); lcd_puts(0,0,""); lcd_puts(0,1,""); return buf; } } break; case 2: /* playlist mode */ return playlist_next(type); } return NULL; } bool dirbrowse(char *root) { char buf[255]; int i; lcd_clear_display(); #ifdef HAVE_LCD_BITMAP lcd_putsxy(0,0, "[Browse]",0); lcd_setmargins(0,MARGIN_Y); lcd_setfont(0); #endif memcpy(currdir,root,sizeof(currdir)); numentries = showdir(root, start); if (numentries == -1) return -1; /* root is not a directory */ lcd_puts(0, dircursor, CURSOR_CHAR); #ifdef HAVE_LCD_BITMAP lcd_update(); #endif while(1) { switch(button_get(true)) { #if defined(SIMULATOR) && defined(HAVE_RECODER_KEYPAD) case BUTTON_OFF: return false; #endif #ifdef HAVE_RECORDER_KEYPAD case BUTTON_LEFT: #else case BUTTON_STOP: #endif i=strlen(currdir); if (i>1) { while (currdir[i-1]!='/') i--; strcpy(buf,&currdir[i]); if (i==1) currdir[i]=0; else currdir[i-1]=0; dirlevel--; if ( dirlevel < MAX_DIR_LEVELS ) { start = dirpos[dirlevel]; dircursor = cursorpos[dirlevel]; } else start = dircursor = 0; numentries = showdir(currdir, start); lcd_puts(0, LINE_Y+dircursor, CURSOR_CHAR); } else mpeg_stop(); break; #ifdef HAVE_RECORDER_KEYPAD case BUTTON_RIGHT: #endif case BUTTON_PLAY: if ((currdir[0]=='/') && (currdir[1]==0)) { snprintf(buf,sizeof(buf),"%s%s",currdir, dircacheptr[dircursor+start]->name); } else { snprintf(buf,sizeof(buf),"%s/%s",currdir, dircacheptr[dircursor+start]->name); } if (!dircacheptr[dircursor+start]->file) { memcpy(currdir,buf,sizeof(currdir)); if ( dirlevel < MAX_DIR_LEVELS ) { dirpos[dirlevel] = start; cursorpos[dirlevel] = dircursor; } dirlevel++; dircursor=0; start=0; } else { int len= strlen(dircacheptr[dircursor+start]->name); if((len > 4) && !strcmp(&dircacheptr[dircursor+start]->name[len-4], ".m3u")) { playing = 2; play_list(currdir, dircacheptr[dircursor+start]->name); } else { playing = 1; playtune(currdir, dircacheptr[dircursor+start]->name); playing = 0; #ifdef HAVE_LCD_BITMAP lcd_setmargins(0, MARGIN_Y); lcd_setfont(0); #endif } } numentries = showdir(currdir, start); lcd_puts(0, LINE_Y+dircursor, CURSOR_CHAR); break; #ifdef HAVE_RECORDER_KEYPAD case BUTTON_UP: #else case BUTTON_LEFT: #endif if(dircursor) { lcd_puts(0, LINE_Y+dircursor, " "); dircursor--; lcd_puts(0, LINE_Y+dircursor, CURSOR_CHAR); lcd_update(); } else { if (start) { start--; numentries = showdir(currdir, start); lcd_puts(0, LINE_Y+dircursor, CURSOR_CHAR); } } break; #ifdef HAVE_RECORDER_KEYPAD case BUTTON_DOWN: #else case BUTTON_RIGHT: #endif if (dircursor + start + 1 < numentries ) { if(dircursor+1 < TREE_MAX_ON_SCREEN) { lcd_puts(0, LINE_Y+dircursor, " "); dircursor++; lcd_puts(0, LINE_Y+dircursor, CURSOR_CHAR); } else { start++; numentries = showdir(currdir, start); lcd_puts(0, LINE_Y+dircursor, CURSOR_CHAR); } } break; #ifdef HAVE_RECORDER_KEYPAD case BUTTON_F1: case BUTTON_F2: case BUTTON_F3: #else case BUTTON_MENU: #endif main_menu(); /* restore display */ /* TODO: this is just a copy from BUTTON_STOP, fix it */ lcd_clear_display(); #ifdef HAVE_LCD_BITMAP lcd_putsxy(0,0, "[Browse]",0); lcd_setmargins(0,MARGIN_Y); lcd_setfont(0); #endif numentries = showdir(currdir, start); lcd_puts(0, LINE_Y+dircursor, CURSOR_CHAR); break; } lcd_update(); } return false; }