mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-14 16:40:57 +00:00
681 lines
14 KiB
C
681 lines
14 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1997-2001 Id Software, Inc.
|
|
|
|
This file is part of Quake 2 source code.
|
|
|
|
Quake 2 source code 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.
|
|
|
|
Quake 2 source code 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 Quake 2 source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
// ui_menu.c -- menu support/handling functions
|
|
|
|
#include "../client/client.h"
|
|
#include "ui_local.h"
|
|
|
|
menulayer_t ui_layers[MAX_MENU_DEPTH];
|
|
int ui_menudepth;
|
|
|
|
void (*m_drawfunc) (void);
|
|
const char *(*m_keyfunc) (int key);
|
|
|
|
#ifndef NOTTHIRTYFLIGHTS
|
|
extern char *menu_click;
|
|
#endif
|
|
|
|
/*
|
|
=======================================================================
|
|
|
|
MENU HANDLING
|
|
|
|
=======================================================================
|
|
*/
|
|
|
|
/*
|
|
=================
|
|
UI_AddButton
|
|
From Q2max
|
|
=================
|
|
*/
|
|
void UI_AddButton (buttonmenuobject_t *thisObj, int index, float x, float y, float w, float h)
|
|
{
|
|
float x1, y1, w1, h1;
|
|
|
|
x1 = x; y1 = y; w1 = w; h1 = h;
|
|
SCR_ScaleCoords (&x1, &y1, &w1, &h1, ALIGN_CENTER);
|
|
thisObj->min[0] = x1; thisObj->max[0] = x1 + w1;
|
|
thisObj->min[1] = y1; thisObj->max[1] = y1 + h1;
|
|
thisObj->index = index;
|
|
}
|
|
|
|
|
|
/*
|
|
=============
|
|
UI_AddMainButton
|
|
From Q2max
|
|
=============
|
|
*/
|
|
void UI_AddMainButton (mainmenuobject_t *thisObj, int index, int x, int y, char *name)
|
|
{
|
|
int w, h;
|
|
float x1, y1, w1, h1;
|
|
|
|
R_DrawGetPicSize (&w, &h, name);
|
|
|
|
x1 = x; y1 = y; w1 = w; h1 = h;
|
|
SCR_ScaleCoords (&x1, &y1, &w1, &h1, ALIGN_CENTER);
|
|
thisObj->min[0] = x1; thisObj->max[0] = x1 + w1;
|
|
thisObj->min[1] = y1; thisObj->max[1] = y1 + h1;
|
|
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
thisObj->OpenMenu = Menu_Game_f;
|
|
break;
|
|
case 1:
|
|
thisObj->OpenMenu = Menu_Multiplayer_f;
|
|
break;
|
|
case 2:
|
|
thisObj->OpenMenu = Menu_Options_f;
|
|
break;
|
|
case 3:
|
|
thisObj->OpenMenu = Menu_Video_f;
|
|
break;
|
|
case 4:
|
|
thisObj->OpenMenu = Menu_Quit_f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_PushMenu
|
|
=================
|
|
*/
|
|
void UI_PushMenu ( void (*draw) (void), const char *(*key) (int k) )
|
|
{
|
|
int i;
|
|
|
|
if (Cvar_VariableValue ("maxclients") == 1 && Com_ServerState () && !cls.consoleActive) // Knightmare added
|
|
Cvar_Set ("paused", "1");
|
|
|
|
// Knightmare- if just opened menu, and ingame and not DM, grab screen first
|
|
if (cls.key_dest != key_menu && !Cvar_VariableValue("deathmatch")
|
|
&& Com_ServerState() == 2) //ss_game
|
|
//&& !cl.cinematictime && Com_ServerState())
|
|
R_GrabScreen();
|
|
|
|
// if this menu is already present, drop back to that level
|
|
// to avoid stacking menus by hotkeys
|
|
for (i=0 ; i<ui_menudepth ; i++)
|
|
if (ui_layers[i].draw == draw &&
|
|
ui_layers[i].key == key)
|
|
{
|
|
ui_menudepth = i;
|
|
}
|
|
|
|
if (i == ui_menudepth)
|
|
{
|
|
if (ui_menudepth >= MAX_MENU_DEPTH)
|
|
Com_Error (ERR_FATAL, "UI_PushMenu: MAX_MENU_DEPTH");
|
|
ui_layers[ui_menudepth].draw = m_drawfunc;
|
|
ui_layers[ui_menudepth].key = m_keyfunc;
|
|
ui_menudepth++;
|
|
}
|
|
|
|
m_drawfunc = draw;
|
|
m_keyfunc = key;
|
|
|
|
ui_entersound = true;
|
|
|
|
// Knightmare- added Psychospaz's mouse support
|
|
UI_RefreshCursorLink ();
|
|
UI_RefreshCursorButtons ();
|
|
|
|
cls.key_dest = key_menu;
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_ForceMenuOff
|
|
=================
|
|
*/
|
|
void UI_ForceMenuOff (void)
|
|
{
|
|
// Knightmare- added Psychospaz's mouse support
|
|
UI_RefreshCursorLink ();
|
|
m_drawfunc = 0;
|
|
m_keyfunc = 0;
|
|
cls.key_dest = key_game;
|
|
ui_menudepth = 0;
|
|
Key_ClearStates ();
|
|
if (!cls.consoleActive && Cvar_VariableValue ("maxclients") == 1 && Com_ServerState()) // Knightmare added
|
|
Cvar_Set ("paused", "0");
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_PopMenu
|
|
=================
|
|
*/
|
|
void UI_PopMenu (void)
|
|
{
|
|
S_StartLocalSound (ui_menu_out_sound);
|
|
if (ui_menudepth < 1)
|
|
Com_Error (ERR_FATAL, "UI_PopMenu: depth < 1");
|
|
ui_menudepth--;
|
|
|
|
m_drawfunc = ui_layers[ui_menudepth].draw;
|
|
m_keyfunc = ui_layers[ui_menudepth].key;
|
|
|
|
// Knightmare- added Psychospaz's mouse support
|
|
UI_RefreshCursorLink ();
|
|
UI_RefreshCursorButtons ();
|
|
|
|
if (!ui_menudepth)
|
|
UI_ForceMenuOff ();
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_BackMenu
|
|
=================
|
|
*/
|
|
void UI_BackMenu (void *unused)
|
|
{
|
|
// We need to manually save changes for playerconfig menu here
|
|
if (m_drawfunc == Menu_PlayerConfig_Draw)
|
|
Menu_PConfigSaveChanges ();
|
|
|
|
UI_PopMenu ();
|
|
}
|
|
|
|
|
|
/*
|
|
==========================
|
|
UI_AddMenuItem
|
|
==========================
|
|
*/
|
|
void UI_AddMenuItem (menuframework_s *menu, void *item)
|
|
{
|
|
int i, j;
|
|
menulist_s *list;
|
|
menucommon_s *baseItem;
|
|
|
|
if (menu->nitems == 0)
|
|
menu->nslots = 0;
|
|
|
|
if (menu->nitems < MAXMENUITEMS)
|
|
{
|
|
menu->items[menu->nitems] = item;
|
|
( (menucommon_s *)menu->items[menu->nitems] )->parent = menu;
|
|
menu->nitems++;
|
|
}
|
|
|
|
menu->nslots = UI_TallyMenuSlots(menu);
|
|
|
|
list = (menulist_s *)item;
|
|
|
|
switch (list->generic.type) {
|
|
case MTYPE_SPINCONTROL:
|
|
for (i=0; list->itemNames[i]; i++);
|
|
list->numItems = i;
|
|
if (list->itemValues) // Check if itemvalues count matches itemnames
|
|
{
|
|
for (j=0; list->itemValues[j]; j++);
|
|
if (j != i) {
|
|
Com_Printf (S_COLOR_YELLOW"UI_AddMenuItem: itemvalues size mismatch for %s!\n",
|
|
(list->generic.name && (list->generic.name[0] != 0)) ? list->generic.name : "<noname>");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Knightmare- init text size
|
|
baseItem = (menucommon_s *)item;
|
|
if (!baseItem->textSize)
|
|
baseItem->textSize = MENU_FONT_SIZE;
|
|
baseItem->textSize = min(max(baseItem->textSize, 4), 32);
|
|
// end Knightmare
|
|
|
|
UI_ClearGrabBindItem (menu); // make sure this starts out unset
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_SetGrabBindItem
|
|
=================
|
|
*/
|
|
void UI_SetGrabBindItem (menuframework_s *m, menucommon_s *item)
|
|
{
|
|
int i;
|
|
menucommon_s *it;
|
|
qboolean found = false;
|
|
|
|
for (i = 0; i < m->nitems; i++)
|
|
{
|
|
it = (menucommon_s *)m->items[i];
|
|
if (it->type == MTYPE_KEYBIND)
|
|
{
|
|
if (it == item) {
|
|
((menukeybind_s *)it)->grabBind = true;
|
|
m->grabBindCursor = i;
|
|
found = true;
|
|
}
|
|
else // clear grab flag if it's not the one
|
|
((menukeybind_s *)it)->grabBind = false;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
m->grabBindCursor = -1;
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_ClearGrabBindItem
|
|
=================
|
|
*/
|
|
void UI_ClearGrabBindItem (menuframework_s *m)
|
|
{
|
|
int i;
|
|
menucommon_s *it;
|
|
|
|
m->grabBindCursor = -1;
|
|
|
|
// clear grab flag for all keybind items
|
|
for (i = 0; i < m->nitems; i++)
|
|
{
|
|
it = (menucommon_s *)m->items[i];
|
|
if (it->type == MTYPE_KEYBIND)
|
|
((menukeybind_s *)it)->grabBind = false;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_HasValidGrabBindItem
|
|
=================
|
|
*/
|
|
qboolean UI_HasValidGrabBindItem (menuframework_s *m)
|
|
{
|
|
if (!m) return false;
|
|
|
|
if ( (m->grabBindCursor != -1)
|
|
&& (m->grabBindCursor >= 0)
|
|
&& (m->grabBindCursor < m->nitems)
|
|
&& (((menucommon_s *)m->items[m->grabBindCursor])->type == MTYPE_KEYBIND)
|
|
&& (((menukeybind_s *)m->items[m->grabBindCursor])->grabBind) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
==========================
|
|
UI_MenuItemIsValidCursorPosition
|
|
Checks if an item can be used
|
|
as a cursor position.
|
|
==========================
|
|
*/
|
|
qboolean UI_MenuItemIsValidCursorPosition (void *item)
|
|
{
|
|
if (!item) return false;
|
|
|
|
// if ( (((menuCommon_s *)item)->flags & QMF_NOINTERACTION) || (((menuCommon_s *)item)->flags & QMF_MOUSEONLY) )
|
|
// return false;
|
|
|
|
// hidden items are invalid
|
|
if ( ((menucommon_s *)item)->flags & QMF_HIDDEN )
|
|
return false;
|
|
|
|
switch ( ((menucommon_s *)item)->type )
|
|
{
|
|
case MTYPE_SEPARATOR:
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
==========================
|
|
UI_AdjustMenuCursor
|
|
|
|
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.
|
|
==========================
|
|
*/
|
|
void UI_AdjustMenuCursor (menuframework_s *m, int dir)
|
|
{
|
|
menucommon_s *citem;
|
|
|
|
//
|
|
// see if it's in a valid spot
|
|
//
|
|
if (m->cursor >= 0 && m->cursor < m->nitems)
|
|
{
|
|
if ( (citem = UI_ItemAtMenuCursor(m)) != 0 )
|
|
{
|
|
// if (citem->type != MTYPE_SEPARATOR)
|
|
if ( UI_MenuItemIsValidCursorPosition(citem) )
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// it's not in a valid spot, so crawl in the direction indicated until we
|
|
// find a valid spot
|
|
//
|
|
if (dir == 1)
|
|
{
|
|
while (1)
|
|
{
|
|
if ( (citem = UI_ItemAtMenuCursor(m)) != 0 )
|
|
// if ( citem->type != MTYPE_SEPARATOR )
|
|
if ( UI_MenuItemIsValidCursorPosition(citem) )
|
|
break;
|
|
m->cursor += dir;
|
|
if ( m->cursor >= m->nitems )
|
|
m->cursor = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (1)
|
|
{
|
|
if ( (citem = UI_ItemAtMenuCursor(m)) != 0 )
|
|
// if (citem->type != MTYPE_SEPARATOR)
|
|
if ( UI_MenuItemIsValidCursorPosition(citem) )
|
|
break;
|
|
m->cursor += dir;
|
|
if (m->cursor < 0)
|
|
m->cursor = m->nitems - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
==========================
|
|
UI_CenterMenu
|
|
==========================
|
|
*/
|
|
void UI_CenterMenu (menuframework_s *menu)
|
|
{
|
|
int height = ((menucommon_s *) menu->items[menu->nitems-1])->y + 10;
|
|
menu->y = (SCREEN_HEIGHT - height)*0.5;
|
|
}
|
|
|
|
|
|
/*
|
|
==========================
|
|
UI_DrawMenu
|
|
==========================
|
|
*/
|
|
void UI_DrawMenu (menuframework_s *menu)
|
|
{
|
|
int i;
|
|
menucommon_s *item;
|
|
|
|
//
|
|
// draw contents
|
|
//
|
|
for (i = 0; i < menu->nitems; i++)
|
|
{
|
|
UI_DrawMenuItem (menu->items[i]);
|
|
}
|
|
|
|
// Psychspaz's mouse support
|
|
// check for mouseovers
|
|
UI_Mouseover_Check (menu);
|
|
|
|
item = UI_ItemAtMenuCursor(menu);
|
|
|
|
if (item && item->cursordraw)
|
|
{
|
|
item->cursordraw(item);
|
|
}
|
|
else if (menu->cursordraw)
|
|
{
|
|
menu->cursordraw(menu);
|
|
}
|
|
else if (item && item->type != MTYPE_FIELD)
|
|
{
|
|
char *cursor;
|
|
int cursorX;
|
|
|
|
#ifdef NOTTHIRTYFLIGHTS
|
|
if (item->type == MTYPE_KEYBIND && ((menukeybind_s *)item)->grabBind)
|
|
cursor = UI_ITEMCURSOR_KEYBIND_PIC;
|
|
else
|
|
cursor = ((int)(Sys_Milliseconds()/250)&1) ? UI_ITEMCURSOR_DEFAULT_PIC : UI_ITEMCURSOR_BLINK_PIC;
|
|
#else
|
|
if (item->flags & QMF_LEFT_JUSTIFY)
|
|
cursorX = menu->x + item->x + item->cursor_offset - 24;
|
|
else
|
|
cursorX = menu->x + item->cursor_offset;
|
|
#endif
|
|
#ifdef NOTTHIRTYFLIGHTS
|
|
cursorX = menu->x + item->x + item->cursor_offset;
|
|
if ( (item->flags & QMF_LEFT_JUSTIFY) && (item->type == MTYPE_ACTION) )
|
|
cursorX -= 4*MENU_FONT_SIZE;
|
|
|
|
UI_DrawPic (cursorX, menu->y+item->y, item->textSize, item->textSize, ALIGN_CENTER, false, cursor, 255);
|
|
#else
|
|
// TFOL added the sin/anglemod portion and removed the blink
|
|
if (item->flags & QMF_LEFT_JUSTIFY)
|
|
{
|
|
SCR_DrawChar (menu->x+item->x+item->cursor_offset-28+ (3*sin(anglemod(cl.time*0.01))), menu->y+item->y,
|
|
item->textSize, ALIGN_CENTER, 13 /* 12+((int)(Sys_Milliseconds()/250)&1) */,
|
|
FONT_UI, 255,255,255,255, false, true);
|
|
}
|
|
else
|
|
{
|
|
SCR_DrawChar (menu->x+item->cursor_offset+ (5*sin(anglemod(cl.time*0.01))), menu->y+item->y,
|
|
item->textSize, ALIGN_CENTER, 13 /* 12+((int)(Sys_Milliseconds()/250)&1) */,
|
|
FONT_UI, 255,255,255,255, false, true);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (item)
|
|
{
|
|
// if (item->statusbarfunc)
|
|
// item->statusbarfunc ( (void *)item );
|
|
if (item->type == MTYPE_KEYBIND && ((menukeybind_s *)item)->grabBind && ((menukeybind_s *)item)->enter_statusbar)
|
|
UI_DrawMenuStatusBar (((menukeybind_s *)item)->enter_statusbar);
|
|
else if (item->statusbar)
|
|
UI_DrawMenuStatusBar (item->statusbar);
|
|
else
|
|
UI_DrawMenuStatusBar (menu->statusbar);
|
|
}
|
|
else
|
|
UI_DrawMenuStatusBar (menu->statusbar);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
UI_DefaultMenuKey
|
|
=================
|
|
*/
|
|
const char *UI_DefaultMenuKey (menuframework_s *m, int key)
|
|
{
|
|
const char *sound = NULL;
|
|
menucommon_s *item;
|
|
|
|
if ( m )
|
|
{
|
|
if ( ( item = UI_ItemAtMenuCursor( m ) ) != 0 )
|
|
{
|
|
if ( item->type == MTYPE_FIELD )
|
|
{
|
|
if ( UI_MenuField_Key((menufield_s *) item, key) )
|
|
return NULL;
|
|
}
|
|
else if (item->type == MTYPE_KEYBIND)
|
|
{
|
|
if ( (sound = UI_MenuKeyBind_Key((menukeybind_s *)item, key)) != ui_menu_null_sound )
|
|
return sound;
|
|
else
|
|
sound = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch ( key )
|
|
{
|
|
case K_JOY2: //BC 1/30/2024 gamepad B button
|
|
case K_ESCAPE:
|
|
UI_PopMenu ();
|
|
return ui_menu_out_sound;
|
|
case K_AUX29: //BC 1/30/2024 dpad up.
|
|
case K_JOY_UP: //BC 1/30/2024 joystick up.
|
|
case K_KP_UPARROW:
|
|
case K_UPARROW:
|
|
if ( m )
|
|
{
|
|
m->cursor--;
|
|
// Knightmare- added Psychospaz's mouse support
|
|
UI_RefreshCursorLink ();
|
|
|
|
UI_AdjustMenuCursor (m, -1);
|
|
sound = ui_menu_move_sound;
|
|
}
|
|
break;
|
|
case K_AUX31: //BC 1/30/2024 dpad down.
|
|
case K_JOY_DOWN: //BC 1/30/2024 joystick down.
|
|
case K_TAB:
|
|
case K_KP_DOWNARROW:
|
|
case K_DOWNARROW:
|
|
if ( m )
|
|
{
|
|
m->cursor++;
|
|
// Knightmare- added Psychospaz's mouse support
|
|
|
|
UI_RefreshCursorLink ();
|
|
UI_AdjustMenuCursor (m, 1);
|
|
sound = ui_menu_move_sound;
|
|
}
|
|
break;
|
|
case K_AUX32: //BC 1/30/2024 dpad left.
|
|
case K_KP_LEFTARROW:
|
|
case K_LEFTARROW:
|
|
if ( m )
|
|
{
|
|
UI_SlideMenuItem (m, -1);
|
|
sound = ui_menu_move_sound;
|
|
}
|
|
break;
|
|
case K_AUX30: //BC 1/30/2024 dpad right.
|
|
case K_KP_RIGHTARROW:
|
|
case K_RIGHTARROW:
|
|
if ( m )
|
|
{
|
|
UI_SlideMenuItem (m, 1);
|
|
sound = ui_menu_move_sound;
|
|
}
|
|
break;
|
|
|
|
/*case K_MOUSE1:
|
|
case K_MOUSE2:
|
|
case K_MOUSE3:
|
|
//Knightmare 12/22/2001
|
|
case K_MOUSE4:
|
|
case K_MOUSE5:*/
|
|
//end Knightmare
|
|
case K_JOY1:
|
|
//case K_JOY2: //BC B button for menu selection
|
|
case K_JOY3:
|
|
case K_JOY4:
|
|
case K_AUX1:
|
|
case K_AUX2:
|
|
case K_AUX3:
|
|
case K_AUX4:
|
|
case K_AUX5:
|
|
case K_AUX6:
|
|
case K_AUX7:
|
|
case K_AUX8:
|
|
case K_AUX9:
|
|
case K_AUX10:
|
|
case K_AUX11:
|
|
case K_AUX12:
|
|
case K_AUX13:
|
|
case K_AUX14:
|
|
case K_AUX15:
|
|
case K_AUX16:
|
|
case K_AUX17:
|
|
case K_AUX18:
|
|
case K_AUX19:
|
|
case K_AUX20:
|
|
case K_AUX21:
|
|
case K_AUX22:
|
|
case K_AUX23:
|
|
case K_AUX24:
|
|
case K_AUX25:
|
|
case K_AUX26:
|
|
case K_AUX27:
|
|
case K_AUX28:
|
|
//case K_AUX29: //BC dpad up for menu selection
|
|
//case K_AUX30: //BC dpad right for menu selection
|
|
//case K_AUX31: //BC dpad down for menu selection
|
|
//case K_AUX32: //BC dpad left for menu selection
|
|
|
|
#ifndef NOTTHIRTYFLIGHTS
|
|
case K_SPACE:
|
|
#endif
|
|
case K_KP_ENTER:
|
|
case K_ENTER:
|
|
#ifdef NOTTHIRTYFLIGHTS
|
|
if ( m )
|
|
UI_SelectMenuItem (m);
|
|
sound = ui_menu_move_sound;
|
|
#else
|
|
if ( m )
|
|
{
|
|
if ( item->type == MTYPE_CHECKBOX )
|
|
{
|
|
|
|
UI_SlideMenuItem( m, 1 );
|
|
sound = menu_click;
|
|
}
|
|
else
|
|
{
|
|
|
|
UI_SelectMenuItem( m );
|
|
|
|
if ( item->type == MTYPE_ACTION )
|
|
sound = ui_menu_move_sound;
|
|
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
return sound;
|
|
}
|