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