|
|
1.1 ! root 1: /* ! 2: Hatari - dlgFileSelect.c ! 3: ! 4: This file is distributed under the GNU Public License, version 2 or at ! 5: your option any later version. Read the file gpl.txt for details. ! 6: ! 7: A file selection dialog for the graphical user interface for Hatari. ! 8: */ ! 9: char DlgFileSelect_rcsid[] = "Hatari $Id: dlgFileSelect.c,v 1.6 2004/04/28 09:04:59 thothy Exp $"; ! 10: ! 11: #include <SDL.h> ! 12: #include <sys/stat.h> ! 13: #include <unistd.h> ! 14: #include <dirent.h> ! 15: ! 16: #include "main.h" ! 17: #include "screen.h" ! 18: #include "sdlgui.h" ! 19: #include "file.h" ! 20: #include "zip.h" ! 21: ! 22: ! 23: #define SGFSDLG_FILENAME 5 ! 24: #define SGFSDLG_UPDIR 6 ! 25: #define SGFSDLG_ROOTDIR 7 ! 26: #define SGFSDLG_ENTRY1 10 ! 27: #define SGFSDLG_ENTRY16 25 ! 28: #define SGFSDLG_UP 26 ! 29: #define SGFSDLG_DOWN 27 ! 30: #define SGFSDLG_OKAY 28 ! 31: #define SGFSDLG_CANCEL 29 ! 32: ! 33: ! 34: #define DLGPATH_SIZE 62 ! 35: static char dlgpath[DLGPATH_SIZE+1]; /* Path name in the dialog */ ! 36: ! 37: #define DLGFNAME_SIZE 56 ! 38: static char dlgfname[DLGFNAME_SIZE+1]; /* Name of the selected file in the dialog */ ! 39: ! 40: #define DLGFILENAMES_SIZE 59 ! 41: static char dlgfilenames[16][DLGFILENAMES_SIZE+1]; /* Visible file names in the dialog */ ! 42: ! 43: /* The dialog data: */ ! 44: static SGOBJ fsdlg[] = ! 45: { ! 46: { SGBOX, 0, 0, 0,0, 64,25, NULL }, ! 47: { SGTEXT, 0, 0, 25,1, 13,1, "Choose a file" }, ! 48: { SGTEXT, 0, 0, 1,2, 7,1, "Folder:" }, ! 49: { SGTEXT, 0, 0, 1,3, DLGPATH_SIZE,1, dlgpath }, ! 50: { SGTEXT, 0, 0, 1,4, 6,1, "File:" }, ! 51: { SGTEXT, 0, 0, 7,4, DLGFNAME_SIZE,1, dlgfname }, ! 52: { SGBUTTON, 0, 0, 55,1, 4,1, ".." }, ! 53: { SGBUTTON, 0, 0, 60,1, 3,1, "/" }, ! 54: { SGBOX, 0, 0, 1,6, 62,16, NULL }, ! 55: { SGBOX, 0, 0, 62,7, 1,14, NULL }, ! 56: { SGTEXT, SG_EXIT, 0, 2,6, DLGFILENAMES_SIZE,1, dlgfilenames[0] }, ! 57: { SGTEXT, SG_EXIT, 0, 2,7, DLGFILENAMES_SIZE,1, dlgfilenames[1] }, ! 58: { SGTEXT, SG_EXIT, 0, 2,8, DLGFILENAMES_SIZE,1, dlgfilenames[2] }, ! 59: { SGTEXT, SG_EXIT, 0, 2,9, DLGFILENAMES_SIZE,1, dlgfilenames[3] }, ! 60: { SGTEXT, SG_EXIT, 0, 2,10, DLGFILENAMES_SIZE,1, dlgfilenames[4] }, ! 61: { SGTEXT, SG_EXIT, 0, 2,11, DLGFILENAMES_SIZE,1, dlgfilenames[5] }, ! 62: { SGTEXT, SG_EXIT, 0, 2,12, DLGFILENAMES_SIZE,1, dlgfilenames[6] }, ! 63: { SGTEXT, SG_EXIT, 0, 2,13, DLGFILENAMES_SIZE,1, dlgfilenames[7] }, ! 64: { SGTEXT, SG_EXIT, 0, 2,14, DLGFILENAMES_SIZE,1, dlgfilenames[8] }, ! 65: { SGTEXT, SG_EXIT, 0, 2,15, DLGFILENAMES_SIZE,1, dlgfilenames[9] }, ! 66: { SGTEXT, SG_EXIT, 0, 2,16, DLGFILENAMES_SIZE,1, dlgfilenames[10] }, ! 67: { SGTEXT, SG_EXIT, 0, 2,17, DLGFILENAMES_SIZE,1, dlgfilenames[11] }, ! 68: { SGTEXT, SG_EXIT, 0, 2,18, DLGFILENAMES_SIZE,1, dlgfilenames[12] }, ! 69: { SGTEXT, SG_EXIT, 0, 2,19, DLGFILENAMES_SIZE,1, dlgfilenames[13] }, ! 70: { SGTEXT, SG_EXIT, 0, 2,20, DLGFILENAMES_SIZE,1, dlgfilenames[14] }, ! 71: { SGTEXT, SG_EXIT, 0, 2,21, DLGFILENAMES_SIZE,1, dlgfilenames[15] }, ! 72: { SGBUTTON, SG_TOUCHEXIT, 0, 62,6, 1,1, "\x01" }, /* Arrow up */ ! 73: { SGBUTTON, SG_TOUCHEXIT, 0, 62,21, 1,1, "\x02" }, /* Arrow down */ ! 74: { SGBUTTON, 0, 0, 14,23, 8,1, "Okay" }, ! 75: { SGBUTTON, 0, 0, 34,23, 8,1, "Cancel" }, ! 76: { -1, 0, 0, 0,0, 0,0, NULL } ! 77: }; ! 78: ! 79: ! 80: ! 81: /*-----------------------------------------------------------------------*/ ! 82: /* ! 83: Update the file name strings in the dialog. ! 84: Returns FALSE if it failed, TRUE on success. ! 85: */ ! 86: static int DlgFileSelect_RefreshEntries(struct dirent **files, char *path, ! 87: BOOL browsingzip, int entries, int ypos) ! 88: { ! 89: int i; ! 90: char *tempstr = malloc(FILENAME_MAX); ! 91: ! 92: if (!tempstr) ! 93: { ! 94: perror("DlgFileSelect_RefreshEntries"); ! 95: return FALSE; ! 96: } ! 97: ! 98: /* Copy entries to dialog: */ ! 99: for(i=0; i<16; i++) ! 100: { ! 101: if( i+ypos < entries ) ! 102: { ! 103: struct stat filestat; ! 104: /* Prepare entries: */ ! 105: strcpy(tempstr, " "); ! 106: strcat(tempstr, files[i+ypos]->d_name); ! 107: File_ShrinkName(dlgfilenames[i], tempstr, DLGFILENAMES_SIZE); ! 108: /* Mark folders: */ ! 109: strcpy(tempstr, path); ! 110: strcat(tempstr, files[i+ypos]->d_name); ! 111: ! 112: if( browsingzip ) ! 113: { ! 114: if( tempstr[strlen(tempstr)-1] == '/' ) ! 115: dlgfilenames[i][0] = SGFOLDER; /* Mark folders */ ! 116: } ! 117: else ! 118: { ! 119: if( stat(tempstr, &filestat)==0 && S_ISDIR(filestat.st_mode) ) ! 120: dlgfilenames[i][0] = SGFOLDER; /* Mark folders */ ! 121: if (ZIP_FileNameIsZIP(tempstr) && browsingzip == FALSE) ! 122: dlgfilenames[i][0] = SGFOLDER; /* Mark .ZIP archives as folders */ ! 123: } ! 124: } ! 125: else ! 126: dlgfilenames[i][0] = 0; /* Clear entry */ ! 127: } ! 128: ! 129: free(tempstr); ! 130: return TRUE; ! 131: } ! 132: ! 133: ! 134: /*-----------------------------------------------------------------------*/ ! 135: /* ! 136: Show and process a file selection dialog. ! 137: Returns TRUE if the use selected "okay", FALSE if "cancel". ! 138: input: zip_path = pointer to buffer to contain file path within a selected ! 139: zip file, or NULL if browsing zip files is disallowed. ! 140: bAllowNew: TRUE if the user is allowed to insert new file names. ! 141: */ ! 142: int SDLGui_FileSelect(char *path_and_name, char *zip_path, BOOL bAllowNew) ! 143: { ! 144: int i,n; ! 145: int entries = 0; /* How many files are in the actual directory? */ ! 146: int ypos = 0; ! 147: struct dirent **files = NULL; ! 148: char *pStringMem; ! 149: char *path, *fname; /* The actual file and path names */ ! 150: BOOL reloaddir = TRUE; /* Do we have to reload the directory file list? */ ! 151: BOOL refreshentries = TRUE; /* Do we have to update the file names in the dialog? */ ! 152: int retbut; ! 153: int oldcursorstate; ! 154: int selection = -1; /* The actual selection, -1 if none selected */ ! 155: char *zipfilename; /* Filename in zip file */ ! 156: char *zipdir; ! 157: BOOL browsingzip = FALSE; /* Are we browsing an archive? */ ! 158: zip_dir *zipfiles = NULL; ! 159: ! 160: /* Allocate memory for the file and path name strings: */ ! 161: pStringMem = malloc(4 * FILENAME_MAX); ! 162: path = pStringMem; ! 163: fname = pStringMem + FILENAME_MAX; ! 164: zipfilename = pStringMem + 2 * FILENAME_MAX; ! 165: zipdir = pStringMem + 3 * FILENAME_MAX; ! 166: ! 167: zipfilename[0] = 0; ! 168: ! 169: SDLGui_CenterDlg(fsdlg); ! 170: if (bAllowNew) ! 171: { ! 172: fsdlg[SGFSDLG_FILENAME].type = SGEDITFIELD; ! 173: fsdlg[SGFSDLG_FILENAME].flags |= SG_EXIT; ! 174: } ! 175: else ! 176: { ! 177: fsdlg[SGFSDLG_FILENAME].type = SGTEXT; ! 178: fsdlg[SGFSDLG_FILENAME].flags &= ~SG_EXIT; ! 179: } ! 180: ! 181: /* Prepare the path and filename variables */ ! 182: File_splitpath(path_and_name, path, fname, NULL); ! 183: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); ! 184: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE); ! 185: ! 186: /* Save old mouse cursor state and enable cursor anyway */ ! 187: oldcursorstate = SDL_ShowCursor(SDL_QUERY); ! 188: if (oldcursorstate == SDL_DISABLE) ! 189: SDL_ShowCursor(SDL_ENABLE); ! 190: ! 191: do ! 192: { ! 193: if (reloaddir) ! 194: { ! 195: if (strlen(path) >= FILENAME_MAX) ! 196: { ! 197: fprintf(stderr, "SDLGui_FileSelect: Path name too long!\n"); ! 198: free(pStringMem); ! 199: return FALSE; ! 200: } ! 201: ! 202: /* Free old allocated memory: */ ! 203: if (files != NULL) ! 204: { ! 205: for(i=0; i<entries; i++) ! 206: { ! 207: free(files[i]); ! 208: } ! 209: free(files); ! 210: files = NULL; ! 211: } ! 212: ! 213: if (browsingzip) ! 214: { ! 215: files = ZIP_GetFilesDir(zipfiles, zipdir, &entries); ! 216: } ! 217: else ! 218: { ! 219: /* Load directory entries: */ ! 220: entries = scandir(path, &files, 0, alphasort); ! 221: } ! 222: ! 223: if (entries < 0) ! 224: { ! 225: fprintf(stderr, "SDLGui_FileSelect: Path not found.\n"); ! 226: free(pStringMem); ! 227: return FALSE; ! 228: } ! 229: ! 230: reloaddir = FALSE; ! 231: refreshentries = TRUE; ! 232: }/* reloaddir */ ! 233: ! 234: /* Update the file name strings in the dialog? */ ! 235: if (refreshentries) ! 236: { ! 237: if (!DlgFileSelect_RefreshEntries(files, path, browsingzip, entries, ypos)) ! 238: { ! 239: free(pStringMem); ! 240: return FALSE; ! 241: } ! 242: refreshentries = FALSE; ! 243: } ! 244: ! 245: /* Show dialog: */ ! 246: retbut = SDLGui_DoDialog(fsdlg); ! 247: ! 248: /* Has the user clicked on a file or folder? */ ! 249: if( retbut>=SGFSDLG_ENTRY1 && retbut<=SGFSDLG_ENTRY16 && retbut-SGFSDLG_ENTRY1+ypos<entries) ! 250: { ! 251: char *tempstr; ! 252: struct stat filestat; ! 253: ! 254: tempstr = malloc(FILENAME_MAX); ! 255: if (!tempstr) ! 256: { ! 257: perror("Error while allocating temporary memory in SDLGui_FileSelect()"); ! 258: free(pStringMem); ! 259: return FALSE; ! 260: } ! 261: ! 262: if( browsingzip == TRUE ) ! 263: { ! 264: strcpy(tempstr, zipdir); ! 265: strcat(tempstr, files[retbut-SGFSDLG_ENTRY1+ypos]->d_name); ! 266: if(tempstr[strlen(tempstr)-1] == '/') ! 267: { ! 268: /* handle the ../ directory */ ! 269: if(strcmp(files[retbut-SGFSDLG_ENTRY1+ypos]->d_name, "../") == 0) ! 270: { ! 271: /* close the zip file */ ! 272: if( strcmp(tempstr, "../") == 0 ) ! 273: { ! 274: reloaddir = refreshentries = TRUE; ! 275: /* free zip file entries */ ! 276: ZIP_FreeZipDir(zipfiles); ! 277: zipfiles = NULL; ! 278: /* Copy the path name to the dialog */ ! 279: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); ! 280: browsingzip = FALSE; ! 281: } ! 282: else ! 283: { ! 284: i=strlen(tempstr)-1; ! 285: n=0; ! 286: while(i > 0 && n < 3) ! 287: if( tempstr[i--] == '/' ) ! 288: n++; ! 289: if(tempstr[i+1] == '/') ! 290: tempstr[i+2] = '\0'; ! 291: else ! 292: tempstr[0] = '\0'; ! 293: ! 294: strcpy(zipdir, tempstr); ! 295: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE); ! 296: } ! 297: } ! 298: else /* not the "../" directory */ ! 299: { ! 300: strcpy(zipdir, tempstr); ! 301: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE); ! 302: } ! 303: reloaddir = TRUE; ! 304: /* Copy the path name to the dialog */ ! 305: selection = -1; /* Remove old selection */ ! 306: zipfilename[0] = '\0'; ! 307: dlgfname[0] = 0; ! 308: ypos = 0; ! 309: ! 310: } ! 311: else ! 312: { ! 313: /* Select a file in the zip */ ! 314: selection = retbut-SGFSDLG_ENTRY1+ypos; ! 315: strcpy(zipfilename, files[selection]->d_name); ! 316: File_ShrinkName(dlgfname, zipfilename, DLGFNAME_SIZE); ! 317: } ! 318: ! 319: } /* if browsingzip */ ! 320: else ! 321: { ! 322: strcpy(tempstr, path); ! 323: strcat(tempstr, files[retbut-SGFSDLG_ENTRY1+ypos]->d_name); ! 324: if( stat(tempstr, &filestat)==0 && S_ISDIR(filestat.st_mode) ) ! 325: { ! 326: /* Set the new directory */ ! 327: strcpy(path, tempstr); ! 328: if( strlen(path)>=3 ) ! 329: { ! 330: if(path[strlen(path)-2]=='/' && path[strlen(path)-1]=='.') ! 331: path[strlen(path)-2] = 0; /* Strip a single dot at the end of the path name */ ! 332: if(path[strlen(path)-3]=='/' && path[strlen(path)-2]=='.' && path[strlen(path)-1]=='.') ! 333: { ! 334: /* Handle the ".." folder */ ! 335: char *ptr; ! 336: if( strlen(path)==3 ) ! 337: path[1] = 0; ! 338: else ! 339: { ! 340: path[strlen(path)-3] = 0; ! 341: ptr = strrchr(path, '/'); ! 342: if(ptr) ! 343: *(ptr+1) = 0; ! 344: } ! 345: } ! 346: } ! 347: File_AddSlashToEndFileName(path); ! 348: reloaddir = TRUE; ! 349: /* Copy the path name to the dialog */ ! 350: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); ! 351: selection = -1; /* Remove old selection */ ! 352: dlgfname[0] = 0; ! 353: ypos = 0; ! 354: } ! 355: else if (ZIP_FileNameIsZIP(tempstr) && zip_path != NULL) ! 356: { ! 357: /* open a zip file */ ! 358: zipfiles = ZIP_GetFiles(tempstr); ! 359: if( zipfiles != NULL && browsingzip == FALSE ) ! 360: { ! 361: selection = retbut-SGFSDLG_ENTRY1+ypos; ! 362: strcpy(fname, files[selection]->d_name); ! 363: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE); ! 364: browsingzip=TRUE; ! 365: strcpy(zipdir, ""); ! 366: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE); ! 367: reloaddir = refreshentries = TRUE; ! 368: ypos = 0; ! 369: } ! 370: ! 371: } ! 372: else ! 373: { ! 374: /* Select a file */ ! 375: selection = retbut-SGFSDLG_ENTRY1+ypos; ! 376: strcpy(fname, files[selection]->d_name); ! 377: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE); ! 378: } ! 379: ! 380: } /* not browsingzip */ ! 381: ! 382: free(tempstr); ! 383: } ! 384: else /* Has the user clicked on another button? */ ! 385: { ! 386: switch(retbut) ! 387: { ! 388: case SGFSDLG_UPDIR: /* Change path to parent directory */ ! 389: ! 390: if( browsingzip ) ! 391: { ! 392: /* close the zip file */ ! 393: if( strcmp(zipdir, "") == 0 ) ! 394: { ! 395: reloaddir = refreshentries = TRUE; ! 396: /* free zip file entries */ ! 397: ZIP_FreeZipDir(zipfiles); ! 398: zipfiles = NULL; ! 399: /* Copy the path name to the dialog */ ! 400: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); ! 401: browsingzip = FALSE; ! 402: reloaddir = TRUE; ! 403: selection = -1; /* Remove old selection */ ! 404: fname[0] = 0; ! 405: dlgfname[0] = 0; ! 406: ypos = 0; ! 407: } ! 408: else ! 409: { ! 410: i=strlen(zipdir)-1; ! 411: n=0; ! 412: while(i > 0 && n < 2) ! 413: if( zipdir[i--] == '/' ) ! 414: n++; ! 415: if(zipdir[i+1] == '/') ! 416: zipdir[i+2] = '\0'; ! 417: else ! 418: zipdir[0] = '\0'; ! 419: ! 420: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE); ! 421: reloaddir = TRUE; ! 422: selection = -1; /* Remove old selection */ ! 423: zipfilename[0] = '\0'; ! 424: dlgfname[0] = 0; ! 425: ypos = 0; ! 426: } ! 427: } /* not a zip file: */ ! 428: else if( strlen(path)>2 ) ! 429: { ! 430: char *ptr; ! 431: File_CleanFileName(path); ! 432: ptr = strrchr(path, '/'); ! 433: if(ptr) ! 434: *(ptr+1) = 0; ! 435: File_AddSlashToEndFileName(path); ! 436: reloaddir = TRUE; ! 437: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); /* Copy the path name to the dialog */ ! 438: selection = -1; /* Remove old selection */ ! 439: fname[0] = 0; ! 440: dlgfname[0] = 0; ! 441: ypos = 0; ! 442: } ! 443: break; ! 444: case SGFSDLG_ROOTDIR: /* Change to root directory */ ! 445: if( browsingzip ) ! 446: { ! 447: /* free zip file entries */ ! 448: ZIP_FreeZipDir(zipfiles); ! 449: zipfiles = NULL; ! 450: browsingzip = FALSE; ! 451: } ! 452: ! 453: strcpy(path, "/"); ! 454: reloaddir = TRUE; ! 455: strcpy(dlgpath, path); ! 456: selection = -1; /* Remove old selection */ ! 457: fname[0] = 0; ! 458: dlgfname[0] = 0; ! 459: ypos = 0; ! 460: break; ! 461: case SGFSDLG_UP: /* Scroll up */ ! 462: if( ypos>0 ) ! 463: { ! 464: --ypos; ! 465: refreshentries = TRUE; ! 466: } ! 467: SDL_Delay(20); ! 468: break; ! 469: case SGFSDLG_DOWN: /* Scroll down */ ! 470: if( ypos+17<=entries ) ! 471: { ! 472: ++ypos; ! 473: refreshentries = TRUE; ! 474: } ! 475: SDL_Delay(20); ! 476: break; ! 477: case SGFSDLG_FILENAME: /* User entered new filename */ ! 478: strcpy(fname, dlgfname); ! 479: break; ! 480: } /* switch */ ! 481: } /* other button code */ ! 482: ! 483: ! 484: } /* do */ ! 485: ! 486: ! 487: while (retbut!=SGFSDLG_OKAY && retbut!=SGFSDLG_CANCEL && !bQuitProgram); ! 488: ! 489: if (oldcursorstate == SDL_DISABLE) ! 490: SDL_ShowCursor(SDL_DISABLE); ! 491: ! 492: File_makepath(path_and_name, path, fname, NULL); ! 493: ! 494: /* Free old allocated memory: */ ! 495: if (files != NULL) ! 496: { ! 497: for(i=0; i<entries; i++) ! 498: { ! 499: free(files[i]); ! 500: } ! 501: free(files); ! 502: files = NULL; ! 503: } ! 504: ! 505: if (browsingzip) ! 506: { ! 507: /* free zip file entries */ ! 508: ZIP_FreeZipDir(zipfiles); ! 509: zipfiles = NULL; ! 510: } ! 511: ! 512: if (zip_path != NULL) ! 513: { ! 514: if( browsingzip ) ! 515: { ! 516: strcpy(zip_path, zipdir); ! 517: strcat(zip_path, zipfilename); ! 518: } ! 519: else ! 520: zip_path[0] = '\0'; ! 521: } ! 522: ! 523: free(pStringMem); ! 524: ! 525: return(retbut == SGFSDLG_OKAY); ! 526: } ! 527:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.