Annotation of hatari/src/gui-sdl/dlgFileSelect.c, revision 1.1.1.12

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;
1.1.1.12! root      244: 
        !           245:        SDL_GetMouseState(&x, &y);
1.1.1.9   root      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.12! root      630:                                        free(tempstr);
1.1.1.10  root      631:                                        goto clean_exit;
1.1.1.4   root      632:                                }
                    633:                                /* directory? */
1.1.1.3   root      634:                                if (File_DoesFileNameEndWithSlash(tempstr))
1.1       root      635:                                {
                    636:                                        /* handle the ../ directory */
1.1.1.9   root      637:                                        if (strcmp(files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name, "../") == 0)
1.1       root      638:                                        {
                    639:                                                /* close the zip file */
1.1.1.4   root      640:                                                if (strcmp(tempstr, "../") == 0)
1.1       root      641:                                                {
                    642:                                                        /* free zip file entries */
                    643:                                                        ZIP_FreeZipDir(zipfiles);
                    644:                                                        zipfiles = NULL;
                    645:                                                        /* Copy the path name to the dialog */
                    646:                                                        File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
1.1.1.7   root      647:                                                        browsingzip = false;
1.1       root      648:                                                }
                    649:                                                else
                    650:                                                {
1.1.1.4   root      651:                                                        /* remove "../" and previous dir from path */
                    652:                                                        File_PathShorten(tempstr, 2);
                    653:                                                        correct_zip_root(tempstr);
1.1       root      654:                                                        strcpy(zipdir, tempstr);
                    655:                                                        File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
                    656:                                                }
                    657:                                        }
                    658:                                        else /* not the "../" directory */
                    659:                                        {
                    660:                                                strcpy(zipdir, tempstr);
                    661:                                                File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
                    662:                                        }
1.1.1.7   root      663:                                        reloaddir = true;
1.1       root      664:                                        /* Copy the path name to the dialog */
                    665:                                        zipfilename[0] = '\0';
                    666:                                        dlgfname[0] = 0;
                    667:                                        ypos = 0;
1.1.1.9   root      668:                                        scrollbar_Ypos = 0.0;
1.1       root      669:                                }
                    670:                                else
                    671:                                {
1.1.1.4   root      672:                                        /* not dir, select a file in the zip */
1.1.1.9   root      673:                                        selection = retbut-SGFSDLG_ENTRYFIRST+ypos;
1.1       root      674:                                        strcpy(zipfilename, files[selection]->d_name);
                    675:                                        File_ShrinkName(dlgfname, zipfilename, DLGFNAME_SIZE);
                    676:                                }
                    677: 
1.1.1.4   root      678:                        }
                    679:                        else /* not browsingzip */
1.1       root      680:                        {
1.1.1.4   root      681:                                if (!strcat_maxlen(tempstr, FILENAME_MAX,
1.1.1.9   root      682:                                                   path, files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name))
1.1       root      683:                                {
1.1.1.4   root      684:                                        fprintf(stderr, "SDLGui_FileSelect: Path name too long!\n");
1.1.1.12! root      685:                                        free(tempstr);
1.1.1.10  root      686:                                        goto clean_exit;
1.1.1.4   root      687:                                }
1.1.1.5   root      688:                                if (File_DirExists(tempstr))
1.1.1.4   root      689:                                {
                    690:                                        File_HandleDotDirs(tempstr);
                    691:                                        File_AddSlashToEndFileName(tempstr);
                    692:                                        /* Copy the path name to the dialog */
                    693:                                        File_ShrinkName(dlgpath, tempstr, DLGPATH_SIZE);
1.1       root      694:                                        strcpy(path, tempstr);
1.1.1.7   root      695:                                        reloaddir = true;
1.1       root      696:                                        dlgfname[0] = 0;
                    697:                                        ypos = 0;
1.1.1.9   root      698:                                        scrollbar_Ypos = 0.0;
1.1       root      699:                                }
                    700:                                else if (ZIP_FileNameIsZIP(tempstr) && zip_path != NULL)
                    701:                                {
                    702:                                        /* open a zip file */
                    703:                                        zipfiles = ZIP_GetFiles(tempstr);
1.1.1.7   root      704:                                        if (zipfiles != NULL && browsingzip == false)
1.1       root      705:                                        {
1.1.1.9   root      706:                                                selection = retbut-SGFSDLG_ENTRYFIRST+ypos;
1.1       root      707:                                                strcpy(fname, files[selection]->d_name);
                    708:                                                File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE);
1.1.1.7   root      709:                                                browsingzip = true;
1.1.1.4   root      710:                                                zipdir[0] = '\0'; /* zip root */
1.1       root      711:                                                File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
1.1.1.7   root      712:                                                reloaddir = true;
1.1       root      713:                                                ypos = 0;
1.1.1.9   root      714:                                                scrollbar_Ypos = 0.0;
1.1       root      715:                                        }
                    716: 
                    717:                                }
                    718:                                else
                    719:                                {
                    720:                                        /* Select a file */
1.1.1.9   root      721:                                        selection = retbut-SGFSDLG_ENTRYFIRST+ypos;
1.1       root      722:                                        strcpy(fname, files[selection]->d_name);
                    723:                                        File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE);
                    724:                                }
                    725: 
                    726:                        } /* not browsingzip */
                    727: 
                    728:                        free(tempstr);
                    729:                }
                    730:                else    /* Has the user clicked on another button? */
                    731:                {
                    732:                        switch(retbut)
                    733:                        {
                    734:                        case SGFSDLG_UPDIR:                 /* Change path to parent directory */
1.1.1.4   root      735:                                if (browsingzip)
1.1       root      736:                                {
1.1.1.4   root      737:                                        /* close the zip file? */
                    738:                                        if (!zipdir[0])
1.1       root      739:                                        {
                    740:                                                /* free zip file entries */
                    741:                                                ZIP_FreeZipDir(zipfiles);
1.1.1.7   root      742:                                                browsingzip = false;
1.1       root      743:                                                zipfiles = NULL;
                    744:                                                File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
                    745:                                        }
                    746:                                        else
                    747:                                        {
1.1.1.4   root      748:                                                /* remove last dir from zipdir path */
                    749:                                                File_PathShorten(zipdir, 1);
                    750:                                                correct_zip_root(zipdir);
1.1       root      751:                                                File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
                    752:                                                zipfilename[0] = '\0';
                    753:                                        }
                    754:                                }  /* not a zip file: */
1.1.1.4   root      755:                                else
1.1       root      756:                                {
1.1.1.4   root      757:                                        File_PathShorten(path, 1);
                    758:                                        File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
1.1       root      759:                                }
1.1.1.7   root      760:                                reloaddir = true;
1.1       root      761:                                break;
1.1.1.3   root      762: 
                    763:                        case SGFSDLG_HOMEDIR:               /* Change to home directory */
1.1.1.11  root      764:                        case SGFSDLG_CWD:                   /* Change to current work directory */
                    765:                                if (retbut == SGFSDLG_CWD)
                    766:                                        home = Paths_GetWorkingDir();
                    767:                                else
                    768:                                        home = Paths_GetUserHome();
1.1.1.8   root      769:                                if (home == NULL || !*home)
1.1.1.3   root      770:                                        break;
                    771:                                if (browsingzip)
                    772:                                {
                    773:                                        /* free zip file entries */
                    774:                                        ZIP_FreeZipDir(zipfiles);
                    775:                                        zipfiles = NULL;
1.1.1.7   root      776:                                        browsingzip = false;
1.1.1.3   root      777:                                }
1.1.1.4   root      778:                                strcpy(path, home);
1.1.1.3   root      779:                                File_AddSlashToEndFileName(path);
1.1.1.4   root      780:                                File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
1.1.1.7   root      781:                                reloaddir = true;
1.1.1.3   root      782:                                break;
                    783: 
1.1       root      784:                        case SGFSDLG_ROOTDIR:               /* Change to root directory */
1.1.1.4   root      785:                                if (browsingzip)
1.1       root      786:                                {
                    787:                                        /* free zip file entries */
                    788:                                        ZIP_FreeZipDir(zipfiles);
                    789:                                        zipfiles = NULL;
1.1.1.7   root      790:                                        browsingzip = false;
1.1       root      791:                                }
1.1.1.7   root      792:                                path[0] = PATHSEP; path[1] = '\0';
1.1       root      793:                                strcpy(dlgpath, path);
1.1.1.7   root      794:                                reloaddir = true;
1.1       root      795:                                break;
                    796:                        case SGFSDLG_UP:                    /* Scroll up */
1.1.1.2   root      797:                                DlgFileSelect_ScrollUp();
                    798:                                SDL_Delay(10);
1.1       root      799:                                break;
                    800:                        case SGFSDLG_DOWN:                  /* Scroll down */
1.1.1.2   root      801:                                DlgFileSelect_ScrollDown();
                    802:                                SDL_Delay(10);
1.1       root      803:                                break;
1.1.1.9   root      804:                        case SGFSDLG_SCROLLBAR:             /* Scrollbar selected */
                    805:                                DlgFileSelect_ManageScrollbar();
                    806:                                SDL_Delay(10);
                    807:                                break;
1.1       root      808:                        case SGFSDLG_FILENAME:              /* User entered new filename */
                    809:                                strcpy(fname, dlgfname);
                    810:                                break;
1.1.1.3   root      811:                        case SGFSDLG_SHOWHIDDEN:            /* Show/hide hidden files */
1.1.1.7   root      812:                                reloaddir = true;
1.1.1.3   root      813:                                ypos = 0;
1.1.1.9   root      814:                                scrollbar_Ypos = 0.0;
1.1.1.3   root      815:                                break;
1.1.1.2   root      816:                        case SDLGUI_UNKNOWNEVENT:
                    817:                                DlgFileSelect_HandleSdlEvents(&sdlEvent);
                    818:                                break;
1.1       root      819:                        } /* switch */
1.1.1.4   root      820:       
                    821:                        if (reloaddir)
                    822:                        {
                    823:                                /* Remove old selection */
                    824:                                fname[0] = 0;
                    825:                                dlgfname[0] = 0;
                    826:                                ypos = 0;
1.1.1.9   root      827:                                scrollbar_Ypos = 0.0;
1.1.1.4   root      828:                        }
1.1       root      829:                } /* other button code */
                    830: 
                    831: 
                    832:        } /* do */
1.1.1.4   root      833:        while (retbut!=SGFSDLG_OKAY && retbut!=SGFSDLG_CANCEL
                    834:               && retbut!=SDLGUI_QUIT && retbut != SDLGUI_ERROR && !bQuitProgram);
1.1       root      835: 
1.1.1.4   root      836:        files_free(files);
1.1       root      837: 
                    838:        if (browsingzip)
                    839:        {
                    840:                /* free zip file entries */
                    841:                ZIP_FreeZipDir(zipfiles);
                    842:                zipfiles = NULL;
                    843:        }
                    844: 
1.1.1.4   root      845:        if (retbut == SGFSDLG_OKAY)
1.1       root      846:        {
1.1.1.4   root      847:                if (zip_path)
                    848:                        *zip_path = zip_get_path(zipdir, zipfilename, browsingzip);
                    849:                retpath = File_MakePath(path, fname, NULL);
                    850:        }
                    851:        else
                    852:                retpath = NULL;
1.1.1.10  root      853: clean_exit:
                    854:        SDL_ShowCursor(bOldMouseVisibility);
1.1.1.4   root      855:        free(pStringMem);
                    856:        return retpath;
                    857: }
                    858: 
                    859: 
                    860: /*-----------------------------------------------------------------------*/
1.1.1.8   root      861: /**
                    862:  * Let user browse for a file, confname is used as default.
1.1.1.4   root      863:  * If bAllowNew is true, user can select new files also.
                    864:  * 
                    865:  * If no file is selected, or there's some problem with the file,
1.1.1.7   root      866:  * return false and clear dlgname & confname.
                    867:  * Otherwise return true, set dlgname & confname to the new file name
1.1.1.11  root      868:  * (dlgname is shrunken & limited to maxlen and confname is assumed
1.1.1.4   root      869:  * to have FILENAME_MAX amount of space).
                    870:  */
1.1.1.5   root      871: bool SDLGui_FileConfSelect(char *dlgname, char *confname, int maxlen, bool bAllowNew)
1.1.1.4   root      872: {
                    873:        char *selname;
                    874:        
                    875:        selname = SDLGui_FileSelect(confname, NULL, bAllowNew);
                    876:        if (selname)
                    877:        {
                    878:                if (!File_DoesFileNameEndWithSlash(selname) &&
                    879:                    (bAllowNew || File_Exists(selname)))
1.1       root      880:                {
1.1.1.4   root      881:                        strncpy(confname, selname, FILENAME_MAX);
                    882:                        confname[FILENAME_MAX-1] = '\0';
                    883:                        File_ShrinkName(dlgname, selname, maxlen);
1.1       root      884:                }
                    885:                else
1.1.1.4   root      886:                {
                    887:                        dlgname[0] = confname[0] = 0;
                    888:                }
                    889:                free(selname);
1.1.1.7   root      890:                return true;
1.1       root      891:        }
1.1.1.7   root      892:        return false;
1.1       root      893: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.