#include #include #include #include #include #include #include #include "file_io.h" #include "user_io.h" #include "osd.h" #include "cfg.h" #include "recent.h" #define RECENT_MAX 16 struct recent_rec_t { char dir[1024]; char name[256]; char label[256]; }; static recent_rec_t recents[RECENT_MAX]; static char ena[RECENT_MAX]; static int numlast = 0; static int iSelectedEntry = 0; static int iFirstEntry = 0; static int recent_available() { return numlast; } static char* recent_create_config_name(int idx) { static char str[256]; sprintf(str, "%s_recent_%d.cfg", user_io_get_core_name(), idx); return str; } static const char* recent_path(char* dir, char* name) { static char path[1024]; snprintf(path, sizeof(path), "%s/%s", dir, name); return path; } static void recent_load(int idx) { // initialize recent to empty strings memset(recents, 0, sizeof(recents)); // load the config file into memory FileLoadConfig(recent_create_config_name(idx), recents, sizeof(recents)); for (numlast = 0; numlast < (int)(sizeof(recents)/sizeof(recents[0])) && strlen(recents[numlast].name); numlast++) {} // check the items for (int i = 0; i < recent_available(); i++) { ena[i] = FileExists(recent_path(recents[i].dir, recents[i].name)); if (is_neogeo_core() && !ena[i]) ena[i] = PathIsDir(recent_path(recents[i].dir, recents[i].name)); } } int recent_init(int idx) { if (!cfg.recents) return 0; recent_load(idx); recent_scan(SCANF_INIT); return recent_available(); } void recent_scan(int mode) { if (mode == SCANF_INIT) { iFirstEntry = 0; iSelectedEntry = 0; } else { if (!recent_available()) return; if (mode == SCANF_END) { iSelectedEntry = recent_available() - 1; iFirstEntry = iSelectedEntry - OsdGetSize() + 1; if (iFirstEntry < 0) iFirstEntry = 0; } else if (mode == SCANF_NEXT) { if (iSelectedEntry + 1 < recent_available()) // scroll within visible items { iSelectedEntry++; if (iSelectedEntry > iFirstEntry + OsdGetSize() - 1) iFirstEntry = iSelectedEntry - OsdGetSize() + 1; } } else if (mode == SCANF_PREV) { if (iSelectedEntry > 0) // scroll within visible items { iSelectedEntry--; if (iSelectedEntry < iFirstEntry) iFirstEntry = iSelectedEntry; } } else if (mode == SCANF_NEXT_PAGE) { if (iSelectedEntry < iFirstEntry + OsdGetSize() - 1) { iSelectedEntry = iFirstEntry + OsdGetSize() - 1; if (iSelectedEntry >= recent_available()) iSelectedEntry = recent_available() - 1; } else { iSelectedEntry += OsdGetSize(); iFirstEntry += OsdGetSize(); if (iSelectedEntry >= recent_available()) { iSelectedEntry = recent_available() - 1; iFirstEntry = iSelectedEntry - OsdGetSize() + 1; if (iFirstEntry < 0) iFirstEntry = 0; } else if (iFirstEntry + OsdGetSize() > recent_available()) { iFirstEntry = recent_available() - OsdGetSize(); } } } else if (mode == SCANF_PREV_PAGE) { if (iSelectedEntry != iFirstEntry) { iSelectedEntry = iFirstEntry; } else { iFirstEntry -= OsdGetSize(); if (iFirstEntry < 0) iFirstEntry = 0; iSelectedEntry = iFirstEntry; } } } } void recent_scroll_name() { // this function is called periodically when file selection window is displayed // it checks if predefined period of time has elapsed and scrolls the name if necessary int len; int max_len; static char name[256 + 4]; // don't scroll if the file doesn't exist if (!ena[iSelectedEntry]) return; name[0] = 32; strcpy(name + 1, recents[iSelectedEntry].label); len = strlen(name); // get name length max_len = 30; ScrollText(iSelectedEntry - iFirstEntry, name, 1, len, max_len, 1); } void recent_print() { int k; int len; static char s[256+4]; ScrollReset(); for (int i = 0; i < OsdGetSize(); i++) { char leftchar = 0; unsigned char d = 1; if (i < recent_available()) { k = iFirstEntry + i; s[0] = 32; char* name = recents[k].label; strcpy(s + 1, name); len = strlen(s); // get name length s[len] = 0; if (len > 28) { len = 27; // trim display length if longer than 30 characters s[28] = 22; } s[29] = 0; if (!i && k) leftchar = 17; if ((i == OsdGetSize() - 1) && (k < recent_available() - 1)) leftchar = 16; d = ena[k] ? 0 : 1; } else { memset(s, ' ', 32); } OsdWriteOffset(i, s, i == (iSelectedEntry - iFirstEntry) && recent_available(), d, 0, leftchar); } } int recent_select(char *dir, char *path, char *label) { // copy directory and file name over dir[0] = 0; path[0] = 0; if (!recent_available()) return 0; if (strlen(recents[iSelectedEntry].name)) { strcpy(dir, recents[iSelectedEntry].dir); strcpy(path, dir); strcat(path, "/"); strcat(path, recents[iSelectedEntry].name); strcpy(label, recents[iSelectedEntry].label); } return ena[iSelectedEntry]; } void recent_update(char* dir, char* path, char* label, int idx) { if (!cfg.recents || !strlen(path)) return; // separate the path into directory and filename char* name = strrchr(path, '/'); if (name) name++; else name = path; // load the current state. this is necessary because we may have started a ROM from multiple sources recent_load(idx); // update the selection int indexToErase = RECENT_MAX - 1; recent_rec_t rec = {}; strncpy(rec.dir, dir, sizeof(rec.dir)); strncpy(rec.name, name, sizeof(rec.name)); strncpy(rec.label, label ? label : name, sizeof(rec.label)); for (unsigned i = 0; i < sizeof(recents)/sizeof(recents[0]); i++) { if (!strcmp(recents[i].dir, dir) && !strcmp(recents[i].name, name)) { indexToErase = i; break; } } if(indexToErase) memmove(recents + 1, recents, sizeof(recents[0])*indexToErase); memcpy(recents, &rec, sizeof(recents[0])); // store the config file to storage FileSaveConfig(recent_create_config_name(idx), recents, sizeof(recents)); } void recent_clear(int idx) { memset(recents, 0, sizeof(recents)); // store the config file to storage FileSaveConfig(recent_create_config_name(idx), recents, sizeof(recents)); }