yquake2remaster/src/client/menu/qmenu.c

782 lines
14 KiB
C
Raw Normal View History

/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*
* =======================================================================
*
* This file implements the generic part of the menu
*
* =======================================================================
*/
#include <string.h>
#include <ctype.h>
2009-03-03 13:43:32 +00:00
#include "../header/client.h"
2010-06-19 19:21:16 +00:00
#include "header/qmenu.h"
2012-07-22 13:34:45 +00:00
static void Action_DoEnter(menuaction_s *a);
static void Action_Draw(menuaction_s *a);
static void Menu_DrawStatusBar(const char *string);
static void MenuList_Draw(menulist_s *l);
static void Separator_Draw(menuseparator_s *s);
static void Slider_DoSlide(menuslider_s *s, int dir);
static void Slider_Draw(menuslider_s *s);
static void SpinControl_Draw(menulist_s *s);
static void SpinControl_DoSlide(menulist_s *s, int dir);
#define RCOLUMN_OFFSET 16
#define LCOLUMN_OFFSET -16
extern viddef_t viddef;
2012-07-22 13:34:45 +00:00
#define VID_WIDTH viddef.width
#define VID_HEIGHT viddef.height
2012-07-22 13:34:45 +00:00
void
Action_DoEnter(menuaction_s *a)
{
if (a->generic.callback)
{
a->generic.callback(a);
}
}
2012-07-22 13:34:45 +00:00
void
Action_Draw(menuaction_s *a)
{
if (a->generic.flags & QMF_LEFT_JUSTIFY)
{
if (a->generic.flags & QMF_GRAYED)
{
Menu_DrawStringDark(a->generic.x + a->generic.parent->x +
LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y,
a->generic.name);
}
else
2012-07-22 13:34:45 +00:00
{
Menu_DrawString(a->generic.x + a->generic.parent->x +
LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y,
a->generic.name);
}
}
else
{
if (a->generic.flags & QMF_GRAYED)
{
Menu_DrawStringR2LDark(a->generic.x + a->generic.parent->x +
LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y,
a->generic.name);
}
else
2012-07-22 13:34:45 +00:00
{
Menu_DrawStringR2L(a->generic.x + a->generic.parent->x +
LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y,
a->generic.name);
}
}
2012-07-22 13:34:45 +00:00
if (a->generic.ownerdraw)
{
a->generic.ownerdraw(a);
}
}
2012-07-22 13:34:45 +00:00
qboolean
Field_DoEnter(menufield_s *f)
{
if (f->generic.callback)
{
f->generic.callback(f);
return true;
}
return false;
}
2012-07-22 13:34:45 +00:00
void
Field_Draw(menufield_s *f)
{
int i, n;
2012-07-22 13:34:45 +00:00
char tempbuffer[128] = "";
2012-07-22 13:34:45 +00:00
if (f->generic.name)
{
Menu_DrawStringR2LDark(f->generic.x + f->generic.parent->x +
LCOLUMN_OFFSET, f->generic.y + f->generic.parent->y,
f->generic.name);
}
n = f->visible_length + 1;
if (n > sizeof(tempbuffer))
{
n = sizeof(tempbuffer);
}
Q_strlcpy(tempbuffer, f->buffer + f->visible_offset, n);
2012-07-22 13:34:45 +00:00
Draw_Char(f->generic.x + f->generic.parent->x + 16,
f->generic.y + f->generic.parent->y - 4, 18);
Draw_Char(f->generic.x + f->generic.parent->x + 16,
f->generic.y + f->generic.parent->y + 4, 24);
Draw_Char(f->generic.x + f->generic.parent->x + 24 +
f->visible_length * 8, f->generic.y +
2012-07-22 13:34:45 +00:00
f->generic.parent->y - 4, 20);
Draw_Char(f->generic.x + f->generic.parent->x + 24 +
f->visible_length * 8, f->generic.y +
2012-07-22 13:34:45 +00:00
f->generic.parent->y + 4, 26);
for (i = 0; i < f->visible_length; i++)
{
Draw_Char(f->generic.x + f->generic.parent->x + 24 + i * 8,
f->generic.y + f->generic.parent->y - 4, 19);
Draw_Char(f->generic.x + f->generic.parent->x + 24 + i * 8,
f->generic.y + f->generic.parent->y + 4, 25);
}
2012-07-22 13:34:45 +00:00
Menu_DrawString(f->generic.x + f->generic.parent->x + 24,
f->generic.y + f->generic.parent->y, tempbuffer);
2012-07-22 13:34:45 +00:00
if (Menu_ItemAtCursor(f->generic.parent) == f)
{
int offset;
2012-07-22 13:34:45 +00:00
if (f->visible_offset)
{
offset = f->visible_length;
2012-07-22 13:34:45 +00:00
}
else
2012-07-22 13:34:45 +00:00
{
offset = f->cursor;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
if (((int)(Sys_Milliseconds() / 250)) & 1)
{
Draw_Char(f->generic.x + f->generic.parent->x +
(offset + 2) * 8 + 8, f->generic.y +
2012-07-22 13:34:45 +00:00
f->generic.parent->y, 11);
}
else
{
Draw_Char(f->generic.x + f->generic.parent->x +
(offset + 2) * 8 + 8, f->generic.y +
2012-07-22 13:34:45 +00:00
f->generic.parent->y, ' ');
}
}
}
2009-03-03 10:34:25 +00:00
extern int keydown[];
2012-07-22 13:34:45 +00:00
qboolean
Field_Key(menufield_s *f, int key)
{
switch (key)
{
case K_KP_SLASH:
key = '/';
break;
case K_KP_MINUS:
key = '-';
break;
case K_KP_PLUS:
key = '+';
break;
case K_KP_HOME:
key = '7';
break;
case K_KP_UPARROW:
key = '8';
break;
case K_KP_PGUP:
key = '9';
break;
case K_KP_LEFTARROW:
key = '4';
break;
case K_KP_5:
key = '5';
break;
case K_KP_RIGHTARROW:
key = '6';
break;
case K_KP_END:
key = '1';
break;
case K_KP_DOWNARROW:
key = '2';
break;
case K_KP_PGDN:
key = '3';
break;
case K_KP_INS:
key = '0';
break;
case K_KP_DEL:
key = '.';
break;
}
2012-07-22 13:34:45 +00:00
if (key > 127)
{
return false;
}
2012-07-22 13:34:45 +00:00
switch (key)
{
case K_KP_LEFTARROW:
case K_LEFTARROW:
case K_BACKSPACE:
2012-07-22 13:34:45 +00:00
if (f->cursor > 0)
{
memmove(&f->buffer[f->cursor - 1],
&f->buffer[f->cursor],
strlen(&f->buffer[f->cursor]) + 1);
f->cursor--;
2012-07-22 13:34:45 +00:00
if (f->visible_offset)
{
f->visible_offset--;
}
}
break;
case K_KP_DEL:
case K_DEL:
2012-07-22 13:34:45 +00:00
memmove(&f->buffer[f->cursor], &f->buffer[f->cursor + 1],
strlen(&f->buffer[f->cursor + 1]) + 1);
break;
case K_KP_ENTER:
case K_ENTER:
case K_ESCAPE:
case K_TAB:
return false;
case K_SPACE:
default:
2012-07-22 13:34:45 +00:00
if (!isdigit(key) && (f->generic.flags & QMF_NUMBERSONLY))
{
return false;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
if (f->cursor < f->length)
{
f->buffer[f->cursor++] = key;
f->buffer[f->cursor] = 0;
2012-07-22 13:34:45 +00:00
if (f->cursor > f->visible_length)
{
f->visible_offset++;
}
}
}
return true;
}
2012-07-22 13:34:45 +00:00
void
Menu_AddItem(menuframework_s *menu, void *item)
{
if (menu->nitems == 0)
{
menu->nslots = 0;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
if (menu->nitems < MAXMENUITEMS)
{
menu->items[menu->nitems] = item;
2012-07-22 13:34:45 +00:00
((menucommon_s *)menu->items[menu->nitems])->parent = menu;
menu->nitems++;
}
2012-07-22 13:34:45 +00:00
menu->nslots = Menu_TallySlots(menu);
}
/*
* This function takes the given menu, the direction, and attempts
* to adjust the menu's cursor so that it's at the next available
* slot.
*/
2012-07-22 13:34:45 +00:00
void
Menu_AdjustCursor(menuframework_s *m, int dir)
{
menucommon_s *citem;
/* see if it's in a valid spot */
2012-07-22 13:34:45 +00:00
if ((m->cursor >= 0) && (m->cursor < m->nitems))
{
if ((citem = Menu_ItemAtCursor(m)) != 0)
{
if (citem->type != MTYPE_SEPARATOR)
{
return;
2012-07-22 13:34:45 +00:00
}
}
}
/* it's not in a valid spot, so crawl in the direction
indicated until we find a valid spot */
2012-07-22 13:34:45 +00:00
if (dir == 1)
{
while (1)
{
citem = Menu_ItemAtCursor(m);
if (citem)
{
if (citem->type != MTYPE_SEPARATOR)
{
break;
2012-07-22 13:34:45 +00:00
}
}
m->cursor += dir;
2012-07-22 13:34:45 +00:00
if (m->cursor >= m->nitems)
{
m->cursor = 0;
2012-07-22 13:34:45 +00:00
}
}
2012-07-22 13:34:45 +00:00
}
else
{
while (1)
{
citem = Menu_ItemAtCursor(m);
if (citem)
{
if (citem->type != MTYPE_SEPARATOR)
{
break;
2012-07-22 13:34:45 +00:00
}
}
m->cursor += dir;
2012-07-22 13:34:45 +00:00
if (m->cursor < 0)
{
m->cursor = m->nitems - 1;
2012-07-22 13:34:45 +00:00
}
}
}
}
2012-07-22 13:34:45 +00:00
void
Menu_Center(menuframework_s *menu)
{
int height;
2012-07-22 13:34:45 +00:00
height = ((menucommon_s *)menu->items[menu->nitems - 1])->y;
height += 10;
2012-07-22 13:34:45 +00:00
menu->y = (VID_HEIGHT - height) / 2;
}
2012-07-22 13:34:45 +00:00
void
Menu_Draw(menuframework_s *menu)
{
int i;
menucommon_s *item;
/* draw contents */
2012-07-22 13:34:45 +00:00
for (i = 0; i < menu->nitems; i++)
{
switch (((menucommon_s *)menu->items[i])->type)
{
case MTYPE_FIELD:
2012-07-22 13:34:45 +00:00
Field_Draw((menufield_s *)menu->items[i]);
break;
case MTYPE_SLIDER:
2012-07-22 13:34:45 +00:00
Slider_Draw((menuslider_s *)menu->items[i]);
break;
case MTYPE_LIST:
2012-07-22 13:34:45 +00:00
MenuList_Draw((menulist_s *)menu->items[i]);
break;
case MTYPE_SPINCONTROL:
2012-07-22 13:34:45 +00:00
SpinControl_Draw((menulist_s *)menu->items[i]);
break;
case MTYPE_ACTION:
2012-07-22 13:34:45 +00:00
Action_Draw((menuaction_s *)menu->items[i]);
break;
case MTYPE_SEPARATOR:
2012-07-22 13:34:45 +00:00
Separator_Draw((menuseparator_s *)menu->items[i]);
break;
}
}
2012-07-22 13:34:45 +00:00
item = Menu_ItemAtCursor(menu);
2012-07-22 13:34:45 +00:00
if (item && item->cursordraw)
{
item->cursordraw(item);
}
else if (menu->cursordraw)
{
menu->cursordraw(menu);
}
else if (item && (item->type != MTYPE_FIELD))
{
if (item->flags & QMF_LEFT_JUSTIFY)
{
Draw_Char(menu->x + item->x - 24 + item->cursor_offset,
menu->y + item->y, 12 + ((int)(Sys_Milliseconds() /
250) & 1));
}
else
{
Draw_Char(menu->x + item->cursor_offset, menu->y + item->y,
12 + ((int)(Sys_Milliseconds() / 250) & 1));
}
}
2012-07-22 13:34:45 +00:00
if (item)
{
if (item->statusbarfunc)
{
item->statusbarfunc((void *)item);
}
2012-07-22 13:34:45 +00:00
else if (item->statusbar)
{
Menu_DrawStatusBar(item->statusbar);
}
else
2012-07-22 13:34:45 +00:00
{
Menu_DrawStatusBar(menu->statusbar);
}
}
else
{
Menu_DrawStatusBar(menu->statusbar);
}
}
2012-07-22 13:34:45 +00:00
void
Menu_DrawStatusBar(const char *string)
{
if (string)
{
int l = (int)strlen(string);
int maxcol = VID_WIDTH / 8;
int col = maxcol / 2 - l / 2;
2012-07-22 13:34:45 +00:00
Draw_Fill(0, VID_HEIGHT - 8, VID_WIDTH, 8, 4);
Menu_DrawString(col * 8, VID_HEIGHT - 8, string);
}
else
{
Draw_Fill(0, VID_HEIGHT - 8, VID_WIDTH, 8, 0);
}
}
2012-07-22 13:34:45 +00:00
void
Menu_DrawString(int x, int y, const char *string)
{
unsigned i;
2012-07-22 13:34:45 +00:00
for (i = 0; i < strlen(string); i++)
{
Draw_Char((x + i * 8), y, string[i]);
}
}
2012-07-22 13:34:45 +00:00
void
Menu_DrawStringDark(int x, int y, const char *string)
{
unsigned i;
2012-07-22 13:34:45 +00:00
for (i = 0; i < strlen(string); i++)
{
Draw_Char((x + i * 8), y, string[i] + 128);
}
}
2012-07-22 13:34:45 +00:00
void
Menu_DrawStringR2L(int x, int y, const char *string)
{
unsigned i;
2012-07-22 13:34:45 +00:00
for (i = 0; i < strlen(string); i++)
{
Draw_Char((x - i * 8), y, string[strlen(string) - i - 1]);
}
}
2012-07-22 13:34:45 +00:00
void
Menu_DrawStringR2LDark(int x, int y, const char *string)
{
unsigned i;
2012-07-22 13:34:45 +00:00
for (i = 0; i < strlen(string); i++)
{
Draw_Char((x - i * 8), y, string[strlen(string) - i - 1] + 128);
}
}
2012-07-22 13:34:45 +00:00
void *
Menu_ItemAtCursor(menuframework_s *m)
{
if ((m->cursor < 0) || (m->cursor >= m->nitems))
{
return 0;
2012-07-22 13:34:45 +00:00
}
return m->items[m->cursor];
}
2012-07-22 13:34:45 +00:00
qboolean
Menu_SelectItem(menuframework_s *s)
{
menucommon_s *item = (menucommon_s *)Menu_ItemAtCursor(s);
2012-07-22 13:34:45 +00:00
if (item)
{
switch (item->type)
{
case MTYPE_FIELD:
2012-07-22 13:34:45 +00:00
return Field_DoEnter((menufield_s *)item);
case MTYPE_ACTION:
2012-07-22 13:34:45 +00:00
Action_DoEnter((menuaction_s *)item);
return true;
case MTYPE_LIST:
return false;
case MTYPE_SPINCONTROL:
return false;
}
}
return false;
}
2012-07-22 13:34:45 +00:00
void
Menu_SetStatusBar(menuframework_s *m, const char *string)
{
m->statusbar = string;
}
2012-07-22 13:34:45 +00:00
void
Menu_SlideItem(menuframework_s *s, int dir)
{
menucommon_s *item = (menucommon_s *)Menu_ItemAtCursor(s);
2012-07-22 13:34:45 +00:00
if (item)
{
switch (item->type)
{
case MTYPE_SLIDER:
2012-07-22 13:34:45 +00:00
Slider_DoSlide((menuslider_s *)item, dir);
break;
case MTYPE_SPINCONTROL:
2012-07-22 13:34:45 +00:00
SpinControl_DoSlide((menulist_s *)item, dir);
break;
}
}
}
2012-07-22 13:34:45 +00:00
int
Menu_TallySlots(menuframework_s *menu)
{
int i;
int total = 0;
2012-07-22 13:34:45 +00:00
for (i = 0; i < menu->nitems; i++)
{
if (((menucommon_s *)menu->items[i])->type == MTYPE_LIST)
{
int nitems = 0;
2012-07-22 13:34:45 +00:00
const char **n = ((menulist_s *)menu->items[i])->itemnames;
while (*n)
2012-07-22 13:34:45 +00:00
{
nitems++, n++;
2012-07-22 13:34:45 +00:00
}
total += nitems;
2012-07-22 13:34:45 +00:00
}
else
{
total++;
}
}
return total;
}
2012-07-22 13:34:45 +00:00
void
MenuList_Draw(menulist_s *l)
{
const char **n;
int y = 0;
Menu_DrawStringR2LDark(l->generic.x + l->generic.parent->x
2012-07-22 13:34:45 +00:00
+ LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y,
l->generic.name);
n = l->itemnames;
Draw_Fill(l->generic.x - 112 + l->generic.parent->x,
l->generic.parent->y + l->generic.y +
2012-07-22 13:34:45 +00:00
l->curvalue * 10 + 10, 128, 10, 16);
2012-07-22 13:34:45 +00:00
while (*n)
{
Menu_DrawStringR2LDark(l->generic.x + l->generic.parent->x +
LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y +
y + 10, *n);
n++;
y += 10;
}
}
2012-07-22 13:34:45 +00:00
void
Separator_Draw(menuseparator_s *s)
{
if (s->generic.name)
{
Menu_DrawStringR2LDark(s->generic.x + s->generic.parent->x,
s->generic.y + s->generic.parent->y,
s->generic.name);
}
}
2012-07-22 13:34:45 +00:00
void
Slider_DoSlide(menuslider_s *s, int dir)
{
s->curvalue += dir;
2012-07-22 13:34:45 +00:00
if (s->curvalue > s->maxvalue)
{
s->curvalue = s->maxvalue;
2012-07-22 13:34:45 +00:00
}
else if (s->curvalue < s->minvalue)
{
s->curvalue = s->minvalue;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
if (s->generic.callback)
{
s->generic.callback(s);
}
}
#define SLIDER_RANGE 10
2012-07-22 13:34:45 +00:00
void
Slider_Draw(menuslider_s *s)
{
int i;
2012-07-22 13:34:45 +00:00
Menu_DrawStringR2LDark(s->generic.x + s->generic.parent->x +
LCOLUMN_OFFSET, s->generic.y + s->generic.parent->y,
s->generic.name);
s->range = (s->curvalue - s->minvalue) /
2012-07-22 13:34:45 +00:00
(float)(s->maxvalue - s->minvalue);
2012-07-22 13:34:45 +00:00
if (s->range < 0)
{
s->range = 0;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
if (s->range > 1)
{
s->range = 1;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
Draw_Char(s->generic.x + s->generic.parent->x + RCOLUMN_OFFSET,
s->generic.y + s->generic.parent->y,
128);
2012-07-22 13:34:45 +00:00
for (i = 0; i < SLIDER_RANGE; i++)
{
Draw_Char(RCOLUMN_OFFSET + s->generic.x + i * 8 +
2012-07-22 13:34:45 +00:00
s->generic.parent->x + 8, s->generic.y +
s->generic.parent->y, 129);
}
Draw_Char(RCOLUMN_OFFSET + s->generic.x + i * 8 +
2012-07-22 13:34:45 +00:00
s->generic.parent->x + 8, s->generic.y +
s->generic.parent->y, 130);
Draw_Char((int)(8 + RCOLUMN_OFFSET + s->generic.parent->x +
s->generic.x + (SLIDER_RANGE - 1) * 8 * s->range),
s->generic.y + s->generic.parent->y,
131);
}
2012-07-22 13:34:45 +00:00
void
SpinControl_DoSlide(menulist_s *s, int dir)
{
s->curvalue += dir;
2012-07-22 13:34:45 +00:00
if (s->curvalue < 0)
{
s->curvalue = 0;
2012-07-22 13:34:45 +00:00
}
else if (s->itemnames[s->curvalue] == 0)
{
s->curvalue--;
2012-07-22 13:34:45 +00:00
}
2012-07-22 13:34:45 +00:00
if (s->generic.callback)
{
s->generic.callback(s);
}
}
2012-07-22 13:34:45 +00:00
void
SpinControl_Draw(menulist_s *s)
{
char buffer[100];
2012-07-22 13:34:45 +00:00
if (s->generic.name)
{
Menu_DrawStringR2LDark(s->generic.x + s->generic.parent->x +
LCOLUMN_OFFSET, s->generic.y + s->generic.parent->y,
s->generic.name);
}
2012-07-22 13:34:45 +00:00
if (!strchr(s->itemnames[s->curvalue], '\n'))
{
Menu_DrawString(RCOLUMN_OFFSET + s->generic.x +
s->generic.parent->x, s->generic.y +
2012-07-22 13:34:45 +00:00
s->generic.parent->y,
s->itemnames[s->curvalue]);
}
else
{
strcpy(buffer, s->itemnames[s->curvalue]);
*strchr(buffer, '\n') = 0;
Menu_DrawString(RCOLUMN_OFFSET + s->generic.x +
s->generic.parent->x, s->generic.y +
2012-07-22 13:34:45 +00:00
s->generic.parent->y, buffer);
strcpy(buffer, strchr(s->itemnames[s->curvalue], '\n') + 1);
Menu_DrawString(RCOLUMN_OFFSET + s->generic.x +
s->generic.parent->x, s->generic.y +
2012-07-22 13:34:45 +00:00
s->generic.parent->y + 10, buffer);
}
}
2012-07-22 13:34:45 +00:00