--- hatari/src/gui-sdl/dlgFileSelect.c 2019/04/09 08:48:52 1.1.1.8 +++ hatari/src/gui-sdl/dlgFileSelect.c 2019/04/09 08:55:54 1.1.1.13 @@ -1,9 +1,9 @@ /* Hatari - dlgFileSelect.c - - This file is distributed under the GNU Public License, version 2 or at - your option any later version. Read the file gpl.txt for details. - + + This file is distributed under the GNU General Public License, version 2 + or at your option any later version. Read the file gpl.txt for details. + A file selection dialog for the graphical user interface for Hatari. */ const char DlgFileSelect_fileid[] = "Hatari dlgFileSelect.c : " __DATE__ " " __TIME__; @@ -22,19 +22,23 @@ const char DlgFileSelect_fileid[] = "Hat #define SGFS_NUMENTRIES 16 /* How many entries are displayed at once */ +#define SGFSDLG_TITLE 1 +#define SGFSDLG_FILENAME 5 +#define SGFSDLG_UPDIR 6 +#define SGFSDLG_CWD 7 +#define SGFSDLG_HOMEDIR 8 +#define SGFSDLG_ROOTDIR 9 +#define SGFSDLG_ENTRYFIRST 12 +#define SGFSDLG_ENTRYLAST 27 +#define SGFSDLG_SCROLLBAR 28 +#define SGFSDLG_UP 29 +#define SGFSDLG_DOWN 30 +#define SGFSDLG_SHOWHIDDEN 31 +#define SGFSDLG_OKAY 32 +#define SGFSDLG_CANCEL 33 -#define SGFSDLG_FILENAME 5 -#define SGFSDLG_UPDIR 6 -#define SGFSDLG_HOMEDIR 7 -#define SGFSDLG_ROOTDIR 8 -#define SGFSDLG_ENTRY1 11 -#define SGFSDLG_ENTRY16 26 -#define SGFSDLG_UP 27 -#define SGFSDLG_DOWN 28 -#define SGFSDLG_SHOWHIDDEN 29 -#define SGFSDLG_OKAY 30 -#define SGFSDLG_CANCEL 31 - +#define SCROLLOUT_ABOVE 1 +#define SCROLLOUT_UNDER 2 #define DLGPATH_SIZE 62 static char dlgpath[DLGPATH_SIZE+1]; /* Path name in the dialog */ @@ -45,18 +49,24 @@ static char dlgfname[DLGFNAME_SIZE+1]; #define DLGFILENAMES_SIZE 59 static char dlgfilenames[SGFS_NUMENTRIES][DLGFILENAMES_SIZE+1]; /* Visible file names in the dialog */ +#define SCROLLBAR_MIN_HEIGHT 4 /* Min value for yScrollbar_size */ + +#define TITLE_OFFSET 1 +#define TITLE_MAXLEN 40 + /* The dialog data: */ static SGOBJ fsdlg[] = { { SGBOX, 0, 0, 0,0, 64,25, NULL }, - { SGTEXT, 0, 0, 25,1, 13,1, "Choose a file" }, + { SGTEXT, 0, 0, 1,1, 13,1, NULL, }, { SGTEXT, 0, 0, 1,2, 7,1, "Folder:" }, { SGTEXT, 0, 0, 1,3, DLGPATH_SIZE,1, dlgpath }, { SGTEXT, 0, 0, 1,4, 6,1, "File:" }, { SGTEXT, 0, 0, 7,4, DLGFNAME_SIZE,1, dlgfname }, - { SGBUTTON, 0, 0, 51,1, 4,1, ".." }, - { SGBUTTON, 0, 0, 56,1, 3,1, "~" }, - { SGBUTTON, 0, 0, 60,1, 3,1, "/" }, + { SGBUTTON, 0, 0, 39,1, 4,1, "_Up" }, + { SGBUTTON, 0, 0, 44,1, 5,1, "_CWD" }, + { SGBUTTON, 0, 0, 50,1, 6,1, "_Home" }, + { SGBUTTON, 0, 0, 57,1, 6,1, "_Root" }, { SGBOX, 0, 0, 1,6, 62,16, NULL }, { SGBOX, 0, 0, 62,7, 1,14, NULL }, { SGTEXT, SG_EXIT, 0, 2,6, DLGFILENAMES_SIZE,1, dlgfilenames[0] }, @@ -75,18 +85,38 @@ static SGOBJ fsdlg[] = { SGTEXT, SG_EXIT, 0, 2,19, DLGFILENAMES_SIZE,1, dlgfilenames[13] }, { SGTEXT, SG_EXIT, 0, 2,20, DLGFILENAMES_SIZE,1, dlgfilenames[14] }, { SGTEXT, SG_EXIT, 0, 2,21, DLGFILENAMES_SIZE,1, dlgfilenames[15] }, - { SGBUTTON, SG_TOUCHEXIT, 0, 62,6, 1,1, "\x01" }, /* Arrow up */ - { SGBUTTON, SG_TOUCHEXIT, 0, 62,21, 1,1, "\x02" }, /* Arrow down */ - { SGCHECKBOX, SG_EXIT, 0, 2,23, 18,1, "Show hidden files" }, - { SGBUTTON, SG_DEFAULT, 0, 32,23, 8,1, "Okay" }, + { SGSCROLLBAR, SG_TOUCHEXIT, 0, 62, 7, 0, 0, NULL }, /* Scrollbar */ + { SGBUTTON, SG_TOUCHEXIT, 0, 62, 6,1,1, "\x01", SG_SHORTCUT_UP }, + { SGBUTTON, SG_TOUCHEXIT, 0, 62,21,1,1, "\x02", SG_SHORTCUT_DOWN }, + { SGCHECKBOX, SG_EXIT, 0, 2,23, 19,1, "_Show hidden files" }, + { SGBUTTON, SG_DEFAULT, 0, 32,23, 8,1, "OK" }, { SGBUTTON, SG_CANCEL, 0, 50,23, 8,1, "Cancel" }, { -1, 0, 0, 0,0, 0,0, NULL } }; -static int ypos; /* First entry number to be displayed */ -static bool refreshentries; /* Do we have to update the file names in the dialog? */ -static int entries; /* How many files are in the actual directory? */ +static int ypos = -1; /* First entry number to be displayed. If -1, file selector start on the 1st file */ + /* else we continue from the previous position when SDLGui_FileSelect is called again */ +static bool refreshentries; /* Do we have to update the file names in the dialog? */ +static int entries; /* How many files are in the actual directory? */ +static int oldMouseY = 0; /* Keep the latest Y mouse position for scrollbar move computing */ +static int mouseClicked = 0; /* used to know if mouse if down for the first time or not */ +static int mouseIsOut = 0; /* used to keep info that mouse if above or under the scrollbar when mousebutton is down */ +static float scrollbar_Ypos = 0.0; /* scrollbar heigth */ + +static char *dirpath; /* for get_dtype() */ +#ifndef HAVE_DIRENT_D_TYPE +enum { + DT_UNKNOWN, + DT_LNK, + DT_DIR, + DT_REG +}; +#endif + +/* Convert file position (in file list) to scrollbar y position */ +static void DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(void); + /*-----------------------------------------------------------------------*/ @@ -131,9 +161,14 @@ static int DlgFileSelect_RefreshEntries( if (ZIP_FileNameIsZIP(tempstr) && browsingzip == false) dlgfilenames[i][0] = SGFOLDER; /* Mark .ZIP archives as folders */ } + + fsdlg[SGFSDLG_ENTRYFIRST+i].flags |= SG_EXIT; } else + { dlgfilenames[i][0] = 0; /* Clear entry */ + fsdlg[SGFSDLG_ENTRYFIRST+i].flags &= ~SG_EXIT; + } } free(tempstr); @@ -185,6 +220,23 @@ static void DlgFileSelect_RemoveHiddenFi } } +/** + * Reset focus to first entry if necessary. + */ +static void DlgFileSelect_ResetFocus(void) +{ + int i; + + for (i = SGFSDLG_ENTRYFIRST+1; i <= SGFSDLG_ENTRYLAST; i++) + { + if (fsdlg[i].state & SG_FOCUSED) + { + fsdlg[i].state &= ~SG_FOCUSED; + fsdlg[SGFSDLG_ENTRYFIRST].state |= SG_FOCUSED; + break; + } + } +} /*-----------------------------------------------------------------------*/ /** @@ -195,6 +247,7 @@ static void DlgFileSelect_ScrollUp(void) if (ypos > 0) { --ypos; + DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); refreshentries = true; } } @@ -209,10 +262,91 @@ static void DlgFileSelect_ScrollDown(voi if (ypos+SGFS_NUMENTRIES < entries) { ++ypos; + DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); refreshentries = true; } } +/*-----------------------------------------------------------------------*/ +/** + * Manage the scrollbar up or down. + */ +static void DlgFileSelect_ManageScrollbar(void) +{ + int b, x, y; + int scrollY, scrollYmin, scrollYmax, scrollH_half; + float scrollMove; + + SDL_GetMouseState(&x, &y); + + /* If mouse is down on the scrollbar for the first time */ + if (fsdlg[SGFSDLG_SCROLLBAR].state & SG_MOUSEDOWN) { + if (mouseClicked == 0) { + mouseClicked = 1; + mouseIsOut = 0; + oldMouseY = y; + } + } + /* Mouse button is up on the scrollbar */ + else { + mouseClicked = 0; + oldMouseY = y; + mouseIsOut = 0; + } + + /* If mouse Y position didn't change */ + if (oldMouseY == y) + return; + + /* Compute scrollbar ymin and ymax values */ + + scrollYmin = (fsdlg[SGFSDLG_SCROLLBAR].y + fsdlg[0].y) * sdlgui_fontheight; + scrollYmax = (fsdlg[SGFSDLG_DOWN].y + fsdlg[0].y) * sdlgui_fontheight; + + scrollY = fsdlg[SGFSDLG_SCROLLBAR].y * sdlgui_fontheight + fsdlg[SGFSDLG_SCROLLBAR].h + fsdlg[0].y * sdlgui_fontheight; + scrollH_half = scrollY + fsdlg[SGFSDLG_SCROLLBAR].w / 2; + scrollMove = (float)(y-oldMouseY)/sdlgui_fontheight; + + /* Verify if mouse is not above the scrollbar area */ + if (y < scrollYmin) { + mouseIsOut = SCROLLOUT_ABOVE; + oldMouseY = y; + return; + } + if (mouseIsOut == SCROLLOUT_ABOVE && y < scrollH_half) { + oldMouseY = y; + return; + } + + /* Verify if mouse is not under the scrollbar area */ + if (y > scrollYmax) { + mouseIsOut = SCROLLOUT_UNDER; + oldMouseY = y; + return; + } + if (mouseIsOut == SCROLLOUT_UNDER && y > scrollH_half) { + oldMouseY = y; + return; + } + + mouseIsOut = 0; + + scrollbar_Ypos += scrollMove; + oldMouseY = y; + + /* Verifiy if scrollbar is in correct inferior boundary */ + if (scrollbar_Ypos < 0) + scrollbar_Ypos = 0.0; + + /* Verifiy if scrollbar is in correct superior boundary */ + b = (int) (scrollbar_Ypos * ((float)entries/(float)(SGFS_NUMENTRIES-2)) + 0.5); + if (b+SGFS_NUMENTRIES >= entries) { + ypos = entries - SGFS_NUMENTRIES; + DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); + } + + refreshentries = true; +} /*-----------------------------------------------------------------------*/ /** @@ -223,25 +357,48 @@ static void DlgFileSelect_HandleSdlEvent int oldypos = ypos; switch (pEvent->type) { +#if WITH_SDL2 + case SDL_MOUSEWHEEL: + if (pEvent->wheel.y>0) + DlgFileSelect_ScrollUp(); + else if (pEvent->wheel.y<0) + DlgFileSelect_ScrollDown(); + break; +#else case SDL_MOUSEBUTTONDOWN: if (pEvent->button.button == SDL_BUTTON_WHEELUP) DlgFileSelect_ScrollUp(); else if (pEvent->button.button == SDL_BUTTON_WHEELDOWN) DlgFileSelect_ScrollDown(); break; +#endif case SDL_KEYDOWN: switch (pEvent->key.keysym.sym) { - case SDLK_UP: DlgFileSelect_ScrollUp(); break; - case SDLK_DOWN: DlgFileSelect_ScrollDown(); break; - case SDLK_HOME: ypos = 0; break; - case SDLK_END: ypos = entries-SGFS_NUMENTRIES; break; - case SDLK_PAGEUP: ypos -= SGFS_NUMENTRIES; break; + case SDLK_UP: + DlgFileSelect_ScrollUp(); + break; + case SDLK_DOWN: + DlgFileSelect_ScrollDown(); + break; + case SDLK_HOME: + ypos = 0; + DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); + break; + case SDLK_END: + ypos = entries-SGFS_NUMENTRIES; + DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); + break; + case SDLK_PAGEUP: + ypos -= SGFS_NUMENTRIES; + DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); + break; case SDLK_PAGEDOWN: if (ypos+2*SGFS_NUMENTRIES < entries) ypos += SGFS_NUMENTRIES; else ypos = entries-SGFS_NUMENTRIES; + DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); break; default: break; @@ -250,8 +407,12 @@ static void DlgFileSelect_HandleSdlEvent default: break; } - if (ypos < 0) + + if (ypos < 0) { ypos = 0; + scrollbar_Ypos = 0.0; + } + if (ypos != oldypos) refreshentries = true; } @@ -297,6 +458,58 @@ static int strcat_maxlen(char *dst, int /*-----------------------------------------------------------------------*/ /** + * Get given file's type, directory or a file. + * (if name itself is symlink, stat() checks file it points to) + */ +static int get_dtype(const char *name) +{ + struct stat buf; + char path[FILENAME_MAX]; + + snprintf(path, sizeof(path), "%s%c%s", dirpath, PATHSEP, name); + if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) + return DT_DIR; + else + return DT_REG; +} + +/*-----------------------------------------------------------------------*/ +/** + * Case insensitive sorting for directory entry names, so + * that directory entries are listed first. + */ +static int filesort(const struct dirent **d1, const struct dirent **d2) +{ + const char *name1 = (*d1)->d_name; + const char *name2 = (*d2)->d_name; +#ifndef HAVE_DIRENT_D_TYPE + int type1 = DT_UNKNOWN; + int type2 = DT_UNKNOWN; +#else + int type1 = (*d1)->d_type; + int type2 = (*d2)->d_type; +#endif + + /* OS / file system that doesn't support d_type field, or symlink */ + if (type1 == DT_UNKNOWN || type1 == DT_LNK) + type1 = get_dtype(name1); + if (type2 == DT_UNKNOWN || type2 == DT_LNK) + type2 = get_dtype(name2); + + if (type1 == DT_DIR) + { + if (type2 != DT_DIR) + return -1; + } else if (type2 == DT_DIR) + { + if (type1 != DT_DIR) + return 1; + } + return strcasecmp(name1, name2); +} + +/*-----------------------------------------------------------------------*/ +/** * Create and return suitable path into zip file */ static char* zip_get_path(const char *zipdir, const char *zipfilename, int browsingzip) @@ -323,6 +536,17 @@ static void correct_zip_root(char *zippa } } +/** + * Convert Ypos to Y scrollbar position + */ +static void DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(void) +{ + if (entries <= SGFS_NUMENTRIES) + scrollbar_Ypos = 0.0; + else + scrollbar_Ypos = (float)ypos / ((float)entries/(float)(SGFS_NUMENTRIES-2)); +} + /*-----------------------------------------------------------------------*/ /** * Show and process a file selection dialog. @@ -331,24 +555,40 @@ static void correct_zip_root(char *zippa * within a selected zip file, or NULL if browsing zip files is disallowed. * bAllowNew: true if the user is allowed to insert new file names. */ -char* SDLGui_FileSelect(const char *path_and_name, char **zip_path, bool bAllowNew) +char* SDLGui_FileSelect(const char *title, const char *path_and_name, char **zip_path, bool bAllowNew) { struct dirent **files = NULL; char *pStringMem; - char *retpath; + char *retpath = NULL; const char *home; char *path, *fname; /* The actual file and path names */ bool reloaddir = true; /* Do we have to reload the directory file list? */ - int retbut; - int oldcursorstate; - int selection = -1; /* The actual selection, -1 if none selected */ + int retbut, len; + bool bOldMouseVisibility; + int selection; /* The selection index */ char *zipfilename; /* Filename in zip file */ char *zipdir; bool browsingzip = false; /* Are we browsing an archive? */ zip_dir *zipfiles = NULL; SDL_Event sdlEvent; + int yScrollbar_size; /* Size of the vertical scrollbar */ + union { + char *mtxt; + const char *ctxt; + } dlgtitle; /* A hack to silent recent GCCs warnings */ + bool KeepCurrentObject; + + dlgtitle.ctxt = title; + + /* If this is the first call to SDLGui_FileSelect, we reset scrollbar_Ypos and ypos */ + /* Else, we keep the previous value of scrollbar_Ypos and update ypos below, to open */ + /* the fileselector at the same position it was used */ + if ( ypos < 0 ) + { + scrollbar_Ypos = 0.0; + ypos = 0; + } - ypos = 0; refreshentries = true; entries = 0; @@ -362,6 +602,15 @@ char* SDLGui_FileSelect(const char *path fname[0] = 0; path[0] = 0; + len = strlen(title); + fsdlg[SGFSDLG_TITLE].txt = dlgtitle.mtxt; + fsdlg[SGFSDLG_TITLE].x = TITLE_OFFSET + (TITLE_MAXLEN-len)/2; + fsdlg[SGFSDLG_TITLE].w = len; + + /* Save mouse state and enable cursor */ + bOldMouseVisibility = SDL_ShowCursor(SDL_QUERY); + SDL_ShowCursor(SDL_ENABLE); + SDLGui_CenterDlg(fsdlg); if (bAllowNew) { @@ -386,8 +635,7 @@ char* SDLGui_FileSelect(const char *path if (!(File_DirExists(path) || getcwd(path, FILENAME_MAX))) { perror("SDLGui_FileSelect: non-existing path and CWD failed"); - free(pStringMem); - return NULL; + goto clean_exit; } } @@ -396,10 +644,9 @@ char* SDLGui_FileSelect(const char *path File_ShrinkName(dlgpath, path, DLGPATH_SIZE); File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE); - /* Save old mouse cursor state and enable cursor */ - oldcursorstate = SDL_ShowCursor(SDL_QUERY); - if (oldcursorstate == SDL_DISABLE) - SDL_ShowCursor(SDL_ENABLE); + /* The first time we display the dialog, we reset the current position */ + /* On next calls, current_object's value will be kept to handle scrolling */ + KeepCurrentObject = false; do { @@ -413,16 +660,17 @@ char* SDLGui_FileSelect(const char *path if(!files) { fprintf(stderr, "SDLGui_FileSelect: ZIP_GetFilesDir error!\n"); - free(pStringMem); - return NULL; + goto clean_exit; } } else { + /* for get_dtype() */ + dirpath = path; /* Load directory entries: */ - entries = scandir(path, &files, 0, alphasort); + entries = scandir(path, &files, NULL, filesort); } - + /* Remove hidden files from the list if necessary: */ if (!(fsdlg[SGFSDLG_SHOWHIDDEN].state & SG_SELECTED)) { @@ -432,56 +680,79 @@ char* SDLGui_FileSelect(const char *path if (entries < 0) { fprintf(stderr, "SDLGui_FileSelect: Path not found.\n"); - free(pStringMem); - return NULL; + goto clean_exit; } /* reload always implies refresh */ reloaddir = false; refreshentries = true; + + /* Check if focus was in list - if yes then reset to first entry */ + DlgFileSelect_ResetFocus(); }/* reloaddir */ + /* Refresh scrollbar size */ + if (entries <= SGFS_NUMENTRIES) + yScrollbar_size = (SGFS_NUMENTRIES-2) * sdlgui_fontheight; + else + { + yScrollbar_size = (int)((SGFS_NUMENTRIES-2) / ((float)entries/(float)SGFS_NUMENTRIES) * sdlgui_fontheight); + if ( yScrollbar_size < SCROLLBAR_MIN_HEIGHT ) /* Value could be 0 for very large directory */ + yScrollbar_size = SCROLLBAR_MIN_HEIGHT; + } + fsdlg[SGFSDLG_SCROLLBAR].w = yScrollbar_size; + + /* Refresh scrolbar pos */ + ypos = (int) (scrollbar_Ypos * ((float)entries/(float)(SGFS_NUMENTRIES-2)) + 0.5); + + if (ypos+SGFS_NUMENTRIES >= entries) { /* Ensure Y pos is in the correct boundaries */ + ypos = entries - SGFS_NUMENTRIES; + if ( ypos < 0 ) + ypos = 0; + DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); + } + fsdlg[SGFSDLG_SCROLLBAR].h = (int) (scrollbar_Ypos * sdlgui_fontheight); + /* Update the file name strings in the dialog? */ if (refreshentries) { if (!DlgFileSelect_RefreshEntries(files, path, browsingzip)) { - free(pStringMem); - return NULL; + goto clean_exit; } refreshentries = false; } /* Show dialog: */ - retbut = SDLGui_DoDialog(fsdlg, &sdlEvent); + retbut = SDLGui_DoDialog(fsdlg, &sdlEvent, KeepCurrentObject); + KeepCurrentObject = true; /* Don't reset current_object for next calls */ /* Has the user clicked on a file or folder? */ - if (retbut>=SGFSDLG_ENTRY1 && retbut<=SGFSDLG_ENTRY16 && retbut-SGFSDLG_ENTRY1+ypos=SGFSDLG_ENTRYFIRST && retbut<=SGFSDLG_ENTRYLAST && retbut-SGFSDLG_ENTRYFIRST+yposd_name)) + zipdir, files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name)) { fprintf(stderr, "SDLGui_FileSelect: Path name too long!\n"); - free(pStringMem); - return NULL; + free(tempstr); + goto clean_exit; } /* directory? */ if (File_DoesFileNameEndWithSlash(tempstr)) { /* handle the ../ directory */ - if (strcmp(files[retbut-SGFSDLG_ENTRY1+ypos]->d_name, "../") == 0) + if (strcmp(files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name, "../") == 0) { /* close the zip file */ if (strcmp(tempstr, "../") == 0) @@ -509,15 +780,15 @@ char* SDLGui_FileSelect(const char *path } reloaddir = true; /* Copy the path name to the dialog */ - selection = -1; /* Remove old selection */ zipfilename[0] = '\0'; dlgfname[0] = 0; ypos = 0; + scrollbar_Ypos = 0.0; } else { /* not dir, select a file in the zip */ - selection = retbut-SGFSDLG_ENTRY1+ypos; + selection = retbut-SGFSDLG_ENTRYFIRST+ypos; strcpy(zipfilename, files[selection]->d_name); File_ShrinkName(dlgfname, zipfilename, DLGFNAME_SIZE); } @@ -526,11 +797,11 @@ char* SDLGui_FileSelect(const char *path else /* not browsingzip */ { if (!strcat_maxlen(tempstr, FILENAME_MAX, - path, files[retbut-SGFSDLG_ENTRY1+ypos]->d_name)) + path, files[retbut-SGFSDLG_ENTRYFIRST+ypos]->d_name)) { fprintf(stderr, "SDLGui_FileSelect: Path name too long!\n"); - free(pStringMem); - return NULL; + free(tempstr); + goto clean_exit; } if (File_DirExists(tempstr)) { @@ -540,9 +811,9 @@ char* SDLGui_FileSelect(const char *path File_ShrinkName(dlgpath, tempstr, DLGPATH_SIZE); strcpy(path, tempstr); reloaddir = true; - selection = -1; /* Remove old selection */ dlgfname[0] = 0; ypos = 0; + scrollbar_Ypos = 0.0; } else if (ZIP_FileNameIsZIP(tempstr) && zip_path != NULL) { @@ -550,7 +821,7 @@ char* SDLGui_FileSelect(const char *path zipfiles = ZIP_GetFiles(tempstr); if (zipfiles != NULL && browsingzip == false) { - selection = retbut-SGFSDLG_ENTRY1+ypos; + selection = retbut-SGFSDLG_ENTRYFIRST+ypos; strcpy(fname, files[selection]->d_name); File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE); browsingzip = true; @@ -558,13 +829,14 @@ char* SDLGui_FileSelect(const char *path File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE); reloaddir = true; ypos = 0; + scrollbar_Ypos = 0.0; } } else { /* Select a file */ - selection = retbut-SGFSDLG_ENTRY1+ypos; + selection = retbut-SGFSDLG_ENTRYFIRST+ypos; strcpy(fname, files[selection]->d_name); File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE); } @@ -578,7 +850,6 @@ char* SDLGui_FileSelect(const char *path switch(retbut) { case SGFSDLG_UPDIR: /* Change path to parent directory */ - if (browsingzip) { /* close the zip file? */ @@ -608,7 +879,11 @@ char* SDLGui_FileSelect(const char *path break; case SGFSDLG_HOMEDIR: /* Change to home directory */ - home = Paths_GetUserHome(); + case SGFSDLG_CWD: /* Change to current work directory */ + if (retbut == SGFSDLG_CWD) + home = Paths_GetWorkingDir(); + else + home = Paths_GetUserHome(); if (home == NULL || !*home) break; if (browsingzip) @@ -644,25 +919,30 @@ char* SDLGui_FileSelect(const char *path DlgFileSelect_ScrollDown(); SDL_Delay(10); break; + case SGFSDLG_SCROLLBAR: /* Scrollbar selected */ + DlgFileSelect_ManageScrollbar(); + SDL_Delay(10); + break; case SGFSDLG_FILENAME: /* User entered new filename */ strcpy(fname, dlgfname); break; case SGFSDLG_SHOWHIDDEN: /* Show/hide hidden files */ reloaddir = true; ypos = 0; + scrollbar_Ypos = 0.0; break; case SDLGUI_UNKNOWNEVENT: DlgFileSelect_HandleSdlEvents(&sdlEvent); break; } /* switch */ - + if (reloaddir) { /* Remove old selection */ - selection = -1; fname[0] = 0; dlgfname[0] = 0; ypos = 0; + scrollbar_Ypos = 0.0; } } /* other button code */ @@ -671,18 +951,6 @@ char* SDLGui_FileSelect(const char *path while (retbut!=SGFSDLG_OKAY && retbut!=SGFSDLG_CANCEL && retbut!=SDLGUI_QUIT && retbut != SDLGUI_ERROR && !bQuitProgram); - if (oldcursorstate == SDL_DISABLE) - SDL_ShowCursor(SDL_DISABLE); - - files_free(files); - - if (browsingzip) - { - /* free zip file entries */ - ZIP_FreeZipDir(zipfiles); - zipfiles = NULL; - } - if (retbut == SGFSDLG_OKAY) { if (zip_path) @@ -691,7 +959,19 @@ char* SDLGui_FileSelect(const char *path } else retpath = NULL; + +clean_exit: + SDL_ShowCursor(bOldMouseVisibility); + + if (browsingzip && zipfiles != NULL) + { + /* free zip file entries */ + ZIP_FreeZipDir(zipfiles); + zipfiles = NULL; + } + files_free(files); free(pStringMem); + return retpath; } @@ -700,18 +980,18 @@ char* SDLGui_FileSelect(const char *path /** * Let user browse for a file, confname is used as default. * If bAllowNew is true, user can select new files also. - * + * * If no file is selected, or there's some problem with the file, * return false and clear dlgname & confname. * Otherwise return true, set dlgname & confname to the new file name - * (dlgname is shrinked & limited to maxlen and confname is assumed + * (dlgname is shrunken & limited to maxlen and confname is assumed * to have FILENAME_MAX amount of space). */ -bool SDLGui_FileConfSelect(char *dlgname, char *confname, int maxlen, bool bAllowNew) +bool SDLGui_FileConfSelect(const char *title, char *dlgname, char *confname, int maxlen, bool bAllowNew) { char *selname; - - selname = SDLGui_FileSelect(confname, NULL, bAllowNew); + + selname = SDLGui_FileSelect(title, confname, NULL, bAllowNew); if (selname) { if (!File_DoesFileNameEndWithSlash(selname) &&