|
|
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: const char DlgFileSelect_fileid[] = "Hatari dlgFileSelect.c : " __DATE__ " " __TIME__; ! 10: ! 11: #include <SDL.h> ! 12: #include <sys/stat.h> ! 13: #include <unistd.h> ! 14: ! 15: #include "main.h" ! 16: #include "scandir.h" ! 17: #include "sdlgui.h" ! 18: #include "file.h" ! 19: #include "paths.h" ! 20: #include "zip.h" ! 21: ! 22: ! 23: #define SGFS_NUMENTRIES 16 /* How many entries are displayed at once */ ! 24: ! 25: ! 26: #define SGFSDLG_FILENAME 5 ! 27: #define SGFSDLG_UPDIR 6 ! 28: #define SGFSDLG_HOMEDIR 7 ! 29: #define SGFSDLG_ROOTDIR 8 ! 30: #define SGFSDLG_ENTRYFIRST 11 ! 31: #define SGFSDLG_ENTRYLAST 26 ! 32: #define SGFSDLG_SCROLLBAR 27 ! 33: #define SGFSDLG_UP 28 ! 34: #define SGFSDLG_DOWN 29 ! 35: #define SGFSDLG_SHOWHIDDEN 30 ! 36: #define SGFSDLG_OKAY 31 ! 37: #define SGFSDLG_CANCEL 32 ! 38: ! 39: #define SCROLLOUT_ABOVE 1 ! 40: #define SCROLLOUT_UNDER 2 ! 41: ! 42: #define DLGPATH_SIZE 62 ! 43: static char dlgpath[DLGPATH_SIZE+1]; /* Path name in the dialog */ ! 44: ! 45: #define DLGFNAME_SIZE 56 ! 46: static char dlgfname[DLGFNAME_SIZE+1]; /* Name of the selected file in the dialog */ ! 47: ! 48: #define DLGFILENAMES_SIZE 59 ! 49: static char dlgfilenames[SGFS_NUMENTRIES][DLGFILENAMES_SIZE+1]; /* Visible file names in the dialog */ ! 50: ! 51: /* The dialog data: */ ! 52: static SGOBJ fsdlg[] = ! 53: { ! 54: { SGBOX, 0, 0, 0,0, 64,25, NULL }, ! 55: { SGTEXT, 0, 0, 25,1, 13,1, "Choose a file" }, ! 56: { SGTEXT, 0, 0, 1,2, 7,1, "Folder:" }, ! 57: { SGTEXT, 0, 0, 1,3, DLGPATH_SIZE,1, dlgpath }, ! 58: { SGTEXT, 0, 0, 1,4, 6,1, "File:" }, ! 59: { SGTEXT, 0, 0, 7,4, DLGFNAME_SIZE,1, dlgfname }, ! 60: { SGBUTTON, 0, 0, 51,1, 4,1, ".." }, ! 61: { SGBUTTON, 0, 0, 56,1, 3,1, "~" }, ! 62: { SGBUTTON, 0, 0, 60,1, 3,1, "/" }, ! 63: { SGBOX, 0, 0, 1,6, 62,16, NULL }, ! 64: { SGBOX, 0, 0, 62,7, 1,14, NULL }, ! 65: { SGTEXT, SG_EXIT, 0, 2,6, DLGFILENAMES_SIZE,1, dlgfilenames[0] }, ! 66: { SGTEXT, SG_EXIT, 0, 2,7, DLGFILENAMES_SIZE,1, dlgfilenames[1] }, ! 67: { SGTEXT, SG_EXIT, 0, 2,8, DLGFILENAMES_SIZE,1, dlgfilenames[2] }, ! 68: { SGTEXT, SG_EXIT, 0, 2,9, DLGFILENAMES_SIZE,1, dlgfilenames[3] }, ! 69: { SGTEXT, SG_EXIT, 0, 2,10, DLGFILENAMES_SIZE,1, dlgfilenames[4] }, ! 70: { SGTEXT, SG_EXIT, 0, 2,11, DLGFILENAMES_SIZE,1, dlgfilenames[5] }, ! 71: { SGTEXT, SG_EXIT, 0, 2,12, DLGFILENAMES_SIZE,1, dlgfilenames[6] }, ! 72: { SGTEXT, SG_EXIT, 0, 2,13, DLGFILENAMES_SIZE,1, dlgfilenames[7] }, ! 73: { SGTEXT, SG_EXIT, 0, 2,14, DLGFILENAMES_SIZE,1, dlgfilenames[8] }, ! 74: { SGTEXT, SG_EXIT, 0, 2,15, DLGFILENAMES_SIZE,1, dlgfilenames[9] }, ! 75: { SGTEXT, SG_EXIT, 0, 2,16, DLGFILENAMES_SIZE,1, dlgfilenames[10] }, ! 76: { SGTEXT, SG_EXIT, 0, 2,17, DLGFILENAMES_SIZE,1, dlgfilenames[11] }, ! 77: { SGTEXT, SG_EXIT, 0, 2,18, DLGFILENAMES_SIZE,1, dlgfilenames[12] }, ! 78: { SGTEXT, SG_EXIT, 0, 2,19, DLGFILENAMES_SIZE,1, dlgfilenames[13] }, ! 79: { SGTEXT, SG_EXIT, 0, 2,20, DLGFILENAMES_SIZE,1, dlgfilenames[14] }, ! 80: { SGTEXT, SG_EXIT, 0, 2,21, DLGFILENAMES_SIZE,1, dlgfilenames[15] }, ! 81: { SGSCROLLBAR, SG_TOUCHEXIT, 0, 62, 7, 0, 0, NULL }, /* Scrollbar */ ! 82: { SGBUTTON, SG_TOUCHEXIT, 0, 62, 6,1,1, "\x01" }, /* Arrow up */ ! 83: { SGBUTTON, SG_TOUCHEXIT, 0, 62,21,1,1, "\x02" }, /* Arrow down */ ! 84: { SGCHECKBOX, SG_EXIT, 0, 2,23, 18,1, "Show hidden files" }, ! 85: { SGBUTTON, SG_DEFAULT, 0, 32,23, 8,1, "Okay" }, ! 86: { SGBUTTON, SG_CANCEL, 0, 50,23, 8,1, "Cancel" }, ! 87: { -1, 0, 0, 0,0, 0,0, NULL } ! 88: }; ! 89: ! 90: ! 91: static int ypos; /* First entry number to be displayed */ ! 92: static bool refreshentries; /* Do we have to update the file names in the dialog? */ ! 93: static int entries; /* How many files are in the actual directory? */ ! 94: static int oldMouseY = 0; /* Keep the latest Y mouse position for scrollbar move computing */ ! 95: static int mouseClicked = 0; /* used to know if mouse if down for the first time or not */ ! 96: static int mouseIsOut = 0; /* used to keep info that mouse if above or under the scrollbar when mousebutton is down */ ! 97: static float scrollbar_Ypos = 0.0; /* scrollbar heigth */ ! 98: ! 99: /* Convert file position (in file list) to scrollbar y position */ ! 100: static void DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(void); ! 101: ! 102: ! 103: ! 104: /*-----------------------------------------------------------------------*/ ! 105: /** ! 106: * Update the file name strings in the dialog. ! 107: * Returns false if it failed, true on success. ! 108: */ ! 109: static int DlgFileSelect_RefreshEntries(struct dirent **files, char *path, bool browsingzip) ! 110: { ! 111: int i; ! 112: char *tempstr = malloc(FILENAME_MAX); ! 113: ! 114: if (!tempstr) ! 115: { ! 116: perror("DlgFileSelect_RefreshEntries"); ! 117: return false; ! 118: } ! 119: ! 120: /* Copy entries to dialog: */ ! 121: for (i=0; i<SGFS_NUMENTRIES; i++) ! 122: { ! 123: if (i+ypos < entries) ! 124: { ! 125: struct stat filestat; ! 126: /* Prepare entries: */ ! 127: strcpy(tempstr, " "); ! 128: strcat(tempstr, files[i+ypos]->d_name); ! 129: File_ShrinkName(dlgfilenames[i], tempstr, DLGFILENAMES_SIZE); ! 130: /* Mark folders: */ ! 131: strcpy(tempstr, path); ! 132: strcat(tempstr, files[i+ypos]->d_name); ! 133: ! 134: if (browsingzip) ! 135: { ! 136: if (File_DoesFileNameEndWithSlash(tempstr)) ! 137: dlgfilenames[i][0] = SGFOLDER; /* Mark folders */ ! 138: } ! 139: else ! 140: { ! 141: if( stat(tempstr, &filestat)==0 && S_ISDIR(filestat.st_mode) ) ! 142: dlgfilenames[i][0] = SGFOLDER; /* Mark folders */ ! 143: if (ZIP_FileNameIsZIP(tempstr) && browsingzip == false) ! 144: dlgfilenames[i][0] = SGFOLDER; /* Mark .ZIP archives as folders */ ! 145: } ! 146: } ! 147: else ! 148: dlgfilenames[i][0] = 0; /* Clear entry */ ! 149: } ! 150: ! 151: free(tempstr); ! 152: return true; ! 153: } ! 154: ! 155: ! 156: /*-----------------------------------------------------------------------*/ ! 157: /** ! 158: * Remove all hidden files (files with file names that begin with a dot) from ! 159: * the list. ! 160: */ ! 161: static void DlgFileSelect_RemoveHiddenFiles(struct dirent **files) ! 162: { ! 163: int i; ! 164: int nActPos = -1; ! 165: int nOldEntries; ! 166: ! 167: nOldEntries = entries; ! 168: ! 169: /* Scan list for hidden files and remove them. */ ! 170: for (i = 0; i < nOldEntries; i++) ! 171: { ! 172: /* Does file name start with a dot? -> hidden file! */ ! 173: if (files[i]->d_name[0] == '.') ! 174: { ! 175: if (nActPos == -1) ! 176: nActPos = i; ! 177: /* Remove file from list: */ ! 178: free(files[i]); ! 179: files[i] = NULL; ! 180: entries -= 1; ! 181: } ! 182: } ! 183: ! 184: /* Now close the gaps in the list: */ ! 185: if (nActPos != -1) ! 186: { ! 187: for (i = nActPos; i < nOldEntries; i++) ! 188: { ! 189: if (files[i] != NULL) ! 190: { ! 191: /* Move entry to earlier position: */ ! 192: files[nActPos] = files[i]; ! 193: files[i] = NULL; ! 194: nActPos += 1; ! 195: } ! 196: } ! 197: } ! 198: } ! 199: ! 200: ! 201: /*-----------------------------------------------------------------------*/ ! 202: /** ! 203: * Prepare to scroll up one entry. ! 204: */ ! 205: static void DlgFileSelect_ScrollUp(void) ! 206: { ! 207: if (ypos > 0) ! 208: { ! 209: --ypos; ! 210: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); ! 211: refreshentries = true; ! 212: } ! 213: } ! 214: ! 215: ! 216: /*-----------------------------------------------------------------------*/ ! 217: /** ! 218: * Prepare to scroll down one entry. ! 219: */ ! 220: static void DlgFileSelect_ScrollDown(void) ! 221: { ! 222: if (ypos+SGFS_NUMENTRIES < entries) ! 223: { ! 224: ++ypos; ! 225: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); ! 226: refreshentries = true; ! 227: } ! 228: } ! 229: ! 230: /*-----------------------------------------------------------------------*/ ! 231: /** ! 232: * Manage the scrollbar up or down. ! 233: */ ! 234: static void DlgFileSelect_ManageScrollbar(void) ! 235: { ! 236: int b, x, y; ! 237: int scrollY, scrollYmin, scrollYmax, scrollH_half; ! 238: float scrollMove; ! 239: ! 240: b = SDL_GetMouseState(&x, &y); ! 241: ! 242: /* If mouse is down on the scrollbar for the first time */ ! 243: if (fsdlg[SGFSDLG_SCROLLBAR].state & SG_MOUSEDOWN) { ! 244: if (mouseClicked == 0) { ! 245: mouseClicked = 1; ! 246: mouseIsOut = 0; ! 247: oldMouseY = y; ! 248: } ! 249: } ! 250: /* Mouse button is up on the scrollbar */ ! 251: else { ! 252: mouseClicked = 0; ! 253: oldMouseY = y; ! 254: mouseIsOut = 0; ! 255: } ! 256: ! 257: /* If mouse Y position didn't change */ ! 258: if (oldMouseY == y) ! 259: return; ! 260: ! 261: /* Compute scrollbar ymin and ymax values */ ! 262: ! 263: scrollYmin = (fsdlg[SGFSDLG_SCROLLBAR].y + fsdlg[0].y) * sdlgui_fontheight; ! 264: scrollYmax = (fsdlg[SGFSDLG_DOWN].y + fsdlg[0].y) * sdlgui_fontheight; ! 265: ! 266: scrollY = fsdlg[SGFSDLG_SCROLLBAR].y * sdlgui_fontheight + fsdlg[SGFSDLG_SCROLLBAR].h + fsdlg[0].y * sdlgui_fontheight; ! 267: scrollH_half = scrollY + fsdlg[SGFSDLG_SCROLLBAR].w / 2; ! 268: scrollMove = (float)(y-oldMouseY)/sdlgui_fontheight; ! 269: ! 270: /* Verify if mouse is not above the scrollbar area */ ! 271: if (y < scrollYmin) { ! 272: mouseIsOut = SCROLLOUT_ABOVE; ! 273: oldMouseY = y; ! 274: return; ! 275: } ! 276: if (mouseIsOut == SCROLLOUT_ABOVE && y < scrollH_half) { ! 277: oldMouseY = y; ! 278: return; ! 279: } ! 280: ! 281: /* Verify if mouse is not under the scrollbar area */ ! 282: if (y > scrollYmax) { ! 283: mouseIsOut = SCROLLOUT_UNDER; ! 284: oldMouseY = y; ! 285: return; ! 286: } ! 287: if (mouseIsOut == SCROLLOUT_UNDER && y > scrollH_half) { ! 288: oldMouseY = y; ! 289: return; ! 290: } ! 291: ! 292: mouseIsOut = 0; ! 293: ! 294: scrollbar_Ypos += scrollMove; ! 295: oldMouseY = y; ! 296: ! 297: /* Verifiy if scrollbar is in correct inferior boundary */ ! 298: if (scrollbar_Ypos < 0) { ! 299: scrollbar_Ypos = 0.0; ! 300: } ! 301: ! 302: /* Verifiy if scrollbar is in correct superior boundary */ ! 303: b = (int) (scrollbar_Ypos * ((float)entries/(float)(SGFS_NUMENTRIES-2)) + 0.5); ! 304: if (b+SGFS_NUMENTRIES >= entries) { ! 305: ypos = entries - SGFS_NUMENTRIES; ! 306: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); ! 307: } ! 308: ! 309: refreshentries = true; ! 310: } ! 311: ! 312: ! 313: /*-----------------------------------------------------------------------*/ ! 314: /** ! 315: * Handle SDL events. ! 316: */ ! 317: static void DlgFileSelect_HandleSdlEvents(SDL_Event *pEvent) ! 318: { ! 319: int oldypos = ypos; ! 320: switch (pEvent->type) ! 321: { ! 322: case SDL_MOUSEWHEEL: ! 323: if (pEvent->wheel.y>0) ! 324: DlgFileSelect_ScrollUp(); ! 325: else if (pEvent->wheel.y<0) ! 326: DlgFileSelect_ScrollDown(); ! 327: break; ! 328: case SDL_KEYDOWN: ! 329: switch (pEvent->key.keysym.sym) ! 330: { ! 331: case SDLK_UP: ! 332: DlgFileSelect_ScrollUp(); ! 333: break; ! 334: case SDLK_DOWN: ! 335: DlgFileSelect_ScrollDown(); ! 336: break; ! 337: case SDLK_HOME: ! 338: ypos = 0; ! 339: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); ! 340: break; ! 341: case SDLK_END: ! 342: ypos = entries-SGFS_NUMENTRIES; ! 343: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); ! 344: break; ! 345: case SDLK_PAGEUP: ! 346: ypos -= SGFS_NUMENTRIES; ! 347: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); ! 348: break; ! 349: case SDLK_PAGEDOWN: ! 350: if (ypos+2*SGFS_NUMENTRIES < entries) ! 351: ypos += SGFS_NUMENTRIES; ! 352: else ! 353: ypos = entries-SGFS_NUMENTRIES; ! 354: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); ! 355: break; ! 356: default: ! 357: break; ! 358: } ! 359: break; ! 360: default: ! 361: break; ! 362: } ! 363: ! 364: if (ypos < 0) { ! 365: ypos = 0; ! 366: scrollbar_Ypos = 0.0; ! 367: } ! 368: ! 369: if (ypos != oldypos) ! 370: refreshentries = true; ! 371: } ! 372: ! 373: ! 374: /*-----------------------------------------------------------------------*/ ! 375: /** ! 376: * Free file entries ! 377: */ ! 378: static struct dirent **files_free(struct dirent **files) ! 379: { ! 380: int i; ! 381: if (files != NULL) ! 382: { ! 383: for(i=0; i<entries; i++) ! 384: { ! 385: free(files[i]); ! 386: } ! 387: free(files); ! 388: } ! 389: return NULL; ! 390: } ! 391: ! 392: ! 393: /*-----------------------------------------------------------------------*/ ! 394: /** ! 395: * Copy to dst src+add if they are below maxlen and return true, ! 396: * otherwise return false ! 397: */ ! 398: static int strcat_maxlen(char *dst, int maxlen, const char *src, const char *add) ! 399: { ! 400: int slen, alen; ! 401: slen = strlen(src); ! 402: alen = strlen(add); ! 403: if (slen + alen < maxlen) ! 404: { ! 405: strcpy(dst, src); ! 406: strcpy(dst+slen, add); ! 407: return 1; ! 408: } ! 409: return 0; ! 410: } ! 411: ! 412: /*-----------------------------------------------------------------------*/ ! 413: /** ! 414: * Create and return suitable path into zip file ! 415: */ ! 416: static char* zip_get_path(const char *zipdir, const char *zipfilename, int browsingzip) ! 417: { ! 418: if (browsingzip) ! 419: { ! 420: char *zippath; ! 421: zippath = malloc(strlen(zipdir) + strlen(zipfilename) + 1); ! 422: strcpy(zippath, zipdir); ! 423: strcat(zippath, zipfilename); ! 424: return zippath; ! 425: } ! 426: return strdup(""); ! 427: } ! 428: ! 429: /** ! 430: * string for zip root needs to be empty, check and correct if needed ! 431: */ ! 432: static void correct_zip_root(char *zippath) ! 433: { ! 434: if (zippath[0] == PATHSEP && !zippath[1]) ! 435: { ! 436: zippath[0] = '\0'; ! 437: } ! 438: } ! 439: ! 440: /** ! 441: * Convert Ypos to Y scrollbar position ! 442: */ ! 443: static void DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(void) ! 444: { ! 445: if (entries <= SGFS_NUMENTRIES) ! 446: scrollbar_Ypos = 0.0; ! 447: else ! 448: scrollbar_Ypos = (float)ypos / ((float)entries/(float)(SGFS_NUMENTRIES-2)); ! 449: } ! 450: ! 451: /*-----------------------------------------------------------------------*/ ! 452: /** ! 453: * Show and process a file selection dialog. ! 454: * Returns path/name user selected or NULL if user canceled ! 455: * input: zip_path = pointer's pointer to buffer to contain file path ! 456: * within a selected zip file, or NULL if browsing zip files is disallowed. ! 457: * bAllowNew: true if the user is allowed to insert new file names. ! 458: */ ! 459: char* SDLGui_FileSelect(const char *path_and_name, char **zip_path, bool bAllowNew) ! 460: { ! 461: struct dirent **files = NULL; ! 462: char *pStringMem; ! 463: char *retpath; ! 464: const char *home; ! 465: char *path, *fname; /* The actual file and path names */ ! 466: bool reloaddir = true; /* Do we have to reload the directory file list? */ ! 467: int retbut; ! 468: int oldcursorstate; ! 469: int selection; /* The selection index */ ! 470: char *zipfilename; /* Filename in zip file */ ! 471: char *zipdir; ! 472: bool browsingzip = false; /* Are we browsing an archive? */ ! 473: zip_dir *zipfiles = NULL; ! 474: SDL_Event sdlEvent; ! 475: int yScrolbar_size; /* Size of the vertical scrollbar */ ! 476: ! 477: ! 478: ypos = 0; ! 479: scrollbar_Ypos = 0.0; ! 480: refreshentries = true; ! 481: entries = 0; ! 482: ! 483: /* Allocate memory for the file and path name strings: */ ! 484: pStringMem = malloc(4 * FILENAME_MAX); ! 485: path = pStringMem; ! 486: fname = pStringMem + FILENAME_MAX; ! 487: zipdir = pStringMem + 2 * FILENAME_MAX; ! 488: zipfilename = pStringMem + 3 * FILENAME_MAX; ! 489: zipfilename[0] = 0; ! 490: fname[0] = 0; ! 491: path[0] = 0; ! 492: ! 493: SDLGui_CenterDlg(fsdlg); ! 494: if (bAllowNew) ! 495: { ! 496: fsdlg[SGFSDLG_FILENAME].type = SGEDITFIELD; ! 497: fsdlg[SGFSDLG_FILENAME].flags |= SG_EXIT; ! 498: } ! 499: else ! 500: { ! 501: fsdlg[SGFSDLG_FILENAME].type = SGTEXT; ! 502: fsdlg[SGFSDLG_FILENAME].flags &= ~SG_EXIT; ! 503: } ! 504: ! 505: /* Prepare the path and filename variables */ ! 506: if (path_and_name && path_and_name[0]) ! 507: { ! 508: strncpy(path, path_and_name, FILENAME_MAX); ! 509: path[FILENAME_MAX-1] = '\0'; ! 510: } ! 511: if (!File_DirExists(path)) ! 512: { ! 513: File_SplitPath(path, path, fname, NULL); ! 514: if (!(File_DirExists(path) || getcwd(path, FILENAME_MAX))) ! 515: { ! 516: perror("SDLGui_FileSelect: non-existing path and CWD failed"); ! 517: free(pStringMem); ! 518: return NULL; ! 519: } ! 520: } ! 521: ! 522: File_MakeAbsoluteName(path); ! 523: File_MakeValidPathName(path); ! 524: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); ! 525: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE); ! 526: ! 527: /* Save old mouse cursor state and enable cursor */ ! 528: oldcursorstate = SDL_ShowCursor(SDL_QUERY); ! 529: if (oldcursorstate == SDL_DISABLE) ! 530: SDL_ShowCursor(SDL_ENABLE); ! 531: ! 532: do ! 533: { ! 534: if (reloaddir) ! 535: { ! 536: files = files_free(files); ! 537: ! 538: if (browsingzip) ! 539: { ! 540: files = ZIP_GetFilesDir(zipfiles, zipdir, &entries); ! 541: if(!files) ! 542: { ! 543: fprintf(stderr, "SDLGui_FileSelect: ZIP_GetFilesDir error!\n"); ! 544: free(pStringMem); ! 545: return NULL; ! 546: } ! 547: } ! 548: else ! 549: { ! 550: /* Load directory entries: */ ! 551: entries = scandir(path, &files, 0, alphasort); ! 552: } ! 553: ! 554: /* Remove hidden files from the list if necessary: */ ! 555: if (!(fsdlg[SGFSDLG_SHOWHIDDEN].state & SG_SELECTED)) ! 556: { ! 557: DlgFileSelect_RemoveHiddenFiles(files); ! 558: } ! 559: ! 560: if (entries < 0) ! 561: { ! 562: fprintf(stderr, "SDLGui_FileSelect: Path not found.\n"); ! 563: free(pStringMem); ! 564: return NULL; ! 565: } ! 566: ! 567: /* reload always implies refresh */ ! 568: reloaddir = false; ! 569: refreshentries = true; ! 570: }/* reloaddir */ ! 571: ! 572: /* Refresh scrollbar size */ ! 573: if (entries <= SGFS_NUMENTRIES) ! 574: yScrolbar_size = (SGFS_NUMENTRIES-2) * sdlgui_fontheight; ! 575: else ! 576: yScrolbar_size = (int)((SGFS_NUMENTRIES-2) / ((float)entries/(float)SGFS_NUMENTRIES) * sdlgui_fontheight); ! 577: fsdlg[SGFSDLG_SCROLLBAR].w = yScrolbar_size; ! 578: ! 579: /* Refresh scrolbar pos */ ! 580: fsdlg[SGFSDLG_SCROLLBAR].h = (int) (scrollbar_Ypos * sdlgui_fontheight); ! 581: ypos = (int) (scrollbar_Ypos * ((float)entries/(float)(SGFS_NUMENTRIES-2)) + 0.5); ! 582: ! 583: /* Update the file name strings in the dialog? */ ! 584: if (refreshentries) ! 585: { ! 586: if (!DlgFileSelect_RefreshEntries(files, path, browsingzip)) ! 587: { ! 588: free(pStringMem); ! 589: return NULL; ! 590: } ! 591: refreshentries = false; ! 592: } ! 593: ! 594: /* Show dialog: */ ! 595: retbut = SDLGui_DoDialog(fsdlg, &sdlEvent); ! 596: ! 597: /* Has the user clicked on a file or folder? */ ! 598: if (retbut>=SGFSDLG_ENTRYFIRST && retbut<=SGFSDLG_ENTRYLAST && retbut-SGFSDLG_ENTRYFIRST+ypos<entries) ! 599: { ! 600: char *tempstr; ! 601: ! 602: tempstr = malloc(FILENAME_MAX); ! 603: if (!tempstr) ! 604: { ! 605: perror("Error while allocating temporary memory in SDLGui_FileSelect()"); ! 606: free(pStringMem); ! 607: return NULL; ! 608: } ! 609: ! 610: if (browsingzip == true) ! 611: { ! 612: if (!strcat_maxlen(tempstr, FILENAME_MAX, ! 613: zipdir, files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name)) ! 614: { ! 615: fprintf(stderr, "SDLGui_FileSelect: Path name too long!\n"); ! 616: free(pStringMem); ! 617: return NULL; ! 618: } ! 619: /* directory? */ ! 620: if (File_DoesFileNameEndWithSlash(tempstr)) ! 621: { ! 622: /* handle the ../ directory */ ! 623: if (strcmp(files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name, "../") == 0) ! 624: { ! 625: /* close the zip file */ ! 626: if (strcmp(tempstr, "../") == 0) ! 627: { ! 628: /* free zip file entries */ ! 629: ZIP_FreeZipDir(zipfiles); ! 630: zipfiles = NULL; ! 631: /* Copy the path name to the dialog */ ! 632: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); ! 633: browsingzip = false; ! 634: } ! 635: else ! 636: { ! 637: /* remove "../" and previous dir from path */ ! 638: File_PathShorten(tempstr, 2); ! 639: correct_zip_root(tempstr); ! 640: strcpy(zipdir, tempstr); ! 641: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE); ! 642: } ! 643: } ! 644: else /* not the "../" directory */ ! 645: { ! 646: strcpy(zipdir, tempstr); ! 647: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE); ! 648: } ! 649: reloaddir = true; ! 650: /* Copy the path name to the dialog */ ! 651: zipfilename[0] = '\0'; ! 652: dlgfname[0] = 0; ! 653: ypos = 0; ! 654: scrollbar_Ypos = 0.0; ! 655: } ! 656: else ! 657: { ! 658: /* not dir, select a file in the zip */ ! 659: selection = retbut-SGFSDLG_ENTRYFIRST+ypos; ! 660: strcpy(zipfilename, files[selection]->d_name); ! 661: File_ShrinkName(dlgfname, zipfilename, DLGFNAME_SIZE); ! 662: } ! 663: ! 664: } ! 665: else /* not browsingzip */ ! 666: { ! 667: if (!strcat_maxlen(tempstr, FILENAME_MAX, ! 668: path, files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name)) ! 669: { ! 670: fprintf(stderr, "SDLGui_FileSelect: Path name too long!\n"); ! 671: free(pStringMem); ! 672: return NULL; ! 673: } ! 674: if (File_DirExists(tempstr)) ! 675: { ! 676: File_HandleDotDirs(tempstr); ! 677: File_AddSlashToEndFileName(tempstr); ! 678: /* Copy the path name to the dialog */ ! 679: File_ShrinkName(dlgpath, tempstr, DLGPATH_SIZE); ! 680: strcpy(path, tempstr); ! 681: reloaddir = true; ! 682: dlgfname[0] = 0; ! 683: ypos = 0; ! 684: scrollbar_Ypos = 0.0; ! 685: } ! 686: else if (ZIP_FileNameIsZIP(tempstr) && zip_path != NULL) ! 687: { ! 688: /* open a zip file */ ! 689: zipfiles = ZIP_GetFiles(tempstr); ! 690: if (zipfiles != NULL && browsingzip == false) ! 691: { ! 692: selection = retbut-SGFSDLG_ENTRYFIRST+ypos; ! 693: strcpy(fname, files[selection]->d_name); ! 694: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE); ! 695: browsingzip = true; ! 696: zipdir[0] = '\0'; /* zip root */ ! 697: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE); ! 698: reloaddir = true; ! 699: ypos = 0; ! 700: scrollbar_Ypos = 0.0; ! 701: } ! 702: ! 703: } ! 704: else ! 705: { ! 706: /* Select a file */ ! 707: selection = retbut-SGFSDLG_ENTRYFIRST+ypos; ! 708: strcpy(fname, files[selection]->d_name); ! 709: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE); ! 710: } ! 711: ! 712: } /* not browsingzip */ ! 713: ! 714: free(tempstr); ! 715: } ! 716: else /* Has the user clicked on another button? */ ! 717: { ! 718: switch(retbut) ! 719: { ! 720: case SGFSDLG_UPDIR: /* Change path to parent directory */ ! 721: ! 722: if (browsingzip) ! 723: { ! 724: /* close the zip file? */ ! 725: if (!zipdir[0]) ! 726: { ! 727: /* free zip file entries */ ! 728: ZIP_FreeZipDir(zipfiles); ! 729: browsingzip = false; ! 730: zipfiles = NULL; ! 731: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); ! 732: } ! 733: else ! 734: { ! 735: /* remove last dir from zipdir path */ ! 736: File_PathShorten(zipdir, 1); ! 737: correct_zip_root(zipdir); ! 738: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE); ! 739: zipfilename[0] = '\0'; ! 740: } ! 741: } /* not a zip file: */ ! 742: else ! 743: { ! 744: File_PathShorten(path, 1); ! 745: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); ! 746: } ! 747: reloaddir = true; ! 748: break; ! 749: ! 750: case SGFSDLG_HOMEDIR: /* Change to home directory */ ! 751: home = Paths_GetUserHome(); ! 752: if (home == NULL || !*home) ! 753: break; ! 754: if (browsingzip) ! 755: { ! 756: /* free zip file entries */ ! 757: ZIP_FreeZipDir(zipfiles); ! 758: zipfiles = NULL; ! 759: browsingzip = false; ! 760: } ! 761: strcpy(path, home); ! 762: File_AddSlashToEndFileName(path); ! 763: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); ! 764: reloaddir = true; ! 765: break; ! 766: ! 767: case SGFSDLG_ROOTDIR: /* Change to root directory */ ! 768: if (browsingzip) ! 769: { ! 770: /* free zip file entries */ ! 771: ZIP_FreeZipDir(zipfiles); ! 772: zipfiles = NULL; ! 773: browsingzip = false; ! 774: } ! 775: path[0] = PATHSEP; path[1] = '\0'; ! 776: strcpy(dlgpath, path); ! 777: reloaddir = true; ! 778: break; ! 779: case SGFSDLG_UP: /* Scroll up */ ! 780: DlgFileSelect_ScrollUp(); ! 781: SDL_Delay(10); ! 782: break; ! 783: case SGFSDLG_DOWN: /* Scroll down */ ! 784: DlgFileSelect_ScrollDown(); ! 785: SDL_Delay(10); ! 786: break; ! 787: case SGFSDLG_SCROLLBAR: /* Scrollbar selected */ ! 788: DlgFileSelect_ManageScrollbar(); ! 789: SDL_Delay(10); ! 790: break; ! 791: case SGFSDLG_FILENAME: /* User entered new filename */ ! 792: strcpy(fname, dlgfname); ! 793: break; ! 794: case SGFSDLG_SHOWHIDDEN: /* Show/hide hidden files */ ! 795: reloaddir = true; ! 796: ypos = 0; ! 797: scrollbar_Ypos = 0.0; ! 798: break; ! 799: case SDLGUI_UNKNOWNEVENT: ! 800: DlgFileSelect_HandleSdlEvents(&sdlEvent); ! 801: break; ! 802: } /* switch */ ! 803: ! 804: if (reloaddir) ! 805: { ! 806: /* Remove old selection */ ! 807: fname[0] = 0; ! 808: dlgfname[0] = 0; ! 809: ypos = 0; ! 810: scrollbar_Ypos = 0.0; ! 811: } ! 812: } /* other button code */ ! 813: ! 814: ! 815: } /* do */ ! 816: while (retbut!=SGFSDLG_OKAY && retbut!=SGFSDLG_CANCEL ! 817: && retbut!=SDLGUI_QUIT && retbut != SDLGUI_ERROR && !bQuitProgram); ! 818: ! 819: if (oldcursorstate == SDL_DISABLE) ! 820: SDL_ShowCursor(SDL_DISABLE); ! 821: ! 822: files_free(files); ! 823: ! 824: if (browsingzip) ! 825: { ! 826: /* free zip file entries */ ! 827: ZIP_FreeZipDir(zipfiles); ! 828: zipfiles = NULL; ! 829: } ! 830: ! 831: if (retbut == SGFSDLG_OKAY) ! 832: { ! 833: if (zip_path) ! 834: *zip_path = zip_get_path(zipdir, zipfilename, browsingzip); ! 835: retpath = File_MakePath(path, fname, NULL); ! 836: } ! 837: else ! 838: retpath = NULL; ! 839: free(pStringMem); ! 840: return retpath; ! 841: } ! 842: ! 843: ! 844: /*-----------------------------------------------------------------------*/ ! 845: /** ! 846: * Let user browse for a file, confname is used as default. ! 847: * If bAllowNew is true, user can select new files also. ! 848: * ! 849: * If no file is selected, or there's some problem with the file, ! 850: * return false and clear dlgname & confname. ! 851: * Otherwise return true, set dlgname & confname to the new file name ! 852: * (dlgname is shrinked & limited to maxlen and confname is assumed ! 853: * to have FILENAME_MAX amount of space). ! 854: */ ! 855: bool SDLGui_FileConfSelect(char *dlgname, char *confname, int maxlen, bool bAllowNew) ! 856: { ! 857: char *selname; ! 858: ! 859: selname = SDLGui_FileSelect(confname, NULL, bAllowNew); ! 860: if (selname) ! 861: { ! 862: if (!File_DoesFileNameEndWithSlash(selname) && ! 863: (bAllowNew || File_Exists(selname))) ! 864: { ! 865: strncpy(confname, selname, FILENAME_MAX); ! 866: confname[FILENAME_MAX-1] = '\0'; ! 867: File_ShrinkName(dlgname, selname, maxlen); ! 868: } ! 869: else ! 870: { ! 871: dlgname[0] = confname[0] = 0; ! 872: } ! 873: free(selname); ! 874: return true; ! 875: } ! 876: return false; ! 877: } ! 878: ! 879: ! 880: /*-----------------------------------------------------------------------*/ ! 881: /** ! 882: * Let user browse for a directory, confname is used as default. ! 883: * ! 884: * If no directory is selected, or there's some problem with it, ! 885: * return false and clear dlgname & confname. ! 886: * Otherwise return true, set dlgname & confname to the directory name ! 887: * (dlgname is shrinked & limited to maxlen and confname is assumed ! 888: * to have FILENAME_MAX amount of space). ! 889: */ ! 890: ! 891: bool SDLGui_DirectorySelect(char *dlgname, char *confname, int maxlen) ! 892: { ! 893: char *selname; ! 894: ! 895: selname = SDLGui_FileSelect(confname, NULL, false); ! 896: if (selname) ! 897: { ! 898: File_MakeValidPathName(selname); ! 899: ! 900: if (File_DirExists(selname)) ! 901: { ! 902: strncpy(confname, selname, FILENAME_MAX); ! 903: File_ShrinkName(dlgname, selname, maxlen); ! 904: } ! 905: else ! 906: { ! 907: dlgname[0] = confname[0] = 0; ! 908: } ! 909: free(selname); ! 910: return true; ! 911: } ! 912: return false; ! 913: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.