|
|
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: */
1.1.1.7 root 9: const char DlgFileSelect_fileid[] = "Hatari dlgFileSelect.c : " __DATE__ " " __TIME__;
1.1 root 10:
11: #include <SDL.h>
12: #include <sys/stat.h>
13: #include <unistd.h>
14:
15: #include "main.h"
1.1.1.3 root 16: #include "scandir.h"
1.1 root 17: #include "sdlgui.h"
18: #include "file.h"
1.1.1.8 root 19: #include "paths.h"
1.1 root 20: #include "zip.h"
21:
22:
1.1.1.2 root 23: #define SGFS_NUMENTRIES 16 /* How many entries are displayed at once */
24:
25:
1.1.1.9 ! root 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
1.1 root 38:
1.1.1.9 ! root 39: #define SCROLLOUT_ABOVE 1
! 40: #define SCROLLOUT_UNDER 2
1.1 root 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
1.1.1.2 root 49: static char dlgfilenames[SGFS_NUMENTRIES][DLGFILENAMES_SIZE+1]; /* Visible file names in the dialog */
1.1 root 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 },
1.1.1.3 root 60: { SGBUTTON, 0, 0, 51,1, 4,1, ".." },
61: { SGBUTTON, 0, 0, 56,1, 3,1, "~" },
1.1 root 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] },
1.1.1.9 ! root 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 */
1.1.1.5 root 84: { SGCHECKBOX, SG_EXIT, 0, 2,23, 18,1, "Show hidden files" },
1.1.1.4 root 85: { SGBUTTON, SG_DEFAULT, 0, 32,23, 8,1, "Okay" },
86: { SGBUTTON, SG_CANCEL, 0, 50,23, 8,1, "Cancel" },
1.1 root 87: { -1, 0, 0, 0,0, 0,0, NULL }
88: };
89:
90:
1.1.1.2 root 91: static int ypos; /* First entry number to be displayed */
1.1.1.5 root 92: static bool refreshentries; /* Do we have to update the file names in the dialog? */
1.1.1.2 root 93: static int entries; /* How many files are in the actual directory? */
1.1.1.9 ! root 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:
1.1.1.2 root 102:
1.1 root 103:
104: /*-----------------------------------------------------------------------*/
1.1.1.8 root 105: /**
106: * Update the file name strings in the dialog.
107: * Returns false if it failed, true on success.
108: */
1.1.1.5 root 109: static int DlgFileSelect_RefreshEntries(struct dirent **files, char *path, bool browsingzip)
1.1 root 110: {
111: int i;
112: char *tempstr = malloc(FILENAME_MAX);
113:
114: if (!tempstr)
115: {
116: perror("DlgFileSelect_RefreshEntries");
1.1.1.7 root 117: return false;
1.1 root 118: }
119:
120: /* Copy entries to dialog: */
1.1.1.4 root 121: for (i=0; i<SGFS_NUMENTRIES; i++)
1.1 root 122: {
1.1.1.4 root 123: if (i+ypos < entries)
1.1 root 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:
1.1.1.4 root 134: if (browsingzip)
1.1 root 135: {
1.1.1.3 root 136: if (File_DoesFileNameEndWithSlash(tempstr))
1.1 root 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 */
1.1.1.7 root 143: if (ZIP_FileNameIsZIP(tempstr) && browsingzip == false)
1.1 root 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);
1.1.1.7 root 152: return true;
1.1 root 153: }
154:
155:
156: /*-----------------------------------------------------------------------*/
1.1.1.8 root 157: /**
158: * Remove all hidden files (files with file names that begin with a dot) from
159: * the list.
160: */
1.1.1.3 root 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: /*-----------------------------------------------------------------------*/
1.1.1.8 root 202: /**
203: * Prepare to scroll up one entry.
204: */
1.1.1.2 root 205: static void DlgFileSelect_ScrollUp(void)
206: {
207: if (ypos > 0)
208: {
209: --ypos;
1.1.1.9 ! root 210: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos();
1.1.1.7 root 211: refreshentries = true;
1.1.1.2 root 212: }
213: }
214:
215:
216: /*-----------------------------------------------------------------------*/
1.1.1.8 root 217: /**
218: * Prepare to scroll down one entry.
219: */
1.1.1.2 root 220: static void DlgFileSelect_ScrollDown(void)
221: {
222: if (ypos+SGFS_NUMENTRIES < entries)
223: {
224: ++ypos;
1.1.1.9 ! root 225: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos();
1.1.1.7 root 226: refreshentries = true;
1.1.1.2 root 227: }
228: }
229:
1.1.1.9 ! root 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: /* Verifiy if scrollbar is in correct superior boundary */
! 302: b = (int) (scrollbar_Ypos * ((float)entries/(float)(SGFS_NUMENTRIES-2)) + 0.5);
! 303: if (b+SGFS_NUMENTRIES >= entries) {
! 304: ypos = entries - SGFS_NUMENTRIES;
! 305: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos();
! 306: }
! 307:
! 308: refreshentries = true;
! 309: }
1.1.1.2 root 310:
311: /*-----------------------------------------------------------------------*/
1.1.1.8 root 312: /**
313: * Handle SDL events.
314: */
1.1.1.2 root 315: static void DlgFileSelect_HandleSdlEvents(SDL_Event *pEvent)
316: {
1.1.1.4 root 317: int oldypos = ypos;
1.1.1.2 root 318: switch (pEvent->type)
319: {
320: case SDL_MOUSEBUTTONDOWN:
321: if (pEvent->button.button == SDL_BUTTON_WHEELUP)
322: DlgFileSelect_ScrollUp();
323: else if (pEvent->button.button == SDL_BUTTON_WHEELDOWN)
324: DlgFileSelect_ScrollDown();
325: break;
1.1.1.9 ! root 326: case SDL_KEYDOWN:
1.1.1.2 root 327: switch (pEvent->key.keysym.sym)
328: {
1.1.1.9 ! root 329: case SDLK_UP:
! 330: DlgFileSelect_ScrollUp();
! 331: break;
! 332: case SDLK_DOWN:
! 333: DlgFileSelect_ScrollDown();
! 334: break;
! 335: case SDLK_HOME:
! 336: ypos = 0;
! 337: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos();
! 338: break;
! 339: case SDLK_END:
! 340: ypos = entries-SGFS_NUMENTRIES;
! 341: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos();
! 342: break;
! 343: case SDLK_PAGEUP:
! 344: ypos -= SGFS_NUMENTRIES;
! 345: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos();
! 346: break;
1.1.1.2 root 347: case SDLK_PAGEDOWN:
348: if (ypos+2*SGFS_NUMENTRIES < entries)
349: ypos += SGFS_NUMENTRIES;
350: else
351: ypos = entries-SGFS_NUMENTRIES;
1.1.1.9 ! root 352: DlgFileSelect_Convert_ypos_to_scrollbar_Ypos();
1.1.1.2 root 353: break;
1.1.1.4 root 354: default:
355: break;
1.1.1.2 root 356: }
357: break;
1.1.1.4 root 358: default:
359: break;
360: }
1.1.1.9 ! root 361:
! 362: if (ypos < 0) {
1.1.1.4 root 363: ypos = 0;
1.1.1.9 ! root 364: scrollbar_Ypos = 0.0;
! 365: }
! 366:
1.1.1.4 root 367: if (ypos != oldypos)
1.1.1.7 root 368: refreshentries = true;
1.1.1.4 root 369: }
370:
371:
372: /*-----------------------------------------------------------------------*/
1.1.1.8 root 373: /**
374: * Free file entries
375: */
1.1.1.4 root 376: static struct dirent **files_free(struct dirent **files)
377: {
378: int i;
379: if (files != NULL)
380: {
381: for(i=0; i<entries; i++)
382: {
383: free(files[i]);
384: }
385: free(files);
386: }
387: return NULL;
388: }
389:
390:
391: /*-----------------------------------------------------------------------*/
1.1.1.8 root 392: /**
393: * Copy to dst src+add if they are below maxlen and return true,
394: * otherwise return false
395: */
1.1.1.4 root 396: static int strcat_maxlen(char *dst, int maxlen, const char *src, const char *add)
397: {
398: int slen, alen;
399: slen = strlen(src);
400: alen = strlen(add);
401: if (slen + alen < maxlen)
402: {
403: strcpy(dst, src);
404: strcpy(dst+slen, add);
405: return 1;
406: }
407: return 0;
408: }
409:
410: /*-----------------------------------------------------------------------*/
1.1.1.8 root 411: /**
412: * Create and return suitable path into zip file
413: */
1.1.1.4 root 414: static char* zip_get_path(const char *zipdir, const char *zipfilename, int browsingzip)
415: {
416: if (browsingzip)
417: {
418: char *zippath;
419: zippath = malloc(strlen(zipdir) + strlen(zipfilename) + 1);
420: strcpy(zippath, zipdir);
421: strcat(zippath, zipfilename);
422: return zippath;
1.1.1.2 root 423: }
1.1.1.4 root 424: return strdup("");
1.1.1.2 root 425: }
426:
1.1.1.8 root 427: /**
428: * string for zip root needs to be empty, check and correct if needed
429: */
1.1.1.4 root 430: static void correct_zip_root(char *zippath)
431: {
432: if (zippath[0] == PATHSEP && !zippath[1])
433: {
434: zippath[0] = '\0';
435: }
436: }
1.1.1.2 root 437:
1.1.1.9 ! root 438: /**
! 439: * Convert Ypos to Y scrollbar position
! 440: */
! 441: static void DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(void)
! 442: {
! 443: if (entries <= SGFS_NUMENTRIES)
! 444: scrollbar_Ypos = 0.0;
! 445: else
! 446: scrollbar_Ypos = (float)ypos / ((float)entries/(float)(SGFS_NUMENTRIES-2));
! 447: }
! 448:
1.1.1.2 root 449: /*-----------------------------------------------------------------------*/
1.1.1.8 root 450: /**
451: * Show and process a file selection dialog.
452: * Returns path/name user selected or NULL if user canceled
453: * input: zip_path = pointer's pointer to buffer to contain file path
454: * within a selected zip file, or NULL if browsing zip files is disallowed.
455: * bAllowNew: true if the user is allowed to insert new file names.
456: */
1.1.1.5 root 457: char* SDLGui_FileSelect(const char *path_and_name, char **zip_path, bool bAllowNew)
1.1 root 458: {
459: struct dirent **files = NULL;
460: char *pStringMem;
1.1.1.4 root 461: char *retpath;
1.1.1.8 root 462: const char *home;
463: char *path, *fname; /* The actual file and path names */
1.1.1.7 root 464: bool reloaddir = true; /* Do we have to reload the directory file list? */
1.1 root 465: int retbut;
466: int oldcursorstate;
1.1.1.9 ! root 467: int selection; /* The selection index */
1.1 root 468: char *zipfilename; /* Filename in zip file */
469: char *zipdir;
1.1.1.7 root 470: bool browsingzip = false; /* Are we browsing an archive? */
1.1 root 471: zip_dir *zipfiles = NULL;
1.1.1.2 root 472: SDL_Event sdlEvent;
1.1.1.9 ! root 473: int yScrolbar_size; /* Size of the vertical scrollbar */
1.1.1.2 root 474:
475: ypos = 0;
1.1.1.9 ! root 476: scrollbar_Ypos = 0.0;
1.1.1.7 root 477: refreshentries = true;
1.1.1.2 root 478: entries = 0;
1.1 root 479:
480: /* Allocate memory for the file and path name strings: */
481: pStringMem = malloc(4 * FILENAME_MAX);
482: path = pStringMem;
483: fname = pStringMem + FILENAME_MAX;
1.1.1.4 root 484: zipdir = pStringMem + 2 * FILENAME_MAX;
485: zipfilename = pStringMem + 3 * FILENAME_MAX;
1.1 root 486: zipfilename[0] = 0;
1.1.1.5 root 487: fname[0] = 0;
488: path[0] = 0;
1.1 root 489:
490: SDLGui_CenterDlg(fsdlg);
491: if (bAllowNew)
492: {
493: fsdlg[SGFSDLG_FILENAME].type = SGEDITFIELD;
494: fsdlg[SGFSDLG_FILENAME].flags |= SG_EXIT;
495: }
496: else
497: {
498: fsdlg[SGFSDLG_FILENAME].type = SGTEXT;
499: fsdlg[SGFSDLG_FILENAME].flags &= ~SG_EXIT;
500: }
501:
502: /* Prepare the path and filename variables */
1.1.1.4 root 503: if (path_and_name && path_and_name[0])
1.1.1.2 root 504: {
1.1.1.4 root 505: strncpy(path, path_and_name, FILENAME_MAX);
506: path[FILENAME_MAX-1] = '\0';
507: }
1.1.1.5 root 508: if (!File_DirExists(path))
1.1.1.4 root 509: {
1.1.1.5 root 510: File_SplitPath(path, path, fname, NULL);
511: if (!(File_DirExists(path) || getcwd(path, FILENAME_MAX)))
1.1.1.4 root 512: {
1.1.1.5 root 513: perror("SDLGui_FileSelect: non-existing path and CWD failed");
1.1.1.8 root 514: free(pStringMem);
1.1.1.4 root 515: return NULL;
516: }
1.1.1.2 root 517: }
1.1.1.5 root 518:
1.1.1.2 root 519: File_MakeAbsoluteName(path);
520: File_MakeValidPathName(path);
1.1 root 521: File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
522: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE);
523:
1.1.1.4 root 524: /* Save old mouse cursor state and enable cursor */
1.1 root 525: oldcursorstate = SDL_ShowCursor(SDL_QUERY);
526: if (oldcursorstate == SDL_DISABLE)
527: SDL_ShowCursor(SDL_ENABLE);
528:
529: do
530: {
531: if (reloaddir)
532: {
1.1.1.4 root 533: files = files_free(files);
1.1 root 534:
535: if (browsingzip)
536: {
537: files = ZIP_GetFilesDir(zipfiles, zipdir, &entries);
1.1.1.8 root 538: if(!files)
539: {
540: fprintf(stderr, "SDLGui_FileSelect: ZIP_GetFilesDir error!\n");
541: free(pStringMem);
542: return NULL;
543: }
1.1 root 544: }
545: else
546: {
547: /* Load directory entries: */
548: entries = scandir(path, &files, 0, alphasort);
549: }
1.1.1.3 root 550:
551: /* Remove hidden files from the list if necessary: */
552: if (!(fsdlg[SGFSDLG_SHOWHIDDEN].state & SG_SELECTED))
553: {
554: DlgFileSelect_RemoveHiddenFiles(files);
555: }
1.1 root 556:
557: if (entries < 0)
558: {
559: fprintf(stderr, "SDLGui_FileSelect: Path not found.\n");
560: free(pStringMem);
1.1.1.5 root 561: return NULL;
1.1 root 562: }
563:
1.1.1.4 root 564: /* reload always implies refresh */
1.1.1.7 root 565: reloaddir = false;
566: refreshentries = true;
1.1 root 567: }/* reloaddir */
568:
1.1.1.9 ! root 569: /* Refresh scrollbar size */
! 570: if (entries <= SGFS_NUMENTRIES)
! 571: yScrolbar_size = (SGFS_NUMENTRIES-2) * sdlgui_fontheight;
! 572: else
! 573: yScrolbar_size = (int)((SGFS_NUMENTRIES-2) / ((float)entries/(float)SGFS_NUMENTRIES) * sdlgui_fontheight);
! 574: fsdlg[SGFSDLG_SCROLLBAR].w = yScrolbar_size;
! 575:
! 576: /* Refresh scrolbar pos */
! 577: fsdlg[SGFSDLG_SCROLLBAR].h = (int) (scrollbar_Ypos * sdlgui_fontheight);
! 578: ypos = (int) (scrollbar_Ypos * ((float)entries/(float)(SGFS_NUMENTRIES-2)) + 0.5);
! 579:
1.1 root 580: /* Update the file name strings in the dialog? */
581: if (refreshentries)
582: {
1.1.1.2 root 583: if (!DlgFileSelect_RefreshEntries(files, path, browsingzip))
1.1 root 584: {
585: free(pStringMem);
1.1.1.5 root 586: return NULL;
1.1 root 587: }
1.1.1.7 root 588: refreshentries = false;
1.1 root 589: }
590:
591: /* Show dialog: */
1.1.1.2 root 592: retbut = SDLGui_DoDialog(fsdlg, &sdlEvent);
1.1 root 593:
594: /* Has the user clicked on a file or folder? */
1.1.1.9 ! root 595: if (retbut>=SGFSDLG_ENTRYFIRST && retbut<=SGFSDLG_ENTRYLAST && retbut-SGFSDLG_ENTRYFIRST+ypos<entries)
1.1 root 596: {
597: char *tempstr;
1.1.1.4 root 598:
1.1 root 599: tempstr = malloc(FILENAME_MAX);
600: if (!tempstr)
601: {
602: perror("Error while allocating temporary memory in SDLGui_FileSelect()");
603: free(pStringMem);
1.1.1.5 root 604: return NULL;
1.1 root 605: }
606:
1.1.1.7 root 607: if (browsingzip == true)
1.1 root 608: {
1.1.1.4 root 609: if (!strcat_maxlen(tempstr, FILENAME_MAX,
1.1.1.9 ! root 610: zipdir, files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name))
1.1.1.4 root 611: {
612: fprintf(stderr, "SDLGui_FileSelect: Path name too long!\n");
613: free(pStringMem);
1.1.1.5 root 614: return NULL;
1.1.1.4 root 615: }
616: /* directory? */
1.1.1.3 root 617: if (File_DoesFileNameEndWithSlash(tempstr))
1.1 root 618: {
619: /* handle the ../ directory */
1.1.1.9 ! root 620: if (strcmp(files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name, "../") == 0)
1.1 root 621: {
622: /* close the zip file */
1.1.1.4 root 623: if (strcmp(tempstr, "../") == 0)
1.1 root 624: {
625: /* free zip file entries */
626: ZIP_FreeZipDir(zipfiles);
627: zipfiles = NULL;
628: /* Copy the path name to the dialog */
629: File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
1.1.1.7 root 630: browsingzip = false;
1.1 root 631: }
632: else
633: {
1.1.1.4 root 634: /* remove "../" and previous dir from path */
635: File_PathShorten(tempstr, 2);
636: correct_zip_root(tempstr);
1.1 root 637: strcpy(zipdir, tempstr);
638: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
639: }
640: }
641: else /* not the "../" directory */
642: {
643: strcpy(zipdir, tempstr);
644: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
645: }
1.1.1.7 root 646: reloaddir = true;
1.1 root 647: /* Copy the path name to the dialog */
648: zipfilename[0] = '\0';
649: dlgfname[0] = 0;
650: ypos = 0;
1.1.1.9 ! root 651: scrollbar_Ypos = 0.0;
1.1 root 652: }
653: else
654: {
1.1.1.4 root 655: /* not dir, select a file in the zip */
1.1.1.9 ! root 656: selection = retbut-SGFSDLG_ENTRYFIRST+ypos;
1.1 root 657: strcpy(zipfilename, files[selection]->d_name);
658: File_ShrinkName(dlgfname, zipfilename, DLGFNAME_SIZE);
659: }
660:
1.1.1.4 root 661: }
662: else /* not browsingzip */
1.1 root 663: {
1.1.1.4 root 664: if (!strcat_maxlen(tempstr, FILENAME_MAX,
1.1.1.9 ! root 665: path, files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name))
1.1 root 666: {
1.1.1.4 root 667: fprintf(stderr, "SDLGui_FileSelect: Path name too long!\n");
668: free(pStringMem);
1.1.1.5 root 669: return NULL;
1.1.1.4 root 670: }
1.1.1.5 root 671: if (File_DirExists(tempstr))
1.1.1.4 root 672: {
673: File_HandleDotDirs(tempstr);
674: File_AddSlashToEndFileName(tempstr);
675: /* Copy the path name to the dialog */
676: File_ShrinkName(dlgpath, tempstr, DLGPATH_SIZE);
1.1 root 677: strcpy(path, tempstr);
1.1.1.7 root 678: reloaddir = true;
1.1 root 679: dlgfname[0] = 0;
680: ypos = 0;
1.1.1.9 ! root 681: scrollbar_Ypos = 0.0;
1.1 root 682: }
683: else if (ZIP_FileNameIsZIP(tempstr) && zip_path != NULL)
684: {
685: /* open a zip file */
686: zipfiles = ZIP_GetFiles(tempstr);
1.1.1.7 root 687: if (zipfiles != NULL && browsingzip == false)
1.1 root 688: {
1.1.1.9 ! root 689: selection = retbut-SGFSDLG_ENTRYFIRST+ypos;
1.1 root 690: strcpy(fname, files[selection]->d_name);
691: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE);
1.1.1.7 root 692: browsingzip = true;
1.1.1.4 root 693: zipdir[0] = '\0'; /* zip root */
1.1 root 694: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
1.1.1.7 root 695: reloaddir = true;
1.1 root 696: ypos = 0;
1.1.1.9 ! root 697: scrollbar_Ypos = 0.0;
1.1 root 698: }
699:
700: }
701: else
702: {
703: /* Select a file */
1.1.1.9 ! root 704: selection = retbut-SGFSDLG_ENTRYFIRST+ypos;
1.1 root 705: strcpy(fname, files[selection]->d_name);
706: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE);
707: }
708:
709: } /* not browsingzip */
710:
711: free(tempstr);
712: }
713: else /* Has the user clicked on another button? */
714: {
715: switch(retbut)
716: {
717: case SGFSDLG_UPDIR: /* Change path to parent directory */
1.1.1.4 root 718: if (browsingzip)
1.1 root 719: {
1.1.1.4 root 720: /* close the zip file? */
721: if (!zipdir[0])
1.1 root 722: {
723: /* free zip file entries */
724: ZIP_FreeZipDir(zipfiles);
1.1.1.7 root 725: browsingzip = false;
1.1 root 726: zipfiles = NULL;
727: File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
728: }
729: else
730: {
1.1.1.4 root 731: /* remove last dir from zipdir path */
732: File_PathShorten(zipdir, 1);
733: correct_zip_root(zipdir);
1.1 root 734: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
735: zipfilename[0] = '\0';
736: }
737: } /* not a zip file: */
1.1.1.4 root 738: else
1.1 root 739: {
1.1.1.4 root 740: File_PathShorten(path, 1);
741: File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
1.1 root 742: }
1.1.1.7 root 743: reloaddir = true;
1.1 root 744: break;
1.1.1.3 root 745:
746: case SGFSDLG_HOMEDIR: /* Change to home directory */
1.1.1.8 root 747: home = Paths_GetUserHome();
748: if (home == NULL || !*home)
1.1.1.3 root 749: break;
750: if (browsingzip)
751: {
752: /* free zip file entries */
753: ZIP_FreeZipDir(zipfiles);
754: zipfiles = NULL;
1.1.1.7 root 755: browsingzip = false;
1.1.1.3 root 756: }
1.1.1.4 root 757: strcpy(path, home);
1.1.1.3 root 758: File_AddSlashToEndFileName(path);
1.1.1.4 root 759: File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
1.1.1.7 root 760: reloaddir = true;
1.1.1.3 root 761: break;
762:
1.1 root 763: case SGFSDLG_ROOTDIR: /* Change to root directory */
1.1.1.4 root 764: if (browsingzip)
1.1 root 765: {
766: /* free zip file entries */
767: ZIP_FreeZipDir(zipfiles);
768: zipfiles = NULL;
1.1.1.7 root 769: browsingzip = false;
1.1 root 770: }
1.1.1.7 root 771: path[0] = PATHSEP; path[1] = '\0';
1.1 root 772: strcpy(dlgpath, path);
1.1.1.7 root 773: reloaddir = true;
1.1 root 774: break;
775: case SGFSDLG_UP: /* Scroll up */
1.1.1.2 root 776: DlgFileSelect_ScrollUp();
777: SDL_Delay(10);
1.1 root 778: break;
779: case SGFSDLG_DOWN: /* Scroll down */
1.1.1.2 root 780: DlgFileSelect_ScrollDown();
781: SDL_Delay(10);
1.1 root 782: break;
1.1.1.9 ! root 783: case SGFSDLG_SCROLLBAR: /* Scrollbar selected */
! 784: DlgFileSelect_ManageScrollbar();
! 785: SDL_Delay(10);
! 786: break;
1.1 root 787: case SGFSDLG_FILENAME: /* User entered new filename */
788: strcpy(fname, dlgfname);
789: break;
1.1.1.3 root 790: case SGFSDLG_SHOWHIDDEN: /* Show/hide hidden files */
1.1.1.7 root 791: reloaddir = true;
1.1.1.3 root 792: ypos = 0;
1.1.1.9 ! root 793: scrollbar_Ypos = 0.0;
1.1.1.3 root 794: break;
1.1.1.2 root 795: case SDLGUI_UNKNOWNEVENT:
796: DlgFileSelect_HandleSdlEvents(&sdlEvent);
797: break;
1.1 root 798: } /* switch */
1.1.1.4 root 799:
800: if (reloaddir)
801: {
802: /* Remove old selection */
803: fname[0] = 0;
804: dlgfname[0] = 0;
805: ypos = 0;
1.1.1.9 ! root 806: scrollbar_Ypos = 0.0;
1.1.1.4 root 807: }
1.1 root 808: } /* other button code */
809:
810:
811: } /* do */
1.1.1.4 root 812: while (retbut!=SGFSDLG_OKAY && retbut!=SGFSDLG_CANCEL
813: && retbut!=SDLGUI_QUIT && retbut != SDLGUI_ERROR && !bQuitProgram);
1.1 root 814:
815: if (oldcursorstate == SDL_DISABLE)
816: SDL_ShowCursor(SDL_DISABLE);
817:
1.1.1.4 root 818: files_free(files);
1.1 root 819:
820: if (browsingzip)
821: {
822: /* free zip file entries */
823: ZIP_FreeZipDir(zipfiles);
824: zipfiles = NULL;
825: }
826:
1.1.1.4 root 827: if (retbut == SGFSDLG_OKAY)
1.1 root 828: {
1.1.1.4 root 829: if (zip_path)
830: *zip_path = zip_get_path(zipdir, zipfilename, browsingzip);
831: retpath = File_MakePath(path, fname, NULL);
832: }
833: else
834: retpath = NULL;
835: free(pStringMem);
836: return retpath;
837: }
838:
839:
840: /*-----------------------------------------------------------------------*/
1.1.1.8 root 841: /**
842: * Let user browse for a file, confname is used as default.
1.1.1.4 root 843: * If bAllowNew is true, user can select new files also.
844: *
845: * If no file is selected, or there's some problem with the file,
1.1.1.7 root 846: * return false and clear dlgname & confname.
847: * Otherwise return true, set dlgname & confname to the new file name
1.1.1.4 root 848: * (dlgname is shrinked & limited to maxlen and confname is assumed
849: * to have FILENAME_MAX amount of space).
850: */
1.1.1.5 root 851: bool SDLGui_FileConfSelect(char *dlgname, char *confname, int maxlen, bool bAllowNew)
1.1.1.4 root 852: {
853: char *selname;
854:
855: selname = SDLGui_FileSelect(confname, NULL, bAllowNew);
856: if (selname)
857: {
858: if (!File_DoesFileNameEndWithSlash(selname) &&
859: (bAllowNew || File_Exists(selname)))
1.1 root 860: {
1.1.1.4 root 861: strncpy(confname, selname, FILENAME_MAX);
862: confname[FILENAME_MAX-1] = '\0';
863: File_ShrinkName(dlgname, selname, maxlen);
1.1 root 864: }
865: else
1.1.1.4 root 866: {
867: dlgname[0] = confname[0] = 0;
868: }
869: free(selname);
1.1.1.7 root 870: return true;
1.1 root 871: }
1.1.1.7 root 872: return false;
1.1 root 873: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.