diff options
author | Andrey Nazarov <skuller@skuller.net> | 2013-03-12 18:35:40 +0400 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2013-03-12 18:35:40 +0400 |
commit | 81d367700746853119939a30e2db60ff63bfbef9 (patch) | |
tree | 030cbc1c49be8eecb999d99f6868bbcbcb88a89b | |
parent | f00bbaac10421e54ba045cb3df80c010f8a4dfea (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.c | 69 | ||||
-rw-r--r-- | src/client/ui/script.c | 198 | ||||
-rw-r--r-- | src/client/ui/ui.h | 3 |
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]; |