/* =========================================================================== 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); /* ======================================================================= 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= 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( 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; 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->numitemnames = i; 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_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; cursor = ((int)(Sys_Milliseconds()/250)&1) ? UI_ITEMCURSOR_DEFAULT_PIC : UI_ITEMCURSOR_BLINK_PIC; if (item->flags & QMF_LEFT_JUSTIFY) cursorX = menu->x + item->x + item->cursor_offset - 24; else cursorX = menu->x + item->cursor_offset; UI_DrawPic (cursorX, menu->y+item->y, item->textSize, item->textSize, ALIGN_CENTER, false, cursor, 255); /* if (item->flags & QMF_LEFT_JUSTIFY) { UI_DrawChar (menu->x+item->x+item->cursor_offset-24, menu->y+item->y, item->textSize, ALIGN_CENTER, 12+((int)(Sys_Milliseconds()/250)&1), FONT_UI, 255,255,255,255, false, true); } else { UI_DrawChar (menu->x+item->cursor_offset, menu->y+item->y, item->textSize, ALIGN_CENTER, 12+((int)(Sys_Milliseconds()/250)&1), FONT_UI, 255,255,255,255, false, true); } */ } if (item) { if (item->statusbarfunc) item->statusbarfunc ( (void *)item ); else if (item->statusbar) UI_DrawStatusBar (item->statusbar); else UI_DrawStatusBar (menu->statusbar); } else UI_DrawStatusBar( 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; } } } switch ( key ) { case K_ESCAPE: UI_PopMenu(); return menu_out_sound; case K_KP_UPARROW: case K_UPARROW: if ( m ) { m->cursor--; // Knightmare- added Psychospaz's mouse support UI_RefreshCursorLink (); UI_AdjustMenuCursor (m, -1); sound = menu_move_sound; } break; 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 = menu_move_sound; } break; case K_KP_LEFTARROW: case K_LEFTARROW: if ( m ) { UI_SlideMenuItem (m, -1); sound = menu_move_sound; } break; case K_KP_RIGHTARROW: case K_RIGHTARROW: if ( m ) { UI_SlideMenuItem (m, 1); sound = 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: 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: case K_AUX30: case K_AUX31: case K_AUX32: case K_KP_ENTER: case K_ENTER: if ( m ) UI_SelectMenuItem (m); sound = menu_move_sound; break; } return sound; }