mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-12 19:20:38 +00:00
Menus: Bring MenuFileSelect_t up to speed with MenuMenu_t.
>They see me scrollin' >They hatin' git-svn-id: https://svn.eduke32.com/eduke32@4509 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
2281e287dd
commit
a7714f2c74
2 changed files with 149 additions and 108 deletions
|
@ -1226,9 +1226,14 @@ static MenuMessage_t M_BUYDUKE = { CURSOR_BOTTOMRIGHT, MENU_EPISODE, };
|
||||||
|
|
||||||
static MenuPassword_t M_ADULTPASSWORD = { MAXPWLOCKOUT, NULL, };
|
static MenuPassword_t M_ADULTPASSWORD = { MAXPWLOCKOUT, NULL, };
|
||||||
|
|
||||||
#define MAKE_MENUFILESELECT(...) { __VA_ARGS__, FNLIST_INITIALIZER, NULL, NULL, 0, 0, };
|
#define MAKE_MENUFILESELECT(...) { __VA_ARGS__, FNLIST_INITIALIZER, { NULL, NULL, }, 0, { 0, 0, }, }
|
||||||
|
|
||||||
static MenuFileSelect_t M_USERMAP = MAKE_MENUFILESELECT( "Select A User Map", &MF_Minifont, &MF_MinifontRed, "*.map", boardfilename );
|
static MenuFileSelect_t M_USERMAP = MAKE_MENUFILESELECT( "Select A User Map", { &MF_Minifont, &MF_MinifontRed, }, "*.map", boardfilename );
|
||||||
|
|
||||||
|
static const int32_t MenuFileSelect_entryheight = 8<<16;
|
||||||
|
static const int32_t MenuFileSelect_startx[2] = { 40<<16, 180<<16, };
|
||||||
|
static const int32_t MenuFileSelect_ytop[2] = { ((1+12+32+8)<<16), (1+12+32)<<16, };
|
||||||
|
static const int32_t MenuFileSelect_ybottom = (1+12+32+8*13)<<16;
|
||||||
|
|
||||||
// MUST be in ascending order of MenuID enum values due to binary search
|
// MUST be in ascending order of MenuID enum values due to binary search
|
||||||
static Menu_t Menus[] = {
|
static Menu_t Menus[] = {
|
||||||
|
@ -2935,16 +2940,49 @@ static void M_MenuPasswordSubmit(char *input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void klistbookends(CACHE1D_FIND_REC *start)
|
||||||
|
{
|
||||||
|
CACHE1D_FIND_REC *end = start, *n;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
if (!start)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (start->prev)
|
||||||
|
start = start->prev;
|
||||||
|
|
||||||
|
while (end->next)
|
||||||
|
end = end->next;
|
||||||
|
|
||||||
|
for (n = start; n; n = n->next)
|
||||||
|
{
|
||||||
|
n->type = i; // overload this...
|
||||||
|
n->usera = start;
|
||||||
|
n->userb = end;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void M_MenuFileSelectInit(MenuFileSelect_t *object)
|
static void M_MenuFileSelectInit(MenuFileSelect_t *object)
|
||||||
{
|
{
|
||||||
if (object->destination[0] == 0) Bstrcpy(object->destination, "./");
|
size_t i;
|
||||||
|
|
||||||
|
if (object->destination[0] == 0)
|
||||||
|
Bstrcpy(object->destination, "./");
|
||||||
Bcorrectfilename(object->destination, 1);
|
Bcorrectfilename(object->destination, 1);
|
||||||
|
|
||||||
fnlist_getnames(&object->fnlist, object->destination, object->pattern, 0, 0);
|
fnlist_getnames(&object->fnlist, object->destination, object->pattern, 0, 0);
|
||||||
object->finddirshigh = object->fnlist.finddirs;
|
object->findhigh[0] = object->fnlist.finddirs;
|
||||||
object->findfileshigh = object->fnlist.findfiles;
|
object->findhigh[1] = object->fnlist.findfiles;
|
||||||
|
|
||||||
|
for (i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
object->scrollPos[i] = 0;
|
||||||
|
klistbookends(object->findhigh[i]);
|
||||||
|
}
|
||||||
|
|
||||||
object->currentList = 0;
|
object->currentList = 0;
|
||||||
if (object->findfileshigh)
|
if (object->findhigh[1])
|
||||||
object->currentList = 1;
|
object->currentList = 1;
|
||||||
|
|
||||||
KB_FlushKeyboardQueue();
|
KB_FlushKeyboardQueue();
|
||||||
|
@ -3614,6 +3652,20 @@ static void M_RunMenu_MenuOptionList(MenuOption_t *object)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void M_RunMenu_AbbreviateNameIntoBuffer(const char* name, int32_t entrylength)
|
||||||
|
{
|
||||||
|
int32_t len = Bstrlen(name);
|
||||||
|
Bstrncpy(tempbuf, name, len);
|
||||||
|
if (len > entrylength)
|
||||||
|
{
|
||||||
|
len = entrylength-3;
|
||||||
|
tempbuf[len] = 0;
|
||||||
|
while (len < entrylength)
|
||||||
|
tempbuf[len++] = '.';
|
||||||
|
}
|
||||||
|
tempbuf[len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void M_RunMenu(Menu_t *cm)
|
static void M_RunMenu(Menu_t *cm)
|
||||||
{
|
{
|
||||||
const int32_t cursorShade = 4-(sintable[(totalclock<<4)&2047]>>11);
|
const int32_t cursorShade = 4-(sintable[(totalclock<<4)&2047]>>11);
|
||||||
|
@ -3684,63 +3736,27 @@ static void M_RunMenu(Menu_t *cm)
|
||||||
|
|
||||||
mgametext(40+4,32,"Directories",0,2+8+16);
|
mgametext(40+4,32,"Directories",0,2+8+16);
|
||||||
|
|
||||||
if (object->finddirshigh)
|
|
||||||
{
|
|
||||||
int32_t len;
|
|
||||||
|
|
||||||
CACHE1D_FIND_REC *dir = object->finddirshigh;
|
|
||||||
for (i=0; i<5; i++) if (!dir->prev) break;
|
|
||||||
else dir=dir->prev;
|
|
||||||
for (i=5; i>-8 && dir; i--, dir=dir->next)
|
|
||||||
{
|
|
||||||
uint8_t status = 0;
|
|
||||||
|
|
||||||
len = Bstrlen(dir->name);
|
|
||||||
Bstrncpy(tempbuf,dir->name,len);
|
|
||||||
if (len > USERMAPENTRYLENGTH)
|
|
||||||
{
|
|
||||||
len = USERMAPENTRYLENGTH-3;
|
|
||||||
tempbuf[len] = 0;
|
|
||||||
while (len < USERMAPENTRYLENGTH)
|
|
||||||
tempbuf[len++] = '.';
|
|
||||||
}
|
|
||||||
tempbuf[len] = 0;
|
|
||||||
|
|
||||||
status |= (dir == object->finddirshigh && object->currentList == 0)<<0;
|
|
||||||
|
|
||||||
M_MenuText(40<<16, (1+12+32+8*(6-i))<<16, object->dirfont, tempbuf, status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mgametext(180+4,32,"Files",0,2+8+16);
|
mgametext(180+4,32,"Files",0,2+8+16);
|
||||||
|
|
||||||
if (object->findfileshigh)
|
for (i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
int32_t len;
|
if (object->findhigh[i])
|
||||||
|
{
|
||||||
|
CACHE1D_FIND_REC *dir;
|
||||||
|
int32_t y = MenuFileSelect_ytop[i] - object->scrollPos[i];
|
||||||
|
for (dir = object->findhigh[i]->usera; dir; dir = dir->next)
|
||||||
|
{
|
||||||
|
uint8_t status = (dir == object->findhigh[i] && object->currentList == i)<<0;
|
||||||
|
|
||||||
CACHE1D_FIND_REC *dir = object->findfileshigh;
|
// pal = dir->source==CACHE1D_SOURCE_ZIP ? 8 : 2
|
||||||
for (i=0; i<6; i++) if (!dir->prev) break;
|
|
||||||
else dir=dir->prev;
|
|
||||||
for (i=6; i>-8 && dir; i--, dir=dir->next)
|
|
||||||
{
|
|
||||||
uint8_t status = 0;
|
|
||||||
|
|
||||||
len = Bstrlen(dir->name);
|
M_RunMenu_AbbreviateNameIntoBuffer(dir->name, USERMAPENTRYLENGTH);
|
||||||
Bstrncpy(tempbuf,dir->name,len);
|
|
||||||
if (len > USERMAPENTRYLENGTH)
|
if (MenuFileSelect_ytop[i] <= y && y <= MenuFileSelect_ybottom)
|
||||||
{
|
M_MenuText(MenuFileSelect_startx[i], y, object->font[i], tempbuf, status);
|
||||||
len = USERMAPENTRYLENGTH-3;
|
|
||||||
tempbuf[len] = 0;
|
y += MenuFileSelect_entryheight;
|
||||||
while (len < USERMAPENTRYLENGTH)
|
|
||||||
tempbuf[len++] = '.';
|
|
||||||
}
|
}
|
||||||
tempbuf[len] = 0;
|
|
||||||
|
|
||||||
status |= (dir == object->findfileshigh && object->currentList == 1)<<0;
|
|
||||||
|
|
||||||
M_MenuText(180<<16, (1+12+32+8*(6-i))<<16, object->filefont, tempbuf, status);
|
|
||||||
|
|
||||||
// dir->source==CACHE1D_SOURCE_ZIP ? 8 : 2
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3860,9 +3876,7 @@ static void M_RunMenuInput(Menu_t *cm)
|
||||||
case FileSelect:
|
case FileSelect:
|
||||||
{
|
{
|
||||||
MenuFileSelect_t *object = (MenuFileSelect_t*)cm->object;
|
MenuFileSelect_t *object = (MenuFileSelect_t*)cm->object;
|
||||||
|
int32_t movement = 0;
|
||||||
// JBF 20040208: seek to first name matching pressed character
|
|
||||||
CACHE1D_FIND_REC *seeker = object->currentList ? object->fnlist.findfiles : object->fnlist.finddirs;
|
|
||||||
|
|
||||||
if (I_ReturnTrigger())
|
if (I_ReturnTrigger())
|
||||||
{
|
{
|
||||||
|
@ -3886,8 +3900,8 @@ static void M_RunMenuInput(Menu_t *cm)
|
||||||
|
|
||||||
if (object->currentList == 0)
|
if (object->currentList == 0)
|
||||||
{
|
{
|
||||||
if (!object->finddirshigh) break;
|
if (!object->findhigh[0]) break;
|
||||||
Bstrcat(object->destination, object->finddirshigh->name);
|
Bstrcat(object->destination, object->findhigh[0]->name);
|
||||||
Bstrcat(object->destination, "/");
|
Bstrcat(object->destination, "/");
|
||||||
Bcorrectfilename(object->destination, 1);
|
Bcorrectfilename(object->destination, 1);
|
||||||
|
|
||||||
|
@ -3897,32 +3911,39 @@ static void M_RunMenuInput(Menu_t *cm)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!object->findfileshigh) break;
|
if (!object->findhigh[1]) break;
|
||||||
Bstrcat(object->destination, object->findfileshigh->name);
|
Bstrcat(object->destination, object->findhigh[1]->name);
|
||||||
|
|
||||||
fnlist_clearnames(&object->fnlist);
|
fnlist_clearnames(&object->fnlist);
|
||||||
|
|
||||||
M_MenuFileSelect(1);
|
M_MenuFileSelect(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((KB_KeyPressed(sc_Home)|KB_KeyPressed(sc_End)) > 0)
|
else if (KB_KeyPressed(sc_Home))
|
||||||
{
|
{
|
||||||
while (seeker && (KB_KeyPressed(sc_End)?seeker->next:seeker->prev))
|
movement = 1;
|
||||||
seeker = KB_KeyPressed(sc_End)?seeker->next:seeker->prev;
|
|
||||||
if (seeker)
|
object->findhigh[object->currentList] = object->findhigh[object->currentList]->usera;
|
||||||
{
|
|
||||||
if (object->currentList) object->findfileshigh = seeker;
|
|
||||||
else object->finddirshigh = seeker;
|
|
||||||
// clear keys, don't play the kick sound a dozen times!
|
|
||||||
KB_ClearKeyDown(sc_End);
|
|
||||||
KB_ClearKeyDown(sc_Home);
|
KB_ClearKeyDown(sc_Home);
|
||||||
|
|
||||||
S_PlaySound(KICK_HIT);
|
S_PlaySound(KICK_HIT);
|
||||||
}
|
}
|
||||||
|
else if (KB_KeyPressed(sc_End))
|
||||||
|
{
|
||||||
|
movement = 1;
|
||||||
|
|
||||||
|
object->findhigh[object->currentList] = object->findhigh[object->currentList]->userb;
|
||||||
|
|
||||||
|
KB_ClearKeyDown(sc_End);
|
||||||
|
|
||||||
|
S_PlaySound(KICK_HIT);
|
||||||
}
|
}
|
||||||
else if ((KB_KeyPressed(sc_PgUp)|KB_KeyPressed(sc_PgDn)) > 0)
|
else if (KB_KeyPressed(sc_PgUp) || KB_KeyPressed(sc_PgDn))
|
||||||
{
|
{
|
||||||
int32_t i = 6;
|
int32_t i = 6;
|
||||||
seeker = object->currentList?object->findfileshigh:object->finddirshigh;
|
|
||||||
|
CACHE1D_FIND_REC *seeker = object->findhigh[object->currentList];
|
||||||
while (i>0)
|
while (i>0)
|
||||||
{
|
{
|
||||||
if (seeker && (KB_KeyPressed(sc_PgDn)?seeker->next:seeker->prev))
|
if (seeker && (KB_KeyPressed(sc_PgDn)?seeker->next:seeker->prev))
|
||||||
|
@ -3931,11 +3952,13 @@ static void M_RunMenuInput(Menu_t *cm)
|
||||||
}
|
}
|
||||||
if (seeker)
|
if (seeker)
|
||||||
{
|
{
|
||||||
if (object->currentList) object->findfileshigh = seeker;
|
movement = 1;
|
||||||
else object->finddirshigh = seeker;
|
|
||||||
// clear keys, don't play the kick sound a dozen times!
|
object->findhigh[object->currentList] = seeker;
|
||||||
|
|
||||||
KB_ClearKeyDown(sc_PgDn);
|
KB_ClearKeyDown(sc_PgDn);
|
||||||
KB_ClearKeyDown(sc_PgUp);
|
KB_ClearKeyDown(sc_PgUp);
|
||||||
|
|
||||||
S_PlaySound(KICK_HIT);
|
S_PlaySound(KICK_HIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3949,11 +3972,18 @@ static void M_RunMenuInput(Menu_t *cm)
|
||||||
KB_ClearKeyDown(sc_kpad_6);
|
KB_ClearKeyDown(sc_kpad_6);
|
||||||
KB_ClearKeyDown(sc_Tab);
|
KB_ClearKeyDown(sc_Tab);
|
||||||
MOUSE_ClearButton(MIDDLE_MOUSE);
|
MOUSE_ClearButton(MIDDLE_MOUSE);
|
||||||
|
|
||||||
|
if ((object->currentList ? object->fnlist.numdirs : object->fnlist.numfiles) > 0)
|
||||||
|
{
|
||||||
object->currentList = !object->currentList;
|
object->currentList = !object->currentList;
|
||||||
|
|
||||||
S_PlaySound(KICK_HIT);
|
S_PlaySound(KICK_HIT);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (KB_KeyPressed(sc_UpArrow) || KB_KeyPressed(sc_kpad_8) || (MOUSE_GetButtons()&WHEELUP_MOUSE) || BUTTON(gamefunc_Move_Forward) || (JOYSTICK_GetHat(0)&HAT_UP))
|
else if (KB_KeyPressed(sc_UpArrow) || KB_KeyPressed(sc_kpad_8) || (MOUSE_GetButtons()&WHEELUP_MOUSE) || BUTTON(gamefunc_Move_Forward) || (JOYSTICK_GetHat(0)&HAT_UP))
|
||||||
{
|
{
|
||||||
|
movement = 1;
|
||||||
|
|
||||||
KB_ClearKeyDown(sc_UpArrow);
|
KB_ClearKeyDown(sc_UpArrow);
|
||||||
KB_ClearKeyDown(sc_kpad_8);
|
KB_ClearKeyDown(sc_kpad_8);
|
||||||
MOUSE_ClearButton(WHEELUP_MOUSE);
|
MOUSE_ClearButton(WHEELUP_MOUSE);
|
||||||
|
@ -3962,19 +3992,18 @@ static void M_RunMenuInput(Menu_t *cm)
|
||||||
|
|
||||||
S_PlaySound(KICK_HIT);
|
S_PlaySound(KICK_HIT);
|
||||||
|
|
||||||
if (object->currentList == 0)
|
if (object->findhigh[object->currentList])
|
||||||
{
|
{
|
||||||
if (object->finddirshigh)
|
if (object->findhigh[object->currentList]->prev)
|
||||||
if (object->finddirshigh->prev) object->finddirshigh = object->finddirshigh->prev;
|
object->findhigh[object->currentList] = object->findhigh[object->currentList]->prev;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
object->findhigh[object->currentList] = object->findhigh[object->currentList]->userb;
|
||||||
if (object->findfileshigh)
|
|
||||||
if (object->findfileshigh->prev) object->findfileshigh = object->findfileshigh->prev;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (KB_KeyPressed(sc_DownArrow) || KB_KeyPressed(sc_kpad_2) || (MOUSE_GetButtons()&WHEELDOWN_MOUSE) || BUTTON(gamefunc_Move_Backward) || (JOYSTICK_GetHat(0)&HAT_DOWN))
|
else if (KB_KeyPressed(sc_DownArrow) || KB_KeyPressed(sc_kpad_2) || (MOUSE_GetButtons()&WHEELDOWN_MOUSE) || BUTTON(gamefunc_Move_Backward) || (JOYSTICK_GetHat(0)&HAT_DOWN))
|
||||||
{
|
{
|
||||||
|
movement = 1;
|
||||||
|
|
||||||
KB_ClearKeyDown(sc_DownArrow);
|
KB_ClearKeyDown(sc_DownArrow);
|
||||||
KB_ClearKeyDown(sc_kpad_2);
|
KB_ClearKeyDown(sc_kpad_2);
|
||||||
KB_ClearKeyDown(sc_PgDn);
|
KB_ClearKeyDown(sc_PgDn);
|
||||||
|
@ -3984,40 +4013,53 @@ static void M_RunMenuInput(Menu_t *cm)
|
||||||
|
|
||||||
S_PlaySound(KICK_HIT);
|
S_PlaySound(KICK_HIT);
|
||||||
|
|
||||||
if (object->currentList == 0)
|
if (object->findhigh[object->currentList])
|
||||||
{
|
{
|
||||||
if (object->finddirshigh)
|
if (object->findhigh[object->currentList]->next)
|
||||||
if (object->finddirshigh->next) object->finddirshigh = object->finddirshigh->next;
|
object->findhigh[object->currentList] = object->findhigh[object->currentList]->next;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
object->findhigh[object->currentList] = object->findhigh[object->currentList]->usera;
|
||||||
if (object->findfileshigh)
|
|
||||||
if (object->findfileshigh->next) object->findfileshigh = object->findfileshigh->next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// JBF 20040208: seek to first name matching pressed character
|
||||||
char ch2, ch;
|
char ch2, ch;
|
||||||
ch = KB_GetCh();
|
ch = KB_GetCh();
|
||||||
if (ch > 0 && ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')))
|
if (ch > 0 && ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')))
|
||||||
{
|
{
|
||||||
if (ch >= 'a') ch -= ('a'-'A');
|
CACHE1D_FIND_REC *seeker = object->findhigh[object->currentList]->usera;
|
||||||
|
if (ch >= 'a')
|
||||||
|
ch -= ('a'-'A');
|
||||||
while (seeker)
|
while (seeker)
|
||||||
{
|
{
|
||||||
ch2 = seeker->name[0];
|
ch2 = seeker->name[0];
|
||||||
if (ch2 >= 'a' && ch2 <= 'z') ch2 -= ('a'-'A');
|
if (ch2 >= 'a' && ch2 <= 'z')
|
||||||
if (ch2 == ch) break;
|
ch2 -= ('a'-'A');
|
||||||
|
if (ch2 == ch)
|
||||||
|
break;
|
||||||
seeker = seeker->next;
|
seeker = seeker->next;
|
||||||
}
|
}
|
||||||
if (seeker)
|
if (seeker)
|
||||||
{
|
{
|
||||||
if (object->currentList) object->findfileshigh = seeker;
|
movement = 1;
|
||||||
else object->finddirshigh = seeker;
|
|
||||||
|
object->findhigh[object->currentList] = seeker;
|
||||||
|
|
||||||
S_PlaySound(KICK_HIT);
|
S_PlaySound(KICK_HIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (movement)
|
||||||
|
{
|
||||||
|
int32_t ypos = MenuFileSelect_ytop[object->currentList] + object->findhigh[object->currentList]->type * MenuFileSelect_entryheight;
|
||||||
|
if (ypos - object->scrollPos[object->currentList] > MenuFileSelect_ybottom)
|
||||||
|
object->scrollPos[object->currentList] = ypos - MenuFileSelect_ybottom;
|
||||||
|
else if (ypos - object->scrollPos[object->currentList] < MenuFileSelect_ytop[object->currentList])
|
||||||
|
object->scrollPos[object->currentList] = ypos - MenuFileSelect_ytop[object->currentList];
|
||||||
|
}
|
||||||
|
|
||||||
M_PreMenuInput(NULL, NULL);
|
M_PreMenuInput(NULL, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -322,8 +322,7 @@ typedef struct MenuFileSelect_t
|
||||||
const char *title;
|
const char *title;
|
||||||
|
|
||||||
// appearance
|
// appearance
|
||||||
MenuTextType_t *dirfont;
|
MenuTextType_t *font[2];
|
||||||
MenuTextType_t *filefont;
|
|
||||||
|
|
||||||
// traits
|
// traits
|
||||||
const char *pattern;
|
const char *pattern;
|
||||||
|
@ -331,8 +330,8 @@ typedef struct MenuFileSelect_t
|
||||||
|
|
||||||
// state
|
// state
|
||||||
fnlist_t fnlist;
|
fnlist_t fnlist;
|
||||||
CACHE1D_FIND_REC *finddirshigh, *findfileshigh;
|
CACHE1D_FIND_REC *findhigh[2];
|
||||||
int32_t currentEntry, currentList;
|
int32_t currentList, scrollPos[2];
|
||||||
} MenuFileSelect_t;
|
} MenuFileSelect_t;
|
||||||
|
|
||||||
typedef struct Menu_t
|
typedef struct Menu_t
|
||||||
|
|
Loading…
Reference in a new issue