From 605580358db61796b58d6ada4501487fd1de6a68 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sat, 29 Apr 2017 16:40:07 +0100 Subject: [PATCH] Addfile menu! Basic as fuck UI, and the controls for manipulating it suck, but the basic elements of the feature set I'm looking for have been implemented in some form or another. More at a later time. MI, be glad I didn't do this in deeznux ;P --- src/filesrch.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++--- src/filesrch.h | 10 +++ src/m_menu.c | 150 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 319 insertions(+), 13 deletions(-) diff --git a/src/filesrch.c b/src/filesrch.c index acc176d6a..b90123d4b 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -31,6 +31,7 @@ #include "filesrch.h" #include "d_netfil.h" #include "m_misc.h" +#include "z_zone.h" #if (defined (_WIN32) && !defined (_WIN32_WCE)) && defined (_MSC_VER) && !defined (_XBOX) @@ -39,7 +40,7 @@ #include #define SUFFIX "*" -#define SLASH "\\" +#define SLASH PATHSEP #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #ifndef INVALID_FILE_ATTRIBUTES @@ -285,6 +286,15 @@ closedir (DIR * dirp) return rc; } #endif + +char menupath[1024]; +size_t menupathindex[20]; +size_t menudepthleft = 20; + +char **dirmenu; +size_t sizedirmenu; +size_t dir_on; + #if defined (_XBOX) && defined (_MSC_VER) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) @@ -296,6 +306,12 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want completepath = false; return FS_NOTFOUND; } + +boolean preparefilemenu(void) +{ + return false; +} + #elif defined (_WIN32_WCE) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) @@ -346,6 +362,11 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want #endif return FS_NOTFOUND; } + +boolean preparefilemenu(void) +{ + return false; +} #else filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) { @@ -387,25 +408,29 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want { searchpath[searchpathindex[depthleft]]=0; dent = readdir(dirhandle[depthleft]); - if (dent) - strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); if (!dent) + { closedir(dirhandle[depthleft++]); - else if (dent->d_name[0]=='.' && + continue; + } + + if (dent->d_name[0]=='.' && (dent->d_name[1]=='\0' || (dent->d_name[1]=='.' && dent->d_name[2]=='\0'))) { // we don't want to scan uptree + continue; } - else if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat - { - // was the file (re)moved? can't stat it - } + + // okay, now we actually want searchpath to incorporate d_name + strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); + + if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it else if (S_ISDIR(fsstat.st_mode) && depthleft) { - strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); searchpathindex[--depthleft] = strlen(searchpath) + 1; dirhandle[depthleft] = opendir(searchpath); if (!dirhandle[depthleft]) @@ -444,6 +469,135 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want free(searchname); free(searchpathindex); free(dirhandle); + return retval; } + +#define MAXEXT 5 +char ext[MAXEXT][5] = { + ".txt", ".cfg", // exec + ".wad", ".soc", ".lua"}; // addfile + +boolean preparefilemenu(void) +{ + DIR *dirhandle; + struct dirent *dent; + struct stat fsstat; + size_t pos, folderpos = 0, numfolders = 0; + + for (pos = 0; pos < sizedirmenu; pos++) + { + Z_Free(dirmenu[pos]); + dirmenu[pos] = NULL; + } + + sizedirmenu = dir_on = pos = 0; + + dirhandle = opendir(menupath); + + if (dirhandle == NULL) + return false; + + while (true) + { + menupath[menupathindex[menudepthleft]] = 0; + dent = readdir(dirhandle); + + if (!dent) + break; + else if (dent->d_name[0]=='.' && + (dent->d_name[1]=='\0' || + (dent->d_name[1]=='.' && + dent->d_name[2]=='\0'))) + continue; // we don't want to scan uptree + + strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); + + if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it + else // is a file or directory + { + if (!S_ISDIR(fsstat.st_mode)) + { + size_t len = strlen(dent->d_name)+1; + UINT8 i; + for (i = 0; i < MAXEXT; i++) + if (!strcasecmp(ext[i], dent->d_name+len-5)) break; + if (i == MAXEXT) continue; // not an addfile-able (or exec-able) file + } + else + numfolders++; + sizedirmenu++; + } + } + + closedir(dirhandle); // I don't know how to go back to the start of the folder without just opening and closing... if there's a way, it doesn't appear to be easily manipulatable + + if (!sizedirmenu) + return false; + + if (!(dirmenu = Z_Realloc(dirmenu, sizedirmenu*sizeof(char *), PU_STATIC, NULL))) + I_Error("Ran out of memory whilst preparing add-ons menu"); + + dirhandle = opendir(menupath); + + while ((pos+folderpos) < sizedirmenu) + { + menupath[menupathindex[menudepthleft]] = 0; + dent = readdir(dirhandle); + + if (!dent) + break; + else if (dent->d_name[0]=='.' && + (dent->d_name[1]=='\0' || + (dent->d_name[1]=='.' && + dent->d_name[2]=='\0'))) + continue; // we don't want to scan uptree + + strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); + + if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it + else // is a file or directory + { + char *temp; + size_t len = strlen(dent->d_name)+1; + UINT8 i = 0; + size_t folder; + + if (!S_ISDIR(fsstat.st_mode)) // file + { + for (; i < MAXEXT; i++) + if (!strcasecmp(ext[i], dent->d_name+len-5)) break; + if (i == MAXEXT) continue; // not an addfile-able (or exec-able) file + i++; // i goes up so zero-index is directory instead of .txt + folder = 0; + } + else + len += (folder = 1); + + if (len > 255) + len = 255; + + if (!(temp = Z_Malloc((len+2+folder) * sizeof (char), PU_STATIC, NULL))) + I_Error("Ran out of memory whilst preparing add-ons menu"); + temp[0] = i; + temp[1] = (UINT8)(len); + strlcpy(temp+2, dent->d_name, len); + if (folder) + { + strcpy(temp+len, "/"); + dirmenu[folderpos++] = temp; + } + else + dirmenu[numfolders + pos++] = temp; + } + } + + menupath[menupathindex[menudepthleft]] = 0; + sizedirmenu = (pos+folderpos); // crash prevention if things change between openings somehow + + closedir(dirhandle); + return true; +} #endif diff --git a/src/filesrch.h b/src/filesrch.h index 33b148d4b..c6d161597 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -25,4 +25,14 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth); +extern char menupath[1024]; +extern size_t menupathindex[20]; +extern size_t menudepthleft; + +extern char **dirmenu; +extern size_t sizedirmenu; +extern size_t dir_on; + +boolean preparefilemenu(void); + #endif // __FILESRCH_H__ diff --git a/src/m_menu.c b/src/m_menu.c index fb8aeedad..a3ee63ecb 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -33,6 +33,9 @@ #include "s_sound.h" #include "i_system.h" +// Addfile +#include "filesrch.h" + #include "v_video.h" #include "i_video.h" #include "keys.h" @@ -330,10 +333,12 @@ menu_t OP_NetgameOptionsDef, OP_GametypeOptionsDef; menu_t OP_MonitorToggleDef; static void M_ScreenshotOptions(INT32 choice); static void M_EraseData(INT32 choice); +static void M_Addons(INT32 choice); // Drawing functions static void M_DrawGenericMenu(void); static void M_DrawCenteredMenu(void); +static void M_DrawAddons(void); static void M_DrawSkyRoom(void); static void M_DrawChecklist(void); static void M_DrawEmblemHints(void); @@ -369,6 +374,7 @@ static boolean M_CancelConnect(void); #endif static boolean M_ExitPandorasBox(void); static boolean M_QuitMultiPlayerMenu(void); +static void M_HandleAddons(INT32 choice); static void M_HandleLevelPlatter(INT32 choice); static void M_HandleSoundTest(INT32 choice); static void M_HandleImageDef(INT32 choice); @@ -476,10 +482,11 @@ static consvar_t cv_dummymares = {"dummymares", "Overall", CV_HIDEN|CV_CALL, dum // --------- static menuitem_t MainMenu[] = { - {IT_CALL |IT_STRING, NULL, "Secrets", M_SecretsMenu, 84}, - {IT_CALL |IT_STRING, NULL, "1 player", M_SinglePlayerMenu, 92}, - {IT_SUBMENU|IT_STRING, NULL, "multiplayer", &MP_MainDef, 100}, - {IT_CALL |IT_STRING, NULL, "options", M_Options, 108}, + {IT_CALL |IT_STRING, NULL, "Secrets", M_SecretsMenu, 76}, + {IT_CALL |IT_STRING, NULL, "1 player", M_SinglePlayerMenu, 84}, + {IT_SUBMENU|IT_STRING, NULL, "multiplayer", &MP_MainDef, 92}, + {IT_CALL |IT_STRING, NULL, "options", M_Options, 100}, + {IT_CALL |IT_STRING, NULL, "addons", M_Addons, 108}, {IT_CALL |IT_STRING, NULL, "quit game", M_QuitSRB2, 116}, }; @@ -489,9 +496,15 @@ typedef enum singleplr, multiplr, options, + addons, quitdoom } main_e; +static menuitem_t MISC_AddonsMenu[] = +{ + {IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleAddons, 0}, // dummy menuitem for the control func +}; + // --------------------------------- // Pause Menu Mode Attacking Edition // --------------------------------- @@ -1432,6 +1445,18 @@ static menuitem_t OP_MonitorToggleMenu[] = // Main Menu and related menu_t MainDef = CENTERMENUSTYLE(NULL, MainMenu, NULL, 72); +menu_t MISC_AddonsDef = +{ + NULL, + sizeof (MISC_AddonsMenu)/sizeof (menuitem_t), + &MainDef, + MISC_AddonsMenu, + M_DrawAddons, + 0, 0, + 0, + NULL +}; + menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); @@ -4414,6 +4439,123 @@ static void M_HandleImageDef(INT32 choice) // MISC MAIN MENU OPTIONS // ====================== +static void M_Addons(INT32 choice) +{ + (void)choice; + + strlcpy(menupath, srb2home, 1024); + menupathindex[(menudepthleft = 19)] = strlen(menupath) + 1; + + if (menupath[menupathindex[menudepthleft]-2] != '/') + { + menupath[menupathindex[menudepthleft]-1] = '/'; + menupath[menupathindex[menudepthleft]] = 0; + } + else + --menupathindex[menudepthleft]; + + if (!preparefilemenu()) + { + M_StartMessage(M_GetText("No files/folders found.\n\n(Press a key)\n"),NULL,MM_NOTHING); + return; + } + + MISC_AddonsDef.prevMenu = currentMenu; + M_SetupNextMenu(&MISC_AddonsDef); +} + +static void M_DrawAddons(void) +{ + INT32 x, y; + size_t i; + + // DRAW MENU + x = currentMenu->x; + y = currentMenu->y; + + V_DrawString(x, y, 0, menupath); + y += 2*SMALLLINEHEIGHT; + + for (i = dir_on; i < sizedirmenu; i++) + { + if (y > BASEVIDHEIGHT) break; + V_DrawString(x, y, 0, dirmenu[i]+2); + y += SMALLLINEHEIGHT; + } +} + +static void M_HandleAddons(INT32 choice) +{ + boolean exitmenu = false; // exit to previous menu + + switch (choice) + { + case KEY_DOWNARROW: + if (dir_on < sizedirmenu-1) + dir_on++; + S_StartSound(NULL, sfx_menu1); + break; + case KEY_UPARROW: + if (dir_on) + dir_on--; + S_StartSound(NULL, sfx_menu1); + break; + case KEY_ENTER: + if (dirmenu[dir_on][0] == 0) // folder + { + S_StartSound(NULL, sfx_strpst); + strcpy(&menupath[menupathindex[menudepthleft--]],dirmenu[dir_on]+2); + menupathindex[menudepthleft] = strlen(menupath); + menupath[menupathindex[menudepthleft]] = 0; + + if (!preparefilemenu()) + { + M_StartMessage(M_GetText("Folder is empty.\n\n(Press a key)\n"),NULL,MM_NOTHING); + menupath[menupathindex[++menudepthleft]] = 0; + if (!preparefilemenu()) + { + M_StartMessage(M_GetText("Folder no longer exists!\n\n(Press a key)\n"),NULL,MM_NOTHING); + M_SetupNextMenu(MISC_AddonsDef.prevMenu); + return; + } + } + } + else if (dirmenu[dir_on][0] >= 3) // wad/soc/lua + { + S_StartSound(NULL, sfx_strpst); + COM_BufAddText(va("addfile %s%s", menupath, dirmenu[dir_on]+2)); + } + else + S_StartSound(NULL, sfx_lose); + break; + case KEY_BACKSPACE: + if (menudepthleft < 19) + { + menupath[menupathindex[++menudepthleft]] = 0; + if (!preparefilemenu()) + { + M_StartMessage(M_GetText("Folder no longer exists!\n\n(Press a key)\n"),NULL,MM_NOTHING); + M_SetupNextMenu(MISC_AddonsDef.prevMenu); + return; + } + break; + } + case KEY_ESCAPE: + exitmenu = true; + break; + + default: + break; + } + if (exitmenu) + { + if (currentMenu->prevMenu) + M_SetupNextMenu(currentMenu->prevMenu); + else + M_ClearMenus(true); + } +} + static void M_PandorasBox(INT32 choice) { (void)choice;