nx-hbmenu/common/menu-list.c

329 lines
8.2 KiB
C

#include "common.h"
static menu_s s_menu[2];
static menu_s s_menuFileassoc[2];
static bool s_curMenu, s_curMenuFileassoc;
menu_s* menuGetCurrent(void) {
return &s_menu[s_curMenu];
}
menu_s* menuFileassocGetCurrent(void) {
return &s_menuFileassoc[s_curMenuFileassoc];
}
menuEntry_s* menuCreateEntry(MenuEntryType type) {
menuEntry_s* me = (menuEntry_s*)malloc(sizeof(menuEntry_s));
menuEntryInit(me, type);
return me;
}
void menuDeleteEntry(menuEntry_s* me, bool skip_icongfx) {
menuEntryFree(me, skip_icongfx);
free(me);
}
static void _menuAddEntry(menu_s *m, menuEntry_s* me) {
me->menu = m;
if (m->lastEntry)
{
m->lastEntry->next = me;
m->lastEntry = me;
} else
{
m->firstEntry = me;
m->lastEntry = me;
}
m->xPos = 0;
m->slideSpeed = 0;
m->nEntries ++;
}
static void menuAddEntry(menuEntry_s* me) {
_menuAddEntry(&s_menu[!s_curMenu], me);
}
void menuFileassocAddEntry(menuEntry_s* me) {
_menuAddEntry(&s_menuFileassoc[!s_curMenuFileassoc], me);
}
static void menuAddEntryToFront(menuEntry_s* me) {
menu_s* m = &s_menu[!s_curMenu];
me->menu = m;
if (m->lastEntry)
{
me->next = m->firstEntry;
m->firstEntry = me;
} else
{
m->firstEntry = me;
m->lastEntry = me;
}
m->xPos = 0;
m->slideSpeed = 0;
m->nEntries ++;
}
static void _menuClear(menu_s* m) {
menuEntry_s *cur, *next;
for (cur = m->firstEntry; cur; cur = next)
{
next = cur->next;
menuDeleteEntry(cur, 0);
}
memset(m, 0, sizeof(*m));
}
static void menuClear(void) {
_menuClear(&s_menu[!s_curMenu]);
}
static void menuFileassocClear(void) {
_menuClear(&s_menuFileassoc[!s_curMenuFileassoc]);
}
static int menuEntryCmp(const void *p1, const void *p2) {
const menuEntry_s* lhs = *(menuEntry_s**)p1;
const menuEntry_s* rhs = *(menuEntry_s**)p2;
if(lhs->type == rhs->type)
return strcasecmp(lhs->name, rhs->name);
if(lhs->type == ENTRY_TYPE_FOLDER)
return -1;
return 1;
}
static void menuSort(void) {
int i;
menu_s* m = &s_menu[!s_curMenu];
int nEntries = m->nEntries;
if (nEntries==0) return;
int nEntriesStar = 0, nEntriesNoStar = 0;
menuEntry_s** list = (menuEntry_s**)calloc(nEntries, sizeof(menuEntry_s*));
if(list == NULL) return;
menuEntry_s** listStar = (menuEntry_s**)calloc(nEntries, sizeof(menuEntry_s*));
if(listStar == NULL) {
free(list);
return;
}
menuEntry_s* p = m->firstEntry;
for(i = 0; i < nEntries; ++i) {
if (p->starred)
listStar[nEntriesStar++] = p;
else
list[nEntriesNoStar++] = p;
p = p->next;
}
qsort(listStar, nEntriesStar, sizeof(menuEntry_s*), menuEntryCmp);
qsort(list, nEntriesNoStar, sizeof(menuEntry_s*), menuEntryCmp);
menuEntry_s** pp = &m->firstEntry;
for(i = 0; i < nEntriesStar; ++i) {
*pp = listStar[i];
pp = &(*pp)->next;
}
for(i = 0; i < nEntriesNoStar; ++i) {
*pp = list[i];
pp = &(*pp)->next;
}
m->lastEntry = list[nEntries-1];
*pp = NULL;
free(list);
free(listStar);
}
void menuReorder (void) {
s_curMenu = !s_curMenu;
menuSort();
s_curMenu = !s_curMenu;
menuClear();
}
int menuScan(const char* target) {
int pos;
char dirsep[8];
if (chdir(target) < 0) return 1;
if (getcwd(s_menu[!s_curMenu].dirname, PATH_MAX+1) == NULL)
return 1;
memset(dirsep, 0, sizeof(dirsep));
dirsep[0] = '/';
//While cwd will not have '/' at the end normally, it will have it when cwd is the root dir ("sdmc:/"). Don't add '/' to the path below when it's already present.
pos = strlen(s_menu[!s_curMenu].dirname);
if (pos > 0) {
if (s_menu[!s_curMenu].dirname[pos-1] == '/') dirsep[0] = 0;
}
DIR* dir;
struct dirent* dp;
char tmp_path[PATH_MAX+1];
dir = opendir(s_menu[!s_curMenu].dirname);
if (!dir) return 2;
while ((dp = readdir(dir)))
{
menuEntry_s* me = NULL;
bool shortcut = false;
if (dp->d_name[0]=='.')
continue;
bool entrytype=0;
memset(tmp_path, 0, sizeof(tmp_path));
snprintf(tmp_path, sizeof(tmp_path)-1, "%s%s%s", s_menu[!s_curMenu].dirname, dirsep, dp->d_name);
#ifdef _DIRENT_HAVE_D_TYPE
if (dp->d_type == DT_UNKNOWN)
continue;
entrytype = dp->d_type != DT_REG;
#else
struct stat tmpstat;
if(stat(tmp_path, &tmpstat)==-1)
continue;
entrytype = (tmpstat.st_mode & S_IFMT) != S_IFREG;
#endif
if (entrytype)
me = menuCreateEntry(ENTRY_TYPE_FOLDER);
else
{
const char* ext = getExtension(dp->d_name);
if (strcasecmp(ext, ".nro")==0/* || (shortcut = strcasecmp(ext, ".xml")==0)*/)
me = menuCreateEntry(ENTRY_TYPE_FILE);
if (!me)
me = menuCreateEntry(ENTRY_TYPE_FILE_OTHER);
}
if (!me)
continue;
strncpy(me->path, tmp_path, sizeof(me->path)-1);
me->path[sizeof(me->path)-1] = 0;
if (menuEntryLoad(me, dp->d_name, shortcut, true))
menuAddEntry(me);
else
menuDeleteEntry(me, 0);
}
closedir(dir);
menuSort();
// Swap the menu and clear the previous menu
s_curMenu = !s_curMenu;
menuClear();
return 0;
}
int themeMenuScan(const char* target) {
menuClear();
if (chdir(target) < 0) return 1;
if (getcwd(s_menu[!s_curMenu].dirname, PATH_MAX+1) == NULL)
return 1;
DIR* dir;
struct dirent* dp;
char tmp_path[PATH_MAX+1];
dir = opendir(s_menu[!s_curMenu].dirname);
if (!dir) return 2;
while ((dp = readdir(dir)))
{
menuEntry_s* me = NULL;
bool shortcut = false;
if (dp->d_name[0]=='.')
continue;
memset(tmp_path, 0, sizeof(tmp_path));
snprintf(tmp_path, sizeof(tmp_path)-1, "%s/%s", s_menu[!s_curMenu].dirname, dp->d_name);
bool entrytype=0;
#ifdef _DIRENT_HAVE_D_TYPE
if (dp->d_type == DT_UNKNOWN)
continue;
entrytype = dp->d_type != DT_REG;
#else
struct stat tmpstat;
if(stat(tmp_path, &tmpstat)==-1)
continue;
entrytype = (tmpstat.st_mode & S_IFMT) != S_IFREG;
#endif
const char* ext = getExtension(dp->d_name);
if (entrytype || strcasecmp(ext, ".cfg")==0 || strcasecmp(ext, ".romfs")==0 || strcasecmp(ext, ".zip")==0)
me = menuCreateEntry(ENTRY_TYPE_THEME);
if (!me)
continue;
strncpy(me->path, tmp_path, sizeof(me->path)-1);
me->path[sizeof(me->path)-1] = 0;
if (menuEntryLoad(me, dp->d_name, shortcut, true))
menuAddEntry(me);
else
menuDeleteEntry(me, 0);
}
closedir(dir);
menuSort();
menuEntry_s* me = menuCreateEntry(ENTRY_TYPE_THEME);
if(me) {
if(menuEntryLoad(me, textGetString(StrId_DefaultThemeName), false, false))//Create Default theme Menu Entry
menuAddEntryToFront(me);
else
menuDeleteEntry(me, 0);
}
// Swap the menu and clear the previous menu
s_curMenu = !s_curMenu;
menuClear();
return 0;
}
int menuFileassocScan(const char* target) {
menuFileassocClear();
if (chdir(target) < 0) return 1;
if (getcwd(s_menuFileassoc[!s_curMenuFileassoc].dirname, PATH_MAX+1) == NULL)
return 1;
DIR* dir;
struct dirent* dp;
char tmp_path[PATH_MAX+1];
dir = opendir(s_menuFileassoc[!s_curMenuFileassoc].dirname);
if (!dir) return 2;
while ((dp = readdir(dir)))
{
if (dp->d_name[0]=='.')
continue;
memset(tmp_path, 0, sizeof(tmp_path));
snprintf(tmp_path, sizeof(tmp_path)-1, "%s/%s", s_menuFileassoc[!s_curMenuFileassoc].dirname, dp->d_name);
const char* ext = getExtension(dp->d_name);
if (strcasecmp(ext, ".cfg")!=0)
continue;
menuEntryFileassocLoad(tmp_path);
}
closedir(dir);
// Swap the menu and clear the previous menu
s_curMenuFileassoc = !s_curMenuFileassoc;
menuFileassocClear();
return 0;
}