/* ds48 - Nintendo DS ZX Spectrum emulator. Copyright (C) 2007 Ian Cowburn This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. $Id$ */ #include #include #include #include #include #include "framebuffer.h" #include "config.h" /* ---------------------------------------- PRIVATE INTERFACES - PATH HANDLING */ #define FSEL_FILENAME_LEN 20 #define FSEL_LINES 16 #define FSEL_MAX_FILES 512 #define FSEL_LIST_Y 10 #define FSEL_LIST_H FSEL_LINES*8 typedef struct { char name[FSEL_FILENAME_LEN+1]; int is_dir; int size; } FSEL_File; static FSEL_File fsel[FSEL_MAX_FILES]; static void CheckPath(char *path) { size_t l; l = strlen(path); if (l == 1) { path[0] = '/'; } else { if (path[l-1] != '/') { path[l] = '/'; path[l+1] = 0; } } } static void AddPath(char *path, const char *dir) { if (strcmp(dir,"..") == 0) { size_t l; l = strlen(path); if (l > 1) { path[--l] = 0; while(l && path[l] != '/') { path[l--] = 0; } } } else { strcat(path,dir); strcat(path,"/"); } } static int SortFiles(const void *a, const void *b) { const FSEL_File *f1; const FSEL_File *f2; f1 = (const FSEL_File *)a; f2 = (const FSEL_File *)b; if (f1->is_dir == f2->is_dir) { return strcasecmp(f1->name, f2->name); } else if (f1->is_dir) { return -1; } else { return 1; } } static int ValidFilename(const char *name, int is_dir, const char *filter) { size_t l; size_t f; l = strlen(name); if (l > FSEL_FILENAME_LEN) return 0; if (strcmp(name,".") == 0) return 0; if (is_dir || !filter) return 1; f = strlen(filter); if (l > f) { if (strcasecmp(name+l-f,filter) == 0) { return 1; } } return 0; } static int LoadDir(const char *path, const char *filter) { DIR_ITER *dir; struct stat st; char name[FILENAME_MAX]; int no = 0; if ((dir = diropen(path))) { while(no < FSEL_MAX_FILES && dirnext(dir,name,&st) == 0) { if (ValidFilename(name, (st.st_mode & S_IFDIR), filter)) { strcpy(fsel[no].name,name); fsel[no].is_dir = (st.st_mode & S_IFDIR); fsel[no].size = (int)st.st_size; no++; } } dirclose(dir); qsort(fsel,no,sizeof fsel[0],SortFiles); } return no; } /* ---------------------------------------- PUBLIC INTERFACES */ int GUI_Menu(const char *opts[]) { int x,y; int h; int w; int no; int sel; int f; int done; int defer; w=0; h=0; sel=0; done=FALSE; defer=FALSE; for(no=0;opts[no];no++) { h+=16; if (strlen(opts[no])>w) { w=strlen(opts[no]); } } w=w*8+16; x=SCREEN_WIDTH/2-w/2; y=SCREEN_HEIGHT/2-h/2; while(!done) { uint32 key=0; FB_FillBox(x,y,w,h,COL_BLACK); FB_Box(x,y,w,h,COL_WHITE); FB_FillBox(x+1,y+sel*16+1,w-2,14,COL_GUISELECT); for(f=0;f=x && tp.px<(w+w) && tp.py>=y && tp.py<(y+h)) { defer=TRUE; sel=(tp.py-y)/16; } } } } return sel; } void GUI_Alert(int fatal, const char *text) { char line[80]; int h; const char *p; char *d; h=40; p=text; while(*p) { if (*p++=='\n') { h+=8; } } FB_FillBox(0,0,SCREEN_WIDTH,h,COL_BLACK); FB_Box(1,1,SCREEN_WIDTH-2,h-2,COL_WHITE); p=text; h=4; d=line; while(*p) { if (*p=='\n') { *d++=0; p++; FB_Centre(line,h,COL_WHITE,COL_TRANSPARENT); h+=8; d=line; } else { *d++=*p++; } } if (d>line) { *d=0; FB_Centre(line,h,COL_WHITE,COL_TRANSPARENT); h+=8; } if (!fatal) { FB_Centre("PRESS ANY BUTTON OR SCREEN",h+16,COL_YELLOW,COL_TRANSPARENT); while(!keysDown()) { swiWaitForVBlank(); } while(keysHeld()) { swiWaitForVBlank(); } } else { FB_Centre("PLEASE RESET YOUR CONSOLE",h+16,COL_YELLOW,COL_TRANSPARENT); while(1) { swiWaitForVBlank(); } } } void GUI_Config(void) { int sel; DS48_ConfigItem f; int done; int save; sel = 0; done = FALSE; save = FALSE; FB_Clear(); FB_Centre("Up/Down to select",140,COL_YELLOW,COL_TRANSPARENT); FB_Centre("A to toggle",150,COL_YELLOW,COL_TRANSPARENT); FB_Centre("Or use touchscreen",160,COL_YELLOW,COL_TRANSPARENT); FB_Centre("START to finish",170,COL_YELLOW,COL_TRANSPARENT); #ifndef DS48_DISABLE_FAT FB_Centre("SELECT to finish and save",180,COL_YELLOW,COL_TRANSPARENT); #endif for(f=0;f=0 && nsel (no - FSEL_LINES)) { new_top = no - FSEL_LINES; } if (new_top < 0) { new_top = 0; } if (new_top != top) { top = new_top; sel = top; drag_start = tp.py; } } else { drag = FALSE; } } if (!drag) { int activate = FALSE; do { swiWaitForVBlank(); } while(!(key=keysDownRepeat())); if (key & KEY_TOUCH) { touchPosition tp; tp = touchReadXY(); if (tp.py >= FSEL_LIST_Y && tp.py <= (FSEL_LIST_Y+FSEL_LIST_H)) { if (tp.px > 239) { drag = TRUE; drag_start = tp.py; } else { int new_sel; new_sel = top + (tp.py - FSEL_LIST_Y)/8; if (new_sel < no) { if (new_sel == sel) { activate = TRUE; } else { sel = new_sel; } } } } } else if (key & KEY_UP) { if (sel) { sel--; if (sel= (top+FSEL_LINES)) { top++; } } } else if (key & KEY_L) { if (sel) { sel-=FSEL_LINES; if (sel < 0) { sel = 0; } top = sel; } } else if (key & KEY_R) { if (sel < (no-1)) { sel+=FSEL_LINES; if (sel > (no-1)) { sel = no-1; } top = sel - FSEL_LINES + 1; if (top < 0) { top = 0; } } } else if (key & KEY_A) { activate = TRUE; } else if (key & KEY_B) { done = TRUE; } if (activate) { if (fsel[sel].is_dir) { AddPath(pwd,fsel[sel].name); FB_printf(0,0,COL_BLACK,COL_LIGHTGREY,"%-32.32s",pwd); no = LoadDir(pwd,filter); sel = 0; top = 0; if (no<=FSEL_LINES) { bar_step = 0; bar_size = FSEL_LIST_H; } else { bar_step = FSEL_LIST_H/(double)no; bar_size = bar_step*FSEL_LINES; } } else { done = TRUE; ret = TRUE; strcpy(selected_file,pwd); strcat(selected_file,fsel[sel].name); } } } } while (keysHeld()); return ret; }