/* Hatari - dlgFileSelect.c 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__; #include #include #include #include "main.h" #include "scandir.h" #include "sdlgui.h" #include "file.h" #include "paths.h" #include "zip.h" #include "gui-retro.h" #ifdef VITA #include "retro_files.h" #endif #define SGFS_NUMENTRIES 16 /* How many entries are displayed at once */ #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 SCROLLOUT_ABOVE 1 #define SCROLLOUT_UNDER 2 #define DLGPATH_SIZE 62 static char dlgpath[DLGPATH_SIZE+1]; /* Path name in the dialog */ #define DLGFNAME_SIZE 56 static char dlgfname[DLGFNAME_SIZE+1]; /* Name of the selected file in the dialog */ #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 */ /* 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,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, SG_EXIT/*0*/, 0, 45,1, 4,1, ".." }, { SGBUTTON, SG_EXIT/*0*/, 0, 50,1, 5,1, "CWD" }, { SGBUTTON, SG_EXIT/*0*/, 0, 56,1, 3,1, "~" }, { SGBUTTON, SG_EXIT/*0*/, 0, 60,1, 3,1, "/" }, { 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] }, { SGTEXT, SG_EXIT, 0, 2,7, DLGFILENAMES_SIZE,1, dlgfilenames[1] }, { SGTEXT, SG_EXIT, 0, 2,8, DLGFILENAMES_SIZE,1, dlgfilenames[2] }, { SGTEXT, SG_EXIT, 0, 2,9, DLGFILENAMES_SIZE,1, dlgfilenames[3] }, { SGTEXT, SG_EXIT, 0, 2,10, DLGFILENAMES_SIZE,1, dlgfilenames[4] }, { SGTEXT, SG_EXIT, 0, 2,11, DLGFILENAMES_SIZE,1, dlgfilenames[5] }, { SGTEXT, SG_EXIT, 0, 2,12, DLGFILENAMES_SIZE,1, dlgfilenames[6] }, { SGTEXT, SG_EXIT, 0, 2,13, DLGFILENAMES_SIZE,1, dlgfilenames[7] }, { SGTEXT, SG_EXIT, 0, 2,14, DLGFILENAMES_SIZE,1, dlgfilenames[8] }, { SGTEXT, SG_EXIT, 0, 2,15, DLGFILENAMES_SIZE,1, dlgfilenames[9] }, { SGTEXT, SG_EXIT, 0, 2,16, DLGFILENAMES_SIZE,1, dlgfilenames[10] }, { SGTEXT, SG_EXIT, 0, 2,17, DLGFILENAMES_SIZE,1, dlgfilenames[11] }, { SGTEXT, SG_EXIT, 0, 2,18, DLGFILENAMES_SIZE,1, dlgfilenames[12] }, { 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] }, { SGSCROLLBAR, SG_TOUCHEXIT, 0, 62, 7, 0, 0, NULL }, /* Scrollbar */ { SGBUTTON, SG_TOUCHEXIT, 0, 62, 6,1,1, SGARROWUP/*"\x01"*/ }, /* Arrow up */ { SGBUTTON, SG_TOUCHEXIT, 0, 62,21,1,1, SGARROWDOWN/*"\x02"*/ }, /* Arrow down */ { SGCHECKBOX, SG_EXIT, 0, 2,23, 18,1, "Show hidden files" }, { SGBUTTON, SG_EXIT/*SG_DEFAULT*/, 0, 32,23, 8,1, "Okay" }, { SGBUTTON, SG_EXIT/*SG_CANCEL*/, 0, 50,23, 8,1, "Cancel" }, { -1, 0, 0, 0,0, 0,0, NULL } }; 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 */ /* Convert file position (in file list) to scrollbar y position */ static void DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(void); /*-----------------------------------------------------------------------*/ /** * Update the file name strings in the dialog. * Returns false if it failed, true on success. */ static int DlgFileSelect_RefreshEntries(struct dirent **files, char *path, bool browsingzip) { int i; char *tempstr = malloc(FILENAME_MAX); if (!tempstr) { perror("DlgFileSelect_RefreshEntries"); return false; } /* Copy entries to dialog: */ for (i=0; id_name); File_ShrinkName(dlgfilenames[i], tempstr, DLGFILENAMES_SIZE); /* Mark folders: */ strcpy(tempstr, path); strcat(tempstr, files[i+ypos]->d_name); if (browsingzip) { if (File_DoesFileNameEndWithSlash(tempstr)) dlgfilenames[i][0] = SGFOLDER; /* Mark folders */ } else { if( stat(tempstr, &filestat)==0 && S_ISDIR(filestat.st_mode) ) dlgfilenames[i][0] = SGFOLDER; /* Mark folders */ if (ZIP_FileNameIsZIP(tempstr) && browsingzip == false) dlgfilenames[i][0] = SGFOLDER; /* Mark .ZIP archives as folders */ } } else dlgfilenames[i][0] = 0; /* Clear entry */ } free(tempstr); return true; } /*-----------------------------------------------------------------------*/ /** * Remove all hidden files (files with file names that begin with a dot) from * the list. */ static void DlgFileSelect_RemoveHiddenFiles(struct dirent **files) { int i; int nActPos = -1; int nOldEntries; nOldEntries = entries; /* Scan list for hidden files and remove them. */ for (i = 0; i < nOldEntries; i++) { /* Does file name start with a dot? -> hidden file! */ if (files[i]->d_name[0] == '.') { if (nActPos == -1) nActPos = i; /* Remove file from list: */ free(files[i]); files[i] = NULL; entries -= 1; } } /* Now close the gaps in the list: */ if (nActPos != -1) { for (i = nActPos; i < nOldEntries; i++) { if (files[i] != NULL) { /* Move entry to earlier position: */ files[nActPos] = files[i]; files[i] = NULL; nActPos += 1; } } } } /*-----------------------------------------------------------------------*/ /** * Prepare to scroll up one entry. */ static void DlgFileSelect_ScrollUp(void) { if (ypos > 0) { --ypos; DlgFileSelect_Convert_ypos_to_scrollbar_Ypos(); refreshentries = true; } } /*-----------------------------------------------------------------------*/ /** * Prepare to scroll down one entry. */ static void DlgFileSelect_ScrollDown(void) { 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; b = 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; } /*-----------------------------------------------------------------------*/ /** * Handle SDL events. */ static void DlgFileSelect_HandleSdlEvents(SDL_Event *pEvent) { int oldypos = ypos; //RETRO TODO FIX #if 0 switch (pEvent->type) { case SDL_MOUSEBUTTONDOWN: if (pEvent->button.button == SDL_BUTTON_WHEELUP) DlgFileSelect_ScrollUp(); else if (pEvent->button.button == SDL_BUTTON_WHEELDOWN) DlgFileSelect_ScrollDown(); break; 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; 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; } break; default: break; } #endif if (ypos < 0) { ypos = 0; scrollbar_Ypos = 0.0; } if (ypos != oldypos) refreshentries = true; } /*-----------------------------------------------------------------------*/ /** * Free file entries */ static struct dirent **files_free(struct dirent **files) { int i; if (files != NULL) { for(i=0; i