Updated the menu_demo code. The list is now sorted. Miscellaneous paths from pk3 files are not shown any more either.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2906 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
28351eb001
commit
20cc7dc9f5
1 changed files with 218 additions and 71 deletions
|
@ -245,105 +245,154 @@ void M_Menu_SinglePlayer_f (void)
|
|||
}
|
||||
|
||||
|
||||
typedef struct demoitem_s {
|
||||
char name[64];
|
||||
qboolean isdir;
|
||||
int size;
|
||||
struct demoitem_s *next;
|
||||
struct demoitem_s *prev;
|
||||
} demoitem_t;
|
||||
|
||||
typedef struct {
|
||||
menucustom_t *list;
|
||||
int nummatches;
|
||||
int selected;
|
||||
int firstshown;
|
||||
int maxmatches;
|
||||
demoitem_t *selected;
|
||||
demoitem_t *firstitem;
|
||||
int pathlen;
|
||||
|
||||
char *command[64]; //these let the menu be used for nearly any sort of file browser.
|
||||
char *ext[64];
|
||||
int numext;
|
||||
|
||||
struct demofilelist_s{
|
||||
char name[64];
|
||||
int size;
|
||||
} *options;
|
||||
demoitem_t *items;
|
||||
} demomenu_t;
|
||||
|
||||
void M_DemoDraw(int x, int y, menucustom_t *control, menu_t *menu)
|
||||
static void M_DemoDraw(int x, int y, menucustom_t *control, menu_t *menu)
|
||||
{
|
||||
char *text;
|
||||
int i;
|
||||
demomenu_t *info = menu->data;
|
||||
demoitem_t *item, *lostit;
|
||||
int ty;
|
||||
|
||||
if (info->firstshown > info->selected)
|
||||
info->firstshown = info->selected;
|
||||
if ((vid.height - y)/8 < info->selected - info->firstshown+2)
|
||||
info->firstshown = info->selected - (vid.height - y)/8+2;
|
||||
|
||||
i = info->firstshown;
|
||||
while(i < info->nummatches)
|
||||
ty = vid.height-24;
|
||||
item = info->selected;
|
||||
while(item)
|
||||
{
|
||||
if (info->options[i].size)
|
||||
text = va("%-30s %6iKB", info->options[i].name+info->pathlen, info->options[i].size/1024);
|
||||
if (info->firstitem == item)
|
||||
break;
|
||||
if (ty < y)
|
||||
{
|
||||
//we couldn't find it
|
||||
for (lostit = info->firstitem; lostit; lostit = lostit->prev)
|
||||
{
|
||||
if (info->selected == lostit)
|
||||
{
|
||||
item = lostit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
info->firstitem = item;
|
||||
break;
|
||||
}
|
||||
item = item->prev;
|
||||
ty-=8;
|
||||
}
|
||||
if (!item)
|
||||
info->firstitem = info->items;
|
||||
|
||||
|
||||
item = info->firstitem;
|
||||
while(item)
|
||||
{
|
||||
if (y+8 >= vid.height)
|
||||
return;
|
||||
if (!item->isdir)
|
||||
text = va("%-32.32s%6iKB", item->name+info->pathlen, item->size/1024);
|
||||
else
|
||||
text = info->options[i].name+info->pathlen;
|
||||
if (i == info->selected)
|
||||
Draw_Alt_String(x+8, y+8, text);
|
||||
text = item->name+info->pathlen;
|
||||
if (item == info->selected)
|
||||
Draw_Alt_String(x, y+8, text);
|
||||
else
|
||||
Draw_String(x+8, y+8, text);
|
||||
Draw_String(x, y+8, text);
|
||||
y+=8;
|
||||
i++;
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
void ShowDemoMenu (menu_t *menu, char *path);
|
||||
qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key)
|
||||
static void ShowDemoMenu (menu_t *menu, char *path);
|
||||
static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key)
|
||||
{
|
||||
demomenu_t *info = menu->data;
|
||||
if (!info->nummatches)
|
||||
return false;
|
||||
int i;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case K_MWHEELUP:
|
||||
case K_UPARROW:
|
||||
info->selected--;
|
||||
if (info->selected < 0)
|
||||
info->selected = 0;
|
||||
if (info->selected && info->selected->prev)
|
||||
info->selected = info->selected->prev;
|
||||
return true;
|
||||
case K_MWHEELDOWN:
|
||||
case K_DOWNARROW:
|
||||
info->selected++;
|
||||
if (info->selected > info->nummatches-1)
|
||||
info->selected = info->nummatches-1;
|
||||
if (info->selected && info->selected->next)
|
||||
info->selected = info->selected->next;
|
||||
return true;
|
||||
case K_HOME:
|
||||
info->selected = info->items;
|
||||
return true;
|
||||
case K_END:
|
||||
info->selected = info->items;
|
||||
while(info->selected->next)
|
||||
info->selected = info->selected->next;
|
||||
return true;
|
||||
case K_PGUP:
|
||||
info->selected-=10;
|
||||
if (info->selected < 0)
|
||||
info->selected = 0;
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
if (info->selected && info->selected->prev)
|
||||
info->selected = info->selected->prev;
|
||||
}
|
||||
return true;
|
||||
case K_PGDN:
|
||||
info->selected+=10;
|
||||
if (info->selected > info->nummatches-1)
|
||||
info->selected = info->nummatches-1;
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
if (info->selected && info->selected->next)
|
||||
info->selected = info->selected->next;
|
||||
}
|
||||
return true;
|
||||
case K_ENTER:
|
||||
if (info->options[info->selected].name[strlen(info->options[info->selected].name)-1] == '/') //last char is a slash
|
||||
ShowDemoMenu(menu, va("%s", info->options[info->selected].name));
|
||||
else
|
||||
if (info->selected)
|
||||
{
|
||||
int extnum;
|
||||
for (extnum = 0; extnum < info->numext; extnum++)
|
||||
if (!stricmp(info->options[info->selected].name + strlen(info->options[info->selected].name)-4, info->ext[extnum]))
|
||||
break;
|
||||
if (info->selected->isdir)
|
||||
ShowDemoMenu(menu, va("%s", info->selected->name));
|
||||
else
|
||||
{
|
||||
int extnum;
|
||||
for (extnum = 0; extnum < info->numext; extnum++)
|
||||
if (!stricmp(info->selected->name + strlen(info->selected->name)-4, info->ext[extnum]))
|
||||
break;
|
||||
|
||||
if (extnum == info->numext) //wasn't on our list of extensions.
|
||||
extnum = 0;
|
||||
if (extnum == info->numext) //wasn't on our list of extensions.
|
||||
extnum = 0;
|
||||
|
||||
Cbuf_AddText(va("%s \"%s\"\n", info->command[extnum], info->options[info->selected].name), RESTRICT_LOCAL);
|
||||
Cbuf_AddText(va("%s \"%s\"\n", info->command[extnum], info->selected->name), RESTRICT_LOCAL);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int DemoAddItem(char *filename, int size, void *parm)
|
||||
static int DemoAddItem(char *filename, int size, void *parm)
|
||||
{
|
||||
int match;
|
||||
int extnum;
|
||||
demomenu_t *menu = parm;
|
||||
if (filename[strlen(filename)-1] != '/')
|
||||
demoitem_t *link, *newi;
|
||||
int side;
|
||||
qboolean isdir;
|
||||
char tempfname[MAX_PATH];
|
||||
|
||||
char *i;
|
||||
|
||||
i = strchr(filename+menu->pathlen, '/');
|
||||
if (i == NULL)
|
||||
{
|
||||
for (extnum = 0; extnum < menu->numext; extnum++)
|
||||
if (!stricmp(filename + strlen(filename)-4, menu->ext[extnum]))
|
||||
|
@ -351,34 +400,132 @@ int DemoAddItem(char *filename, int size, void *parm)
|
|||
|
||||
if (extnum == menu->numext) //wasn't on our list of extensions.
|
||||
return true;
|
||||
isdir = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//directory
|
||||
i++;
|
||||
if (i-filename > sizeof(tempfname)-2)
|
||||
return true; //too long to fit in our buffers anyway
|
||||
strncpy(tempfname, filename, i-filename);
|
||||
tempfname[i-filename] = 0;
|
||||
filename = tempfname;
|
||||
|
||||
size = 0;
|
||||
isdir = true;
|
||||
}
|
||||
if (menu->maxmatches < menu->nummatches+10)
|
||||
|
||||
if (!menu->items)
|
||||
menu->items = newi = BZ_Malloc(sizeof(*newi));
|
||||
else
|
||||
{
|
||||
menu->maxmatches = menu->nummatches+10;
|
||||
menu->options = BZ_Realloc(menu->options, menu->maxmatches*sizeof(struct demofilelist_s));
|
||||
link = menu->items;
|
||||
for(;;)
|
||||
{
|
||||
if (link->isdir != isdir) //bias directories, so they sink
|
||||
side = (link->isdir > isdir)?1:-1;
|
||||
else
|
||||
side = stricmp(link->name, filename);
|
||||
if (side == 0)
|
||||
return true; //already got this file
|
||||
else if (side > 0)
|
||||
{
|
||||
if (!link->prev)
|
||||
{
|
||||
link->prev = newi = BZ_Malloc(sizeof(*newi));
|
||||
break;
|
||||
}
|
||||
link = link->prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!link->next)
|
||||
{
|
||||
link->next = newi = BZ_Malloc(sizeof(*newi));
|
||||
break;
|
||||
}
|
||||
link = link->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (match = 0; match < menu->nummatches; match++)
|
||||
if (!strcmp(menu->options[match].name, filename))
|
||||
return true; //already got that one
|
||||
Q_strncpyz(menu->options[menu->nummatches].name, filename, sizeof(menu->options[menu->nummatches].name));
|
||||
menu->options[menu->nummatches].size = size;
|
||||
menu->nummatches++;
|
||||
|
||||
Q_strncpyz(newi->name, filename, sizeof(newi->name));
|
||||
newi->size = size;
|
||||
newi->isdir = isdir;
|
||||
newi->prev = NULL;
|
||||
newi->next = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void M_Demo_Remove (menu_t *menu)
|
||||
//converts the binary tree into sorted linked list
|
||||
static void M_Demo_Flatten(demomenu_t *info)
|
||||
{
|
||||
demomenu_t *info = menu->data;
|
||||
if (info->options)
|
||||
BZ_Free(info->options);
|
||||
demoitem_t *btree = info->items, *item, *lastitem;
|
||||
demoitem_t *listhead = NULL, *listlast = NULL;
|
||||
|
||||
while(btree)
|
||||
{
|
||||
if (!btree->prev)
|
||||
{ //none on left side, descend down right removing head node
|
||||
item = btree;
|
||||
btree = btree->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
item = btree;
|
||||
lastitem = item;
|
||||
for (;;)
|
||||
{
|
||||
if (!item->prev)
|
||||
{
|
||||
lastitem->prev = item->next;
|
||||
break;
|
||||
}
|
||||
lastitem = item;
|
||||
item = lastitem->prev;
|
||||
}
|
||||
}
|
||||
if (listlast)
|
||||
{
|
||||
listlast->next = item;
|
||||
item->prev = listlast;
|
||||
listlast = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
listhead = listlast = item;
|
||||
item->prev = NULL;
|
||||
}
|
||||
}
|
||||
if (listlast)
|
||||
listlast->next = NULL;
|
||||
info->items = listhead;
|
||||
info->selected = listhead;
|
||||
info->firstitem = listhead;
|
||||
}
|
||||
|
||||
void ShowDemoMenu (menu_t *menu, char *path)
|
||||
static void M_Demo_Flush (demomenu_t *info)
|
||||
{
|
||||
demoitem_t *item;
|
||||
while (info->items)
|
||||
{
|
||||
item = info->items;
|
||||
info->items = item->next;
|
||||
BZ_Free(item);
|
||||
}
|
||||
info->items = NULL;
|
||||
info->selected = NULL;
|
||||
info->firstitem = NULL;
|
||||
}
|
||||
|
||||
static void M_Demo_Remove (menu_t *menu)
|
||||
{
|
||||
demomenu_t *info = menu->data;
|
||||
M_Demo_Flush(info);
|
||||
}
|
||||
|
||||
static void ShowDemoMenu (menu_t *menu, char *path)
|
||||
{
|
||||
int c;
|
||||
char *s;
|
||||
|
@ -399,11 +546,10 @@ void ShowDemoMenu (menu_t *menu, char *path)
|
|||
if (c<2)
|
||||
*path = '\0';
|
||||
}
|
||||
((demomenu_t*)menu->data)->nummatches = 0;
|
||||
((demomenu_t*)menu->data)->firstshown = 0;
|
||||
((demomenu_t*)menu->data)->selected = 0;
|
||||
((demomenu_t*)menu->data)->selected = NULL;
|
||||
((demomenu_t*)menu->data)->pathlen = strlen(path);
|
||||
|
||||
M_Demo_Flush(menu->data);
|
||||
if (*path)
|
||||
{
|
||||
sprintf(match, "%s../", path);
|
||||
|
@ -412,6 +558,7 @@ void ShowDemoMenu (menu_t *menu, char *path)
|
|||
sprintf(match, "%s*", path);
|
||||
|
||||
COM_EnumerateFiles(match, DemoAddItem, menu->data);
|
||||
M_Demo_Flatten(menu->data);
|
||||
}
|
||||
|
||||
void M_Menu_Demos_f (void)
|
||||
|
|
Loading…
Reference in a new issue