284 lines
6.3 KiB
C++
284 lines
6.3 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
#include <limits.h>
|
|
#include <ctype.h>
|
|
|
|
#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, "cores_recent.cfg");
|
|
if (idx >= 0) 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];
|
|
if(strlen(dir)) snprintf(path, sizeof(path), "%s/%s", dir, name);
|
|
else snprintf(path, sizeof(path), "%s", 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 (idx >= 0 && 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 || (mode == SCANF_PREV && iSelectedEntry <= 0))
|
|
{
|
|
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
|
|
{
|
|
// jump to first visible item
|
|
iFirstEntry = 0;
|
|
iSelectedEntry = 0;
|
|
}
|
|
}
|
|
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, recent_path(recents[iSelectedEntry].dir, 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));
|
|
}
|