summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2013-03-12 18:35:40 +0400
committerAndrey Nazarov <skuller@skuller.net>2013-03-12 18:35:40 +0400
commit81d367700746853119939a30e2db60ff63bfbef9 (patch)
tree030cbc1c49be8eecb999d99f6868bbcbcb88a89b
parentf00bbaac10421e54ba045cb3df80c010f8a4dfea (diff)
Improve status bar support in menus.
Extend syntax of most menu items to accept ‘--status’ argument. Fix status bar updates when opening menus and moving between items. Draw multi-line status bar with word wrapping.
-rw-r--r--src/client/ui/menu.c69
-rw-r--r--src/client/ui/script.c198
-rw-r--r--src/client/ui/ui.h3
3 files changed, 215 insertions, 55 deletions
diff --git a/src/client/ui/menu.c b/src/client/ui/menu.c
index 60e3233..aa5d6cc 100644
--- a/src/client/ui/menu.c
+++ b/src/client/ui/menu.c
@@ -30,6 +30,7 @@ ACTION CONTROL
static void Action_Free(menuAction_t *a)
{
Z_Free(a->generic.name);
+ Z_Free(a->generic.status);
Z_Free(a->cmd);
Z_Free(a);
}
@@ -143,6 +144,7 @@ BITMAP CONTROL
static void Bitmap_Free(menuBitmap_t *b)
{
+ Z_Free(b->generic.status);
Z_Free(b->cmd);
Z_Free(b);
}
@@ -177,7 +179,9 @@ KEYBIND CONTROL
static void Keybind_Free(menuKeybind_t *k)
{
Z_Free(k->generic.name);
+ Z_Free(k->generic.status);
Z_Free(k->cmd);
+ Z_Free(k->altstatus);
Z_Free(k);
}
@@ -314,7 +318,7 @@ static qboolean keybind_cb(void *arg, int key)
Keybind_Update(menu);
menu->keywait = qfalse;
- menu->status = "Press Enter to change, Backspace to clear";
+ menu->status = k->generic.status;
Key_WaitKey(NULL, NULL);
UI_StartSound(QMS_OUT);
@@ -326,7 +330,7 @@ static menuSound_t Keybind_DoEnter(menuKeybind_t *k)
menuFrameWork_t *menu = k->generic.parent;
menu->keywait = qtrue;
- menu->status = "Press the desired key, Escape to cancel";
+ menu->status = k->altstatus;
Key_WaitKey(keybind_cb, k);
return QMS_IN;
}
@@ -507,6 +511,7 @@ static void SpinControl_Free(menuSpinControl_t *s)
int i;
Z_Free(s->generic.name);
+ Z_Free(s->generic.status);
for (i = 0; i < s->numItems; i++) {
Z_Free(s->itemnames[i]);
}
@@ -644,6 +649,7 @@ static void BitField_Pop(menuSpinControl_t *s)
static void BitField_Free(menuSpinControl_t *s)
{
Z_Free(s->generic.name);
+ Z_Free(s->generic.status);
Z_Free(s);
}
@@ -677,6 +683,7 @@ static void Pairs_Free(menuSpinControl_t *s)
int i;
Z_Free(s->generic.name);
+ Z_Free(s->generic.status);
for (i = 0; i < s->numItems; i++) {
Z_Free(s->itemnames[i]);
Z_Free(s->itemvalues[i]);
@@ -1454,6 +1461,7 @@ static void Slider_Pop(menuSlider_t *s)
static void Slider_Free(menuSlider_t *s)
{
Z_Free(s->generic.name);
+ Z_Free(s->generic.status);
Z_Free(s);
}
@@ -1588,7 +1596,7 @@ static void Savegame_Push(menuAction_t *a)
a->generic.name = info;
a->generic.flags &= ~QMF_GRAYED;
} else {
- a->generic.name = Z_CopyString("<EMPTY>");
+ a->generic.name = UI_CopyString("<EMPTY>");
if (a->generic.type == MTYPE_LOADGAME)
a->generic.flags |= QMF_GRAYED;
}
@@ -1722,6 +1730,9 @@ void Menu_Init(menuFrameWork_t *menu)
if (!focus && menu->nitems) {
item = menu->items[0];
((menuCommon_t *)item)->flags |= QMF_HASFOCUS;
+ if (((menuCommon_t *)item)->status) {
+ menu->status = ((menuCommon_t *)item)->status;
+ }
}
// calc menu bounding box
@@ -1887,7 +1898,8 @@ void Menu_SetFocus(menuCommon_t *focus)
item->flags &= ~QMF_HASFOCUS;
if (item->focus) {
item->focus(item, qfalse);
- } else if (menu->status == item->status) {
+ } else if (menu->status == item->status
+ && menu->status != focus->status) {
menu->status = NULL;
}
}
@@ -1951,6 +1963,51 @@ menuSound_t Menu_AdjustCursor(menuFrameWork_t *m, int dir)
return QMS_MOVE;
}
+static void Menu_DrawStatus(menuFrameWork_t *menu)
+{
+ int linewidth = uis.width / CHAR_WIDTH;
+ int x, y, l, count;
+ char *txt, *p;
+ int lens[8];
+ char *ptrs[8];
+
+ txt = menu->status;
+ x = 0;
+
+ count = 0;
+ ptrs[0] = txt;
+
+ while (*txt) {
+ // count word length
+ for (p = txt; *p > 32; p++)
+ ;
+ l = p - txt;
+
+ // word wrap
+ if ((l < linewidth && x + l > linewidth) || (x == linewidth)) {
+ if (count == 7)
+ break;
+ lens[count++] = x;
+ ptrs[count] = txt;
+ x = 0;
+ }
+
+ // display character and advance
+ txt++;
+ x++;
+ }
+
+ lens[count++] = x;
+
+ R_DrawFill8(0, menu->y2 - count * CHAR_HEIGHT, uis.width, count * CHAR_HEIGHT, 4);
+
+ for (l = 0; l < count; l++) {
+ x = (uis.width - lens[l] * CHAR_WIDTH) / 2;
+ y = menu->y2 - (count - l) * CHAR_HEIGHT;
+ R_DrawString(x, y, 0, lens[l], ptrs[l], uis.fontHandle);
+ }
+}
+
/*
=================
Menu_Draw
@@ -2051,9 +2108,7 @@ void Menu_Draw(menuFrameWork_t *menu)
// draw status bar
//
if (menu->status) {
- R_DrawFill8(0, menu->y2 - CHAR_HEIGHT, uis.width, CHAR_HEIGHT, 4);
- UI_DrawString(uis.width / 2, menu->y2 - CHAR_HEIGHT,
- UI_CENTER, menu->status);
+ Menu_DrawStatus(menu);
}
}
diff --git a/src/client/ui/script.c b/src/client/ui/script.c
index 7e30df9..9d276ad 100644
--- a/src/client/ui/script.c
+++ b/src/client/ui/script.c
@@ -47,12 +47,28 @@ static menuSound_t Activate(menuCommon_t *self)
return; \
}
+static const cmd_option_t o_common[] = {
+ { "s:", "status" },
+ { NULL }
+};
+
static void Parse_Spin(menuFrameWork_t *menu, menuType_t type)
{
menuSpinControl_t *s;
- int numItems = Cmd_Argc() - 3;
- int i;
+ int c, i, numItems;
+ char *status = NULL;
+
+ while ((c = Cmd_ParseOptions(o_common)) != -1) {
+ switch (c) {
+ case 's':
+ status = cmd_optarg;
+ break;
+ default:
+ return;
+ }
+ }
+ numItems = Cmd_Argc() - (cmd_optind + 2);
if (numItems < 1) {
Com_Printf("Usage: %s <name> <cvar> <desc1> [...]\n", Cmd_Argv(0));
return;
@@ -62,11 +78,12 @@ static void Parse_Spin(menuFrameWork_t *menu, menuType_t type)
s = UI_Mallocz(sizeof(*s));
s->generic.type = type;
- s->generic.name = UI_CopyString(Cmd_Argv(1));
- s->cvar = Cvar_WeakGet(Cmd_Argv(2));
+ s->generic.name = UI_CopyString(Cmd_Argv(cmd_optind));
+ s->generic.status = UI_CopyString(status);
+ s->cvar = Cvar_WeakGet(Cmd_Argv(cmd_optind + 1));
s->itemnames = UI_Mallocz(sizeof(char *) * (numItems + 1));
for (i = 0; i < numItems; i++) {
- s->itemnames[i] = UI_CopyString(Cmd_Argv(3 + i));
+ s->itemnames[i] = UI_CopyString(Cmd_Argv(cmd_optind + 2 + i));
}
s->numItems = numItems;
@@ -76,9 +93,20 @@ static void Parse_Spin(menuFrameWork_t *menu, menuType_t type)
static void Parse_Pairs(menuFrameWork_t *menu)
{
menuSpinControl_t *s;
- int numItems = Cmd_Argc() - 3;
- int i;
+ int c, i, numItems;
+ char *status = NULL;
+ while ((c = Cmd_ParseOptions(o_common)) != -1) {
+ switch (c) {
+ case 's':
+ status = cmd_optarg;
+ break;
+ default:
+ return;
+ }
+ }
+
+ numItems = Cmd_Argc() - (cmd_optind + 2);
if (numItems < 2 || (numItems & 1)) {
Com_Printf("Usage: %s <name> <cvar> <desc1> <value1> [...]\n", Cmd_Argv(0));
return;
@@ -88,16 +116,15 @@ static void Parse_Pairs(menuFrameWork_t *menu)
s = UI_Mallocz(sizeof(*s));
s->generic.type = MTYPE_PAIRS;
- s->generic.name = UI_CopyString(Cmd_Argv(1));
- s->cvar = Cvar_WeakGet(Cmd_Argv(2));
- numItems >>= 1;
+ s->generic.name = UI_CopyString(Cmd_Argv(cmd_optind));
+ s->generic.status = UI_CopyString(status);
+ s->cvar = Cvar_WeakGet(Cmd_Argv(cmd_optind + 1));
+ numItems /= 2;
s->itemnames = UI_Mallocz(sizeof(char *) * (numItems + 1));
- for (i = 0; i < numItems; i++) {
- s->itemnames[i] = UI_CopyString(Cmd_Argv(3 + i * 2));
- }
s->itemvalues = UI_Mallocz(sizeof(char *) * (numItems + 1));
for (i = 0; i < numItems; i++) {
- s->itemvalues[i] = UI_CopyString(Cmd_Argv(4 + i * 2));
+ s->itemnames[i] = UI_CopyString(Cmd_Argv(cmd_optind + 2 + i * 2));
+ s->itemvalues[i] = UI_CopyString(Cmd_Argv(cmd_optind + 3 + i * 2));
}
s->numItems = numItems;
@@ -107,8 +134,20 @@ static void Parse_Pairs(menuFrameWork_t *menu)
static void Parse_Range(menuFrameWork_t *menu)
{
menuSlider_t *s;
+ char *status = NULL;
+ int c;
+
+ while ((c = Cmd_ParseOptions(o_common)) != -1) {
+ switch (c) {
+ case 's':
+ status = cmd_optarg;
+ break;
+ default:
+ return;
+ }
+ }
- if (Cmd_Argc() < 5) {
+ if (Cmd_Argc() - cmd_optind < 4) {
Com_Printf("Usage: %s <name> <cvar> <min> <max> [step]\n", Cmd_Argv(0));
return;
}
@@ -117,12 +156,13 @@ static void Parse_Range(menuFrameWork_t *menu)
s = UI_Mallocz(sizeof(*s));
s->generic.type = MTYPE_SLIDER;
- s->generic.name = UI_CopyString(Cmd_Argv(1));
- s->cvar = Cvar_WeakGet(Cmd_Argv(2));
- s->minvalue = atof(Cmd_Argv(3));
- s->maxvalue = atof(Cmd_Argv(4));
- if (Cmd_Argc() > 5) {
- s->step = atof(Cmd_Argv(5));
+ s->generic.name = UI_CopyString(Cmd_Argv(cmd_optind));
+ s->generic.status = UI_CopyString(status);
+ s->cvar = Cvar_WeakGet(Cmd_Argv(cmd_optind + 1));
+ s->minvalue = atof(Cmd_Argv(cmd_optind + 2));
+ s->maxvalue = atof(Cmd_Argv(cmd_optind + 3));
+ if (Cmd_Argc() - cmd_optind > 4) {
+ s->step = atof(Cmd_Argv(cmd_optind + 4));
} else {
s->step = (s->maxvalue - s->minvalue) / SLIDER_RANGE;
}
@@ -132,7 +172,7 @@ static void Parse_Range(menuFrameWork_t *menu)
static void Parse_Action(menuFrameWork_t *menu)
{
- static const cmd_option_t options[] = {
+ static const cmd_option_t o_action[] = {
{ "a", "align" },
{ "s:", "status" },
{ NULL }
@@ -142,7 +182,7 @@ static void Parse_Action(menuFrameWork_t *menu)
char *status = NULL;
int c;
- while ((c = Cmd_ParseOptions(options)) != -1) {
+ while ((c = Cmd_ParseOptions(o_action)) != -1) {
switch (c) {
case 'a':
uiFlags = UI_LEFT | UI_ALTCOLOR;
@@ -175,28 +215,45 @@ static void Parse_Action(menuFrameWork_t *menu)
static void Parse_Bitmap(menuFrameWork_t *menu)
{
- char buffer[MAX_QPATH];
+ static const cmd_option_t o_bitmap[] = {
+ { "s:", "status" },
+ { "N:", "altname" },
+ { NULL }
+ };
menuBitmap_t *b;
- char *name;
+ char *status = NULL, *altname = NULL;
+ int c;
- if (Cmd_Argc() < 3) {
+ while ((c = Cmd_ParseOptions(o_bitmap)) != -1) {
+ switch (c) {
+ case 's':
+ status = cmd_optarg;
+ break;
+ case 'N':
+ altname = cmd_optarg;
+ break;
+ default:
+ return;
+ }
+ }
+
+ if (Cmd_Argc() - cmd_optind < 2) {
Com_Printf("Usage: %s <name> <command>\n", Cmd_Argv(0));
return;
}
CHECK_NITEMS
+ if (!altname)
+ altname = va("%s_sel", Cmd_Argv(cmd_optind));
+
b = UI_Mallocz(sizeof(*b));
b->generic.type = MTYPE_BITMAP;
b->generic.activate = Activate;
- b->cmd = UI_CopyString(Cmd_ArgsFrom(2));
-
- name = Cmd_Argv(1);
- b->pics[0] = R_RegisterPic(name);
-
- Q_snprintf(buffer, sizeof(buffer), "%s_sel", name);
- b->pics[1] = R_RegisterPic(buffer);
-
+ b->generic.status = UI_CopyString(status);
+ b->cmd = UI_CopyString(Cmd_ArgsFrom(cmd_optind + 1));
+ b->pics[0] = R_RegisterPic(Cmd_Argv(cmd_optind));
+ b->pics[1] = R_RegisterPic(altname);
R_GetPicSize(&b->generic.width, &b->generic.height, b->pics[0]);
Menu_AddItem(menu, b);
@@ -204,9 +261,30 @@ static void Parse_Bitmap(menuFrameWork_t *menu)
static void Parse_Bind(menuFrameWork_t *menu)
{
+ static const cmd_option_t o_bind[] = {
+ { "s:", "status" },
+ { "S:", "altstatus" },
+ { NULL }
+ };
menuKeybind_t *k;
+ char *status = "Press Enter to change, Backspace to clear";
+ char *altstatus = "Press the desired key, Escape to cancel";
+ int c;
- if (Cmd_Argc() < 3) {
+ while ((c = Cmd_ParseOptions(o_bind)) != -1) {
+ switch (c) {
+ case 's':
+ status = cmd_optarg;
+ break;
+ case 'S':
+ altstatus = cmd_optarg;
+ break;
+ default:
+ return;
+ }
+ }
+
+ if (Cmd_Argc() - cmd_optind < 2) {
Com_Printf("Usage: %s <name> <command>\n", Cmd_Argv(0));
return;
}
@@ -215,9 +293,11 @@ static void Parse_Bind(menuFrameWork_t *menu)
k = UI_Mallocz(sizeof(*k));
k->generic.type = MTYPE_KEYBIND;
- k->generic.name = UI_CopyString(Cmd_Argv(1));
+ k->generic.name = UI_CopyString(Cmd_Argv(cmd_optind));
k->generic.uiFlags = UI_CENTER;
- k->cmd = UI_CopyString(Cmd_ArgsFrom(2));
+ k->generic.status = UI_CopyString(status);
+ k->cmd = UI_CopyString(Cmd_ArgsFrom(cmd_optind + 1));
+ k->altstatus = UI_CopyString(altstatus);
Menu_AddItem(menu, k);
}
@@ -225,8 +305,20 @@ static void Parse_Bind(menuFrameWork_t *menu)
static void Parse_Savegame(menuFrameWork_t *menu, menuType_t type)
{
menuAction_t *a;
+ char *status = NULL;
+ int c;
- if (Cmd_Argc() < 2) {
+ while ((c = Cmd_ParseOptions(o_common)) != -1) {
+ switch (c) {
+ case 's':
+ status = cmd_optarg;
+ break;
+ default:
+ return;
+ }
+ }
+
+ if (Cmd_Argc() - cmd_optind < 1) {
Com_Printf("Usage: %s <dir>\n", Cmd_Argv(0));
return;
}
@@ -235,10 +327,11 @@ static void Parse_Savegame(menuFrameWork_t *menu, menuType_t type)
a = UI_Mallocz(sizeof(*a));
a->generic.type = type;
- a->generic.name = Z_CopyString("<EMPTY>");
- a->generic.uiFlags = UI_CENTER;
+ a->generic.name = UI_CopyString("<EMPTY>");
a->generic.activate = Activate;
- a->cmd = UI_CopyString(Cmd_Argv(1));
+ a->generic.uiFlags = UI_CENTER;
+ a->generic.status = UI_CopyString(status);
+ a->cmd = UI_CopyString(Cmd_Argv(cmd_optind));
if (type == MTYPE_LOADGAME)
a->generic.flags |= QMF_GRAYED;
@@ -252,15 +345,25 @@ static void Parse_Toggle(menuFrameWork_t *menu)
menuSpinControl_t *s;
qboolean negate = qfalse;
menuType_t type = MTYPE_TOGGLE;
- int bit = 0;
- char *b;
+ int c, bit = 0;
+ char *b, *status = NULL;
- if (Cmd_Argc() < 3) {
+ while ((c = Cmd_ParseOptions(o_common)) != -1) {
+ switch (c) {
+ case 's':
+ status = cmd_optarg;
+ break;
+ default:
+ return;
+ }
+ }
+
+ if (Cmd_Argc() - cmd_optind < 2) {
Com_Printf("Usage: %s <name> <cvar> [~][bit]\n", Cmd_Argv(0));
return;
}
- b = Cmd_Argv(3);
+ b = Cmd_Argv(cmd_optind + 2);
if (*b == '~') {
negate = qtrue;
b++;
@@ -278,8 +381,9 @@ static void Parse_Toggle(menuFrameWork_t *menu)
s = UI_Mallocz(sizeof(*s));
s->generic.type = type;
- s->generic.name = UI_CopyString(Cmd_Argv(1));
- s->cvar = Cvar_WeakGet(Cmd_Argv(2));
+ s->generic.name = UI_CopyString(Cmd_Argv(cmd_optind));
+ s->generic.status = UI_CopyString(status);
+ s->cvar = Cvar_WeakGet(Cmd_Argv(cmd_optind + 1));
s->itemnames = (char **)yes_no_names;
s->numItems = 2;
s->negate = negate;
diff --git a/src/client/ui/ui.h b/src/client/ui/ui.h
index 0c5e8f6..fda28cb 100644
--- a/src/client/ui/ui.h
+++ b/src/client/ui/ui.h
@@ -245,6 +245,7 @@ typedef struct menuKeybind_s {
char binding[32];
char altbinding[32];
char *cmd;
+ char *altstatus;
} menuKeybind_t;
#define MAX_PLAYERMODELS 1024
@@ -278,7 +279,7 @@ typedef struct uiStatic_s {
menuCommon_t *mouseTracker;
int mouseCoords[2];
qboolean entersound; // play after drawing a frame, so caching
- // won't disrupt the sound
+ // won't disrupt the sound
qboolean transparent;
int numPlayerModels;
playerModelInfo_t pmi[MAX_PLAYERMODELS];