/* =========================================================================== Copyright (C) 1999 - 2005, Id Software, Inc. Copyright (C) 2000 - 2013, Raven Software, Inc. Copyright (C) 2001 - 2013, Activision, Inc. Copyright (C) 2013 - 2015, OpenJK contributors This file is part of the OpenJK source code. OpenJK is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. 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, see . =========================================================================== */ // // string allocation/managment // leave this at the top of all UI_xxxx files for PCH reasons... // #include "../server/exe_headers.h" #include "ui_local.h" //rww - added for ui ghoul2 models #define UI_SHARED_CPP #include "../game/anims.h" #include "../cgame/animtable.h" #include "ui_shared.h" #include "menudef.h" #include "qcommon/stringed_ingame.h" void UI_LoadMenus(const char *menuFile, qboolean reset); extern vmCvar_t ui_char_color_red; extern vmCvar_t ui_char_color_green; extern vmCvar_t ui_char_color_blue; void *UI_Alloc( int size ); void Controls_GetConfig( void ); void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount); void Item_Init(itemDef_t *item); void Item_InitControls(itemDef_t *item); qboolean Item_Parse(itemDef_t *item); void Item_RunScript(itemDef_t *item, const char *s); void Item_SetupKeywordHash(void); void Item_Text_AutoWrapped_Paint(itemDef_t *item); void Item_UpdatePosition(itemDef_t *item); void Item_ValidateTypeData(itemDef_t *item); void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t); itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p); itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name); void Menu_Paint(menuDef_t *menu, qboolean forcePaint); void Menu_SetupKeywordHash(void); void Menus_ShowItems(const char *menuName); qboolean ParseRect(const char **p, rectDef_t *r); const char *String_Alloc(const char *p); void ToWindowCoords(float *x, float *y, windowDef_t *window); void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle); int Item_ListBox_ThumbDrawPosition(itemDef_t *item); int Item_ListBox_ThumbPosition(itemDef_t *item); int Item_ListBox_MaxScroll(itemDef_t *item); static qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) ; static qboolean Item_Paint(itemDef_t *item, qboolean bDraw); int Item_TextScroll_ThumbDrawPosition ( itemDef_t *item ); static void Item_TextScroll_BuildLines ( itemDef_t* item ); //static qboolean debugMode = qfalse; static qboolean g_waitingForKey = qfalse; static qboolean g_editingField = qfalse; static itemDef_t *g_bindItem = NULL; static itemDef_t *g_editItem = NULL; static itemDef_t *itemCapture = NULL; // item that has the mouse captured ( if any ) #define DOUBLE_CLICK_DELAY 300 static int lastListBoxClickTime = 0; static void (*captureFunc) (void *p) = NULL; static void *captureData = NULL; //const char defaultString[10] = {"default"}; #ifdef CGAME #define MEM_POOL_SIZE (128 * 1024) #else #define MEM_POOL_SIZE (4 * 1024 * 1024) #endif #define SCROLL_TIME_START 500 #define SCROLL_TIME_ADJUST 150 #define SCROLL_TIME_ADJUSTOFFSET 40 #define SCROLL_TIME_FLOOR 20 typedef struct scrollInfo_s { int nextScrollTime; int nextAdjustTime; int adjustValue; int scrollKey; float xStart; float yStart; itemDef_t *item; qboolean scrollDir; } scrollInfo_t; static scrollInfo_t scrollInfo; static char memoryPool[MEM_POOL_SIZE]; static int allocPoint, outOfMemory; displayContextDef_t *DC = NULL; menuDef_t Menus[MAX_MENUS]; // defined menus int menuCount = 0; // how many menuDef_t *menuStack[MAX_OPEN_MENUS]; int openMenuCount = 0; static int strPoolIndex = 0; static char strPool[STRING_POOL_SIZE]; typedef struct stringDef_s { struct stringDef_s *next; const char *str; } stringDef_t; #define HASH_TABLE_SIZE 2048 static int strHandleCount = 0; static stringDef_t *strHandle[HASH_TABLE_SIZE]; typedef struct itemFlagsDef_s { const char *string; int value; } itemFlagsDef_t; itemFlagsDef_t itemFlags [] = { { "WINDOW_INACTIVE", WINDOW_INACTIVE }, { NULL, 0 } }; const char *styles [] = { "WINDOW_STYLE_EMPTY", "WINDOW_STYLE_FILLED", "WINDOW_STYLE_GRADIENT", "WINDOW_STYLE_SHADER", "WINDOW_STYLE_TEAMCOLOR", "WINDOW_STYLE_CINEMATIC", NULL }; const char *types [] = { "ITEM_TYPE_TEXT", "ITEM_TYPE_BUTTON", "ITEM_TYPE_RADIOBUTTON", "ITEM_TYPE_CHECKBOX", "ITEM_TYPE_EDITFIELD", "ITEM_TYPE_COMBO", "ITEM_TYPE_LISTBOX", "ITEM_TYPE_MODEL", "ITEM_TYPE_OWNERDRAW", "ITEM_TYPE_NUMERICFIELD", "ITEM_TYPE_SLIDER", "ITEM_TYPE_YESNO", "ITEM_TYPE_MULTI", "ITEM_TYPE_BIND", "ITEM_TYPE_TEXTSCROLL", NULL }; const char *alignment [] = { "ITEM_ALIGN_LEFT", "ITEM_ALIGN_CENTER", "ITEM_ALIGN_RIGHT", NULL }; /* ================== Init_Display Initializes the display with a structure to all the drawing routines ================== */ void Init_Display(displayContextDef_t *dc) { DC = dc; } /* ================== Window_Init Initializes a window structure ( windowDef_t ) with defaults ================== */ void Window_Init(Window *w) { memset(w, 0, sizeof(windowDef_t)); w->borderSize = 1; w->foreColor[0] = w->foreColor[1] = w->foreColor[2] = w->foreColor[3] = 1.0; w->cinematic = -1; } /* ================= PC_SourceError ================= */ void PC_SourceError(int handle, char *format, ...) { int line; char filename[128]; va_list argptr; static char string[4096]; va_start (argptr, format); Q_vsnprintf (string, sizeof(string), format, argptr); va_end (argptr); filename[0] = '\0'; line = 0; Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string); } /* ================= PC_ParseStringMem ================= */ qboolean PC_ParseStringMem(const char **out) { const char *temp; if (PC_ParseString(&temp)) { return qfalse; } *(out) = String_Alloc(temp); return qtrue; } /* ================= PC_ParseRect ================= */ qboolean PC_ParseRect(rectDef_t *r) { if (!PC_ParseFloat(&r->x)) { if (!PC_ParseFloat(&r->y)) { if (!PC_ParseFloat(&r->w)) { if (!PC_ParseFloat(&r->h)) { return qtrue; } } } } return qfalse; } /* ================= PC_Script_Parse ================= */ qboolean PC_Script_Parse(const char **out) { char script[4096]; // pc_token_t token; char *token2; script[0]=0; // scripts start with { and have ; separated command lists.. commands are command, arg.. // basically we want everything between the { } as it will be interpreted at run time token2 = PC_ParseExt(); if (!token2) { return qfalse; } if (*token2 !='{') { return qfalse; } while ( 1 ) { token2 = PC_ParseExt(); if (!token2) { return qfalse; } if (*token2 =='}') // End of the script? { *out = String_Alloc(script); return qtrue; } if (*(token2 +1) != '\0') { Q_strcat(script, sizeof(script), va("\"%s\"", token2)); } else { Q_strcat(script, sizeof(script), token2); } Q_strcat(script, sizeof(script), " "); } } //-------------------------------------------------------------------------------------------- // Menu Keyword Parse functions //-------------------------------------------------------------------------------------------- /* ================= MenuParse_font ================= */ qboolean MenuParse_font( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (!PC_ParseStringMem(&menu->font)) { return qfalse; } if (!DC->Assets.fontRegistered) { DC->Assets.qhMediumFont = DC->registerFont(menu->font); DC->Assets.fontRegistered = qtrue; } return qtrue; } /* ================= MenuParse_name ================= */ qboolean MenuParse_name(itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (!PC_ParseStringMem((const char **) &menu->window.name)) { return qfalse; } // if (Q_stricmp(menu->window.name, "main") == 0) // { // default main as having focus // menu->window.flags |= WINDOW_HASFOCUS; // } return qtrue; } /* ================= MenuParse_fullscreen ================= */ qboolean MenuParse_fullscreen( itemDef_t *item ) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseInt((int *) &menu->fullScreen)) { return qfalse; } return qtrue; } /* ================= MenuParse_rect ================= */ qboolean MenuParse_rect( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (!PC_ParseRect(&menu->window.rect)) { return qfalse; } return qtrue; } /* ================= MenuParse_style ================= */ qboolean MenuParse_style( itemDef_t *item) { int i; const char *tempStr; menuDef_t *menu = (menuDef_t*)item; if (PC_ParseString(&tempStr)) { return qfalse; } i=0; while (styles[i]) { if (Q_stricmp(tempStr,styles[i])==0) { menu->window.style = i; break; } i++; } if (styles[i] == NULL) { PC_ParseWarning(va("Unknown menu style value '%s'",tempStr)); } return qtrue; } /* ================= MenuParse_visible ================= */ qboolean MenuParse_visible( itemDef_t *item ) { int i; menuDef_t *menu = (menuDef_t*)item; if (PC_ParseInt(&i)) { return qfalse; } if (i) { menu->window.flags |= WINDOW_VISIBLE; } return qtrue; } /* ================= MenuParse_ignoreescape ================= */ qboolean MenuParse_ignoreescape( itemDef_t *item ) { int i; menuDef_t *menu = (menuDef_t*)item; if (PC_ParseInt(&i)) { return qfalse; } if (i) { menu->window.flags |= WINDOW_IGNORE_ESCAPE; } return qtrue; } /* ================= MenuParse_onOpen ================= */ qboolean MenuParse_onOpen( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (!PC_Script_Parse(&menu->onOpen)) { return qfalse; } return qtrue; } /* ================= MenuParse_onClose ================= */ qboolean MenuParse_onClose( itemDef_t *item ) { menuDef_t *menu = (menuDef_t*)item; if (!PC_Script_Parse(&menu->onClose)) { return qfalse; } return qtrue; } //JLFACCEPT MPMOVED /* ================= MenuParse_onAccept ================= */ qboolean MenuParse_onAccept( itemDef_t *item ) { menuDef_t *menu = (menuDef_t*)item; if (!PC_Script_Parse(&menu->onAccept)) { return qfalse; } return qtrue; } /* ================= MenuParse_onESC ================= */ qboolean MenuParse_onESC( itemDef_t *item ) { menuDef_t *menu = (menuDef_t*)item; if (!PC_Script_Parse(&menu->onESC)) { return qfalse; } return qtrue; } /* ================= MenuParse_border ================= */ qboolean MenuParse_border( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseInt(&menu->window.border)) { return qfalse; } return qtrue; } /* ================= MenuParse_borderSize ================= */ qboolean MenuParse_borderSize( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseFloat(&menu->window.borderSize)) { return qfalse; } return qtrue; } /* ================= MenuParse_backcolor ================= */ qboolean MenuParse_backcolor( itemDef_t *item ) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for (i = 0; i < 4; i++) { if (PC_ParseFloat(&f)) { return qfalse; } menu->window.backColor[i] = f; } return qtrue; } /* ================= MenuParse_forecolor ================= */ qboolean MenuParse_forecolor( itemDef_t *item) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for (i = 0; i < 4; i++) { if (PC_ParseFloat(&f)) { return qfalse; } if (f < 0) { //special case for player color menu->window.flags |= WINDOW_PLAYERCOLOR; return qtrue; } menu->window.foreColor[i] = f; menu->window.flags |= WINDOW_FORECOLORSET; } return qtrue; } /* ================= MenuParse_bordercolor ================= */ qboolean MenuParse_bordercolor( itemDef_t *item ) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for (i = 0; i < 4; i++) { if (PC_ParseFloat(&f)) { return qfalse; } menu->window.borderColor[i] = f; } return qtrue; } /* ================= MenuParse_focuscolor ================= */ qboolean MenuParse_focuscolor( itemDef_t *item) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for (i = 0; i < 4; i++) { if (PC_ParseFloat(&f)) { return qfalse; } menu->focusColor[i] = f; } return qtrue; } /* ================= MenuParse_focuscolor ================= */ qboolean MenuParse_appearanceIncrement( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseFloat(&menu->appearanceIncrement)) { return qfalse; } return qtrue; } /* ================= MenuParse_descAlignment ================= */ qboolean MenuParse_descAlignment( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; const char *tempStr; int i; if (PC_ParseString(&tempStr)) { return qfalse; } i=0; while (alignment[i]) { if (Q_stricmp(tempStr,alignment[i])==0) { menu->descAlignment = i; break; } i++; } if (alignment[i] == NULL) { PC_ParseWarning(va("Unknown desc alignment value '%s'",tempStr)); } return qtrue; } /* ================= MenuParse_descTextStyle ================= */ qboolean MenuParse_descTextStyle( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseInt(&menu->descTextStyle)) { return qfalse; } return qtrue; } /* ================= MenuParse_descX ================= */ qboolean MenuParse_descX( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseInt(&menu->descX)) { return qfalse; } return qtrue; } /* ================= MenuParse_descY ================= */ qboolean MenuParse_descY( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseInt(&menu->descY)) { return qfalse; } return qtrue; } /* ================= MenuParse_descScale ================= */ qboolean MenuParse_descScale( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseFloat(&menu->descScale)) { return qfalse; } return qtrue; } /* ================= MenuParse_descColor ================= */ qboolean MenuParse_descColor( itemDef_t *item) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for (i = 0; i < 4; i++) { if (PC_ParseFloat(&f)) { return qfalse; } menu->descColor[i] = f; } return qtrue; } /* ================= MenuParse_disablecolor ================= */ qboolean MenuParse_disablecolor( itemDef_t *item) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for (i = 0; i < 4; i++) { if (PC_ParseFloat(&f)) { return qfalse; } menu->disableColor[i] = f; } return qtrue; } /* ================= MenuParse_outlinecolor ================= */ qboolean MenuParse_outlinecolor( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseColor(&menu->window.outlineColor)) { return qfalse; } return qtrue; } /* ================= MenuParse_background ================= */ qboolean MenuParse_background( itemDef_t *item) { const char *buff; menuDef_t *menu = (menuDef_t*)item; if (PC_ParseString(&buff)) { return qfalse; } menu->window.background = ui.R_RegisterShaderNoMip(buff); return qtrue; } /* ================= MenuParse_cinematic ================= */ qboolean MenuParse_cinematic( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (!PC_ParseStringMem((const char **) &menu->window.cinematicName)) { return qfalse; } return qtrue; } /* ================= MenuParse_ownerdrawFlag ================= */ qboolean MenuParse_ownerdrawFlag( itemDef_t *item) { int i; menuDef_t *menu = (menuDef_t*)item; if (PC_ParseInt(&i)) { return qfalse; } menu->window.ownerDrawFlags |= i; return qtrue; } /* ================= MenuParse_ownerdraw ================= */ qboolean MenuParse_ownerdraw( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseInt(&menu->window.ownerDraw)) { return qfalse; } return qtrue; } /* ================= MenuParse_popup ================= */ qboolean MenuParse_popup( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; menu->window.flags |= WINDOW_POPUP; return qtrue; } /* ================= MenuParse_outOfBounds ================= */ qboolean MenuParse_outOfBounds( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; menu->window.flags |= WINDOW_OOB_CLICK; return qtrue; } /* ================= MenuParse_soundLoop ================= */ qboolean MenuParse_soundLoop( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (!PC_ParseStringMem((const char **) &menu->soundName)) { return qfalse; } return qtrue; } /* ================ MenuParse_fadeClamp ================ */ qboolean MenuParse_fadeClamp( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseFloat(&menu->fadeClamp)) { return qfalse; } return qtrue; } /* ================ MenuParse_fadeAmount ================ */ qboolean MenuParse_fadeAmount( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseFloat(&menu->fadeAmount)) { return qfalse; } return qtrue; } /* ================ MenuParse_fadeCycle ================ */ qboolean MenuParse_fadeCycle( itemDef_t *item) { menuDef_t *menu = (menuDef_t*)item; if (PC_ParseInt(&menu->fadeCycle)) { return qfalse; } return qtrue; } /* =============== Item_ApplyHacks Hacks to fix issues with Team Arena menu scripts =============== */ static void Item_ApplyHacks( itemDef_t *item ) { #if !defined(_WIN32) || ( defined(_WIN32) && defined(idx64) ) // Fix length of favorite address in createfavorite.menu if ( item->type == ITEM_TYPE_MULTI && item->cvar && !Q_stricmp( item->cvar, "s_UseOpenAL" ) ) { if( item->parent ) { menuDef_t *parent = (menuDef_t *)item->parent; VectorSet4( parent->disableColor, 0.5f, 0.5f, 0.5f, 1.0f ); item->disabled = qtrue; // Just in case it had focus item->window.flags &= ~WINDOW_MOUSEOVER; Com_Printf( "Disabling eax field because current platform does not support EAX.\n"); } } if ( item->type == ITEM_TYPE_TEXT && item->window.name && !Q_stricmp( item->window.name, "eax_icon") && item->cvarTest && !Q_stricmp( item->cvarTest, "s_UseOpenAL" ) && item->enableCvar && (item->cvarFlags & CVAR_HIDE) ) { if( item->parent ) { menuDef_t *parent = (menuDef_t *)item->parent; VectorSet4( parent->disableColor, 0.5f, 0.5f, 0.5f, 1.0f ); item->disabled = item->disabledHidden = qtrue; // Just in case it had focus item->window.flags &= ~WINDOW_MOUSEOVER; Com_Printf( "Hiding eax_icon object because current platform does not support EAX.\n"); } } #endif if ( item->type == ITEM_TYPE_MULTI && item->window.name && !Q_stricmp( item->window.name, "sound_quality") ) { multiDef_t *multiPtr = (multiDef_t *)item->typeData; int i; qboolean found = qfalse; for( i = 0; i < multiPtr->count; i++ ) { if ( multiPtr->cvarValue[i] == 44 ) { found = qtrue; break; } } if ( !found && multiPtr->count < MAX_MULTI_CVARS ) { #ifdef JK2_MODE multiPtr->cvarList[multiPtr->count] = String_Alloc("@MENUS0_VERY_HIGH"); #else multiPtr->cvarList[multiPtr->count] = String_Alloc("@MENUS_VERY_HIGH"); #endif multiPtr->cvarValue[multiPtr->count] = 44; multiPtr->count++; Com_Printf( "Extended sound quality field to contain very high option.\n"); } } if ( item->type == ITEM_TYPE_MULTI && item->window.name && !Q_stricmp( item->window.name, "voice") && item->cvar && !Q_stricmp( item->cvar, "g_subtitles" ) ) { multiDef_t *multiPtr = (multiDef_t *)item->typeData; int i; qboolean found = qfalse; for( i = 0; i < multiPtr->count; i++ ) { if ( multiPtr->cvarValue[i] == 1 ) { found = qtrue; break; } } if ( !found && multiPtr->count < MAX_MULTI_CVARS ) { #ifdef JK2_MODE multiPtr->cvarList[multiPtr->count] = String_Alloc("@MENUS3_ALL_VOICEOVERS"); #else multiPtr->cvarList[multiPtr->count] = String_Alloc("@MENUS_ALL_VOICEOVERS"); #endif multiPtr->cvarValue[multiPtr->count] = 1; multiPtr->count++; Com_Printf( "Extended subtitles field to contain all voiceovers option.\n"); } } #ifdef JK2_MODE if ( item->type == ITEM_TYPE_MULTI && item->window.name && !Q_stricmp( item->window.name, "video_mode") && item->cvar && !Q_stricmp( item->cvar, "r_ext_texture_filter_anisotropic" ) ) { { memset(item->typeData, 0, sizeof(multiDef_t)); } editFieldDef_t *editPtr = NULL; item->cvarFlags = CVAR_DISABLE; item->type = ITEM_TYPE_SLIDER; Item_ValidateTypeData(item); editPtr = (editFieldDef_t *)item->typeData; editPtr->minVal = 0.5f; editPtr->maxVal = cls.glconfig.maxTextureFilterAnisotropy; editPtr->defVal = 1.0f; Com_Printf( "Converted anisotropic filter field to slider.\n"); } #endif } /* ================ MenuParse_itemDef ================ */ qboolean MenuParse_itemDef( itemDef_t *item ) { menuDef_t *menu = (menuDef_t*)item; if (menu->itemCount < MAX_MENUITEMS) { itemDef_t *newItem = menu->items[menu->itemCount] = (struct itemDef_s *) UI_Alloc(sizeof(itemDef_t)); Item_Init(newItem); if (!Item_Parse(newItem)) { return qfalse; } Item_InitControls( newItem ); newItem->parent = menu->items[menu->itemCount]->parent = menu; menu->itemCount++; Item_ApplyHacks( newItem ); } else { PC_ParseWarning(va("Exceeded item/menu max of %d", MAX_MENUITEMS)); } return qtrue; } #define KEYWORDHASH_SIZE 512 typedef struct keywordHash_s { const char *keyword; qboolean (*func)(itemDef_t *item); struct keywordHash_s *next; } keywordHash_t; keywordHash_t menuParseKeywords[] = { {"appearanceIncrement", MenuParse_appearanceIncrement}, {"backcolor", MenuParse_backcolor, }, {"background", MenuParse_background, }, {"border", MenuParse_border, }, {"bordercolor", MenuParse_bordercolor, }, {"borderSize", MenuParse_borderSize, }, {"cinematic", MenuParse_cinematic, }, {"descAlignment", MenuParse_descAlignment }, {"descTextStyle", MenuParse_descTextStyle }, {"desccolor", MenuParse_descColor }, {"descX", MenuParse_descX }, {"descY", MenuParse_descY }, {"descScale", MenuParse_descScale }, {"disablecolor", MenuParse_disablecolor, }, {"fadeClamp", MenuParse_fadeClamp, }, {"fadeCycle", MenuParse_fadeCycle, }, {"fadeAmount", MenuParse_fadeAmount, }, {"focuscolor", MenuParse_focuscolor, }, {"font", MenuParse_font, }, {"forecolor", MenuParse_forecolor, }, {"fullscreen", MenuParse_fullscreen, }, {"itemDef", MenuParse_itemDef, }, {"name", MenuParse_name, }, {"onClose", MenuParse_onClose, }, //JLFACCEPT MPMOVED {"onAccept", MenuParse_onAccept, }, {"onESC", MenuParse_onESC, }, {"onOpen", MenuParse_onOpen, }, {"outlinecolor", MenuParse_outlinecolor, }, {"outOfBoundsClick", MenuParse_outOfBounds, }, {"ownerdraw", MenuParse_ownerdraw, }, {"ownerdrawFlag", MenuParse_ownerdrawFlag,}, {"popup", MenuParse_popup, }, {"rect", MenuParse_rect, }, {"soundLoop", MenuParse_soundLoop, }, {"style", MenuParse_style, }, {"visible", MenuParse_visible, }, {"ignoreescape", MenuParse_ignoreescape, }, {NULL, NULL, } }; keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE]; /* ================ KeywordHash_Key ================ */ int KeywordHash_Key(const char *keyword) { int hash, i; hash = 0; for (i = 0; keyword[i] != '\0'; i++) { if (keyword[i] >= 'A' && keyword[i] <= 'Z') hash += (keyword[i] + ('a' - 'A')) * (119 + i); else hash += keyword[i] * (119 + i); } hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (KEYWORDHASH_SIZE-1); return hash; } /* ================ KeywordHash_Add ================ */ void KeywordHash_Add(keywordHash_t *table[], keywordHash_t *key) { int hash; hash = KeywordHash_Key(key->keyword); key->next = table[hash]; table[hash] = key; } /* =============== KeywordHash_Find =============== */ keywordHash_t *KeywordHash_Find(keywordHash_t *table[], const char *keyword) { keywordHash_t *key; int hash; hash = KeywordHash_Key(keyword); for (key = table[hash]; key; key = key->next) { if (!Q_stricmp(key->keyword, keyword)) return key; } return NULL; } /* ================ hashForString return a hash value for the string ================ */ static unsigned hashForString(const char *str) { int i; unsigned hash; char letter; hash = 0; i = 0; while (str[i] != '\0') { letter = tolower((unsigned char)str[i]); hash += (unsigned)(letter)*(i + 119); i++; } hash &= (HASH_TABLE_SIZE-1); return hash; } /* ================= String_Alloc ================= */ const char *String_Alloc(const char *p) { int len; unsigned hash; stringDef_t *str, *last; static const char *staticNULL = ""; if (p == NULL) { return NULL; } if (*p == 0) { return staticNULL; } hash = hashForString(p); str = strHandle[hash]; while (str) { if (strcmp(p, str->str) == 0) { return str->str; } str = str->next; } len = strlen(p); if (len + strPoolIndex + 1 < STRING_POOL_SIZE) { int ph = strPoolIndex; strcpy(&strPool[strPoolIndex], p); strPoolIndex += len + 1; str = strHandle[hash]; last = str; while (last && last->next) { last = last->next; } str = (stringDef_s *) UI_Alloc( sizeof(stringDef_t)); str->next = NULL; str->str = &strPool[ph]; if (last) { last->next = str; } else { strHandle[hash] = str; } return &strPool[ph]; } else { Com_Printf("WARNING: Ran out of strPool space\n"); } return NULL; } /* ================= String_Report ================= */ void String_Report(void) { float f; Com_Printf("Memory/String Pool Info\n"); Com_Printf("----------------\n"); f = strPoolIndex; f /= STRING_POOL_SIZE; f *= 100; Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE); f = allocPoint; f /= MEM_POOL_SIZE; f *= 100; Com_Printf("Memory Pool is %.1f%% full, %i bytes out of %i used.\n", f, allocPoint, MEM_POOL_SIZE); } /* ================= String_Init ================= */ void String_Init(void) { int i; for (i = 0; i < HASH_TABLE_SIZE; i++) { strHandle[i] = 0; } strHandleCount = 0; strPoolIndex = 0; UI_InitMemory(); Item_SetupKeywordHash(); Menu_SetupKeywordHash(); if (DC && DC->getBindingBuf) { Controls_GetConfig(); } } //--------------------------------------------------------------------------------------------------------- // Memory //--------------------------------------------------------------------------------------------------------- /* =============== UI_Alloc =============== */ void *UI_Alloc( int size ) { char *p; if ( allocPoint + size > MEM_POOL_SIZE ) { outOfMemory = qtrue; if (DC->Print) { DC->Print("UI_Alloc: Failure. Out of memory!\n"); } return NULL; } p = &memoryPool[allocPoint]; allocPoint += ( size + 15 ) & ~15; return p; } /* =============== UI_InitMemory =============== */ void UI_InitMemory( void ) { allocPoint = 0; outOfMemory = qfalse; } /* =============== Menu_ItemsMatchingGroup =============== */ int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name) { int i; int count = 0; for (i = 0; i < menu->itemCount; i++) { if ((!menu->items[i]->window.name) && (!menu->items[i]->window.group)) { Com_Printf(S_COLOR_YELLOW"WARNING: item has neither name or group\n"); continue; } if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) { count++; } } return count; } /* =============== Menu_GetMatchingItemByNumber =============== */ itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name) { int i; int count = 0; for (i = 0; i < menu->itemCount; i++) { if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) { if (count == index) { return menu->items[i]; } count++; } } return NULL; } /* =============== Menu_FadeItemByName =============== */ void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut) { itemDef_t *item; int i; int count = Menu_ItemsMatchingGroup(menu, p); for (i = 0; i < count; i++) { item = Menu_GetMatchingItemByNumber(menu, i, p); if (item != NULL) { if (fadeOut) { item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE); item->window.flags &= ~WINDOW_FADINGIN; } else { item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN); item->window.flags &= ~WINDOW_FADINGOUT; } } } } /* =============== Menu_ShowItemByName =============== */ void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow) { itemDef_t *item; int i; int count; count = Menu_ItemsMatchingGroup(menu, p); if (!count) { Com_Printf(S_COLOR_YELLOW"WARNING: Menu_ShowItemByName - unable to locate any items named: \"%s\"\n",p); } for (i = 0; i < count; i++) { item = Menu_GetMatchingItemByNumber(menu, i, p); if (item != NULL) { if (bShow) { item->window.flags |= WINDOW_VISIBLE; } else { item->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS); // stop cinematics playing in the window if (item->window.cinematic >= 0) { DC->stopCinematic(item->window.cinematic); item->window.cinematic = -1; } } } } } /* =============== Menu_GetFocused =============== */ menuDef_t *Menu_GetFocused(void) { int i; for (i = 0; i < menuCount; i++) { if ((Menus[i].window.flags & WINDOW_HASFOCUS) && (Menus[i].window.flags & WINDOW_VISIBLE)) { return &Menus[i]; } } return NULL; } /* =============== Menus_OpenByName =============== */ void Menus_OpenByName(const char *p) { Menus_ActivateByName(p); } /* =============== Menus_FindByName =============== */ menuDef_t *Menus_FindByName(const char *p) { int i; for (i = 0; i < menuCount; i++) { if (Q_stricmp(Menus[i].window.name, p) == 0) { return &Menus[i]; } } return NULL; } /* =============== Menu_RunCloseScript =============== */ static void Menu_RunCloseScript(menuDef_t *menu) { if (menu && menu->window.flags & WINDOW_VISIBLE && menu->onClose) { itemDef_t item; item.parent = menu; Item_RunScript(&item, menu->onClose); } } /* =============== Item_ActivateByName =============== */ void Item_ActivateByName(const char *menuName,const char *itemName) { itemDef_t *item; menuDef_t *menu; menu = Menus_FindByName(menuName); item = (itemDef_s *) Menu_FindItemByName((menuDef_t *) menu, itemName); if (item != NULL) { item->window.flags &= ~WINDOW_INACTIVE; } } /* =============== Menus_CloseByName =============== */ void Menus_CloseByName(const char *p) { menuDef_t *menu = Menus_FindByName(p); // If the menu wasnt found just exit if (menu == NULL) { return; } // Run the close script for the menu Menu_RunCloseScript(menu); // If this window had the focus then take it away if ( menu->window.flags & WINDOW_HASFOCUS ) { // If there is something still in the open menu list then // set it to have focus now if ( openMenuCount ) { // Subtract one from the open menu count to prepare to // remove the top menu from the list openMenuCount -= 1; // Set the top menu to have focus now menuStack[openMenuCount]->window.flags |= WINDOW_HASFOCUS; // Remove the top menu from the list menuStack[openMenuCount] = NULL; } } // Window is now invisible and doenst have focus menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS); } /* =============== Menu_FindItemByName =============== */ itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) { int i; if (menu == NULL || p == NULL) { return NULL; } for (i = 0; i < menu->itemCount; i++) { if (Q_stricmp(p, menu->items[i]->window.name) == 0) { return menu->items[i]; } } return NULL; } /* ================= Menu_ClearFocus ================= */ itemDef_t *Menu_ClearFocus(menuDef_t *menu) { int i; itemDef_t *ret = NULL; if (menu == NULL) { return NULL; } for (i = 0; i < menu->itemCount; i++) { if (menu->items[i]->window.flags & WINDOW_HASFOCUS) { ret = menu->items[i]; menu->items[i]->window.flags &= ~WINDOW_HASFOCUS; if (menu->items[i]->leaveFocus) { Item_RunScript(menu->items[i], menu->items[i]->leaveFocus); } } } return ret; } // Set all the items within a given menu, with the given itemName, to the given shader void Menu_SetItemBackground(const menuDef_t *menu,const char *itemName, const char *background) { itemDef_t *item; int j, count; if (!menu) // No menu??? { return; } count = Menu_ItemsMatchingGroup( (menuDef_t *) menu, itemName); for (j = 0; j < count; j++) { item = Menu_GetMatchingItemByNumber( (menuDef_t *) menu, j, itemName); if (item != NULL) { // item->window.background = DC->registerShaderNoMip(background); item->window.background = ui.R_RegisterShaderNoMip(background); } } } // Set all the items within a given menu, with the given itemName, to the given text void Menu_SetItemText(const menuDef_t *menu,const char *itemName, const char *text) { itemDef_t *item; int j, count; if (!menu) // No menu??? { return; } count = Menu_ItemsMatchingGroup( (menuDef_t *) menu, itemName); for (j = 0; j < count; j++) { item = Menu_GetMatchingItemByNumber( (menuDef_t *) menu, j, itemName); if (item != NULL) { if (text[0] == '*') { item->cvar = text+1; // Just copying what was in ItemParse_cvar() if ( item->typeData) { editFieldDef_t *editPtr; editPtr = (editFieldDef_t*)item->typeData; editPtr->minVal = -1; editPtr->maxVal = -1; editPtr->defVal = -1; } } else { if (item->type == ITEM_TYPE_TEXTSCROLL ) { char cvartext[1024]; textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; if ( scrollPtr ) { scrollPtr->startPos = 0; scrollPtr->endPos = 0; } if (item->cvar) { DC->getCVarString(item->cvar, cvartext, sizeof(cvartext)); item->text = cvartext; } else { item->text = (char *) text; } Item_TextScroll_BuildLines ( item ); } else { item->text = (char *) text; } } } } } /* ================= Menu_TransitionItemByName ================= */ void Menu_TransitionItemByName(menuDef_t *menu, const char *p, const rectDef_t *rectFrom, const rectDef_t *rectTo, int time, float amt) { itemDef_t *item; int i; int count = Menu_ItemsMatchingGroup(menu, p); for (i = 0; i < count; i++) { item = Menu_GetMatchingItemByNumber(menu, i, p); if (item != NULL) { if (!rectFrom) { rectFrom = &item->window.rect; //if there are more than one of these with the same name, they'll all use the FIRST one's FROM. } item->window.flags |= (WINDOW_INTRANSITION | WINDOW_VISIBLE); item->window.offsetTime = time; memcpy(&item->window.rectClient, rectFrom, sizeof(rectDef_t)); memcpy(&item->window.rectEffects, rectTo, sizeof(rectDef_t)); item->window.rectEffects2.x = abs(rectTo->x - rectFrom->x) / amt; item->window.rectEffects2.y = abs(rectTo->y - rectFrom->y) / amt; item->window.rectEffects2.w = abs(rectTo->w - rectFrom->w) / amt; item->window.rectEffects2.h = abs(rectTo->h - rectFrom->h) / amt; Item_UpdatePosition(item); } } } /* ================= Menu_TransitionItemByName ================= */ //JLF MOVED #define _TRANS3 #ifdef _TRANS3 void Menu_Transition3ItemByName(menuDef_t *menu, const char *p, const float minx, const float miny, const float minz, const float maxx, const float maxy, const float maxz, const float fovtx, const float fovty, const int time, const float amt) { itemDef_t *item; int i; int count = Menu_ItemsMatchingGroup(menu, p); modelDef_t * modelptr; for (i = 0; i < count; i++) { item = Menu_GetMatchingItemByNumber(menu, i, p); if (item != NULL) { if ( item->type == ITEM_TYPE_MODEL) { modelptr = (modelDef_t*)item->typeData; item->window.flags |= (WINDOW_INTRANSITIONMODEL | WINDOW_VISIBLE); item->window.offsetTime = time; modelptr->fov_x2 = fovtx; modelptr->fov_y2 = fovty; VectorSet(modelptr->g2maxs2, maxx, maxy, maxz); VectorSet(modelptr->g2mins2, minx, miny, minz); // //modelptr->g2maxs2.x= maxx; // modelptr->g2maxs2.y= maxy; // modelptr->g2maxs2.z= maxz; // modelptr->g2mins2.x= minx; // modelptr->g2mins2.y= miny; // modelptr->g2mins2.z= minz; // VectorSet(modelptr->g2maxs2, maxx, maxy, maxz); modelptr->g2maxsEffect[0] = abs(modelptr->g2maxs2[0] - modelptr->g2maxs[0]) / amt; modelptr->g2maxsEffect[1] = abs(modelptr->g2maxs2[1] - modelptr->g2maxs[1]) / amt; modelptr->g2maxsEffect[2] = abs(modelptr->g2maxs2[2] - modelptr->g2maxs[2]) / amt; modelptr->g2minsEffect[0] = abs(modelptr->g2mins2[0] - modelptr->g2mins[0]) / amt; modelptr->g2minsEffect[1] = abs(modelptr->g2mins2[1] - modelptr->g2mins[1]) / amt; modelptr->g2minsEffect[2] = abs(modelptr->g2mins2[2] - modelptr->g2mins[2]) / amt; modelptr->fov_Effectx = abs(modelptr->fov_x2 - modelptr->fov_x) / amt; modelptr->fov_Effecty = abs(modelptr->fov_y2 - modelptr->fov_y) / amt; } } } } #endif /* ================= Menu_OrbitItemByName ================= */ void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) { itemDef_t *item; int i; int count = Menu_ItemsMatchingGroup(menu, p); for (i = 0; i < count; i++) { item = Menu_GetMatchingItemByNumber(menu, i, p); if (item != NULL) { item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE); item->window.offsetTime = time; item->window.rectEffects.x = cx; item->window.rectEffects.y = cy; item->window.rectClient.x = x; item->window.rectClient.y = y; Item_UpdatePosition(item); } } } void Menu_ItemDisable(menuDef_t *menu, const char *name, qboolean disableFlag) { int j,count; itemDef_t *itemFound; count = Menu_ItemsMatchingGroup(menu, name); // Loop through all items that have this name for (j = 0; j < count; j++) { itemFound = Menu_GetMatchingItemByNumber( menu, j, name); if (itemFound != NULL) { itemFound->disabled = disableFlag; // Just in case it had focus itemFound->window.flags &= ~WINDOW_MOUSEOVER; } } } /* ================= Rect_Parse ================= */ qboolean Rect_Parse(const char **p, rectDef_t *r) { if (!COM_ParseFloat(p, &r->x)) { if (!COM_ParseFloat(p, &r->y)) { if (!COM_ParseFloat(p, &r->w)) { if (!COM_ParseFloat(p, &r->h)) { return qtrue; } } } } return qfalse; } qboolean Script_SetItemRect(itemDef_t *item, const char **args) { const char *itemname; rectDef_t *out; rectDef_t rect; // expecting type of color to set and 4 args for the color if (String_Parse(args, &itemname)) { itemDef_t *item2; int j; int count = Menu_ItemsMatchingGroup((menuDef_t *) item->parent, itemname); if (!Rect_Parse(args, &rect)) { return qtrue; } for (j = 0; j < count; j++) { item2 = Menu_GetMatchingItemByNumber((menuDef_t *) item->parent, j, itemname); if (item2 != NULL) { out = &item2->window.rect; if (out) { item2->window.rect.x = rect.x; item2->window.rect.y = rect.y; item2->window.rect.w = rect.w; item2->window.rect.h = rect.h; } } } } return qtrue; } /* ================= Script_SetItemBackground ================= */ qboolean Script_SetItemBackground(itemDef_t *item, const char **args) { const char *itemName; const char *name; // expecting name of shader if (String_Parse(args, &itemName) && String_Parse(args, &name)) { Menu_SetItemBackground((menuDef_t *) item->parent, itemName, name); } return qtrue; } /* ================= Script_SetItemText ================= */ qboolean Script_SetItemText(itemDef_t *item, const char **args) { const char *itemName; const char *text; // expecting text if (String_Parse(args, &itemName) && String_Parse(args, &text)) { Menu_SetItemText((menuDef_t *) item->parent, itemName, text); } return qtrue; } /* ================= Script_FadeIn ================= */ qboolean Script_FadeIn(itemDef_t *item, const char **args) { const char *name; if (String_Parse(args, &name)) { Menu_FadeItemByName((menuDef_t *) item->parent, name, qfalse); } return qtrue; } /* ================= Script_FadeOut ================= */ qboolean Script_FadeOut(itemDef_t *item, const char **args) { const char *name; if (String_Parse(args, &name)) { Menu_FadeItemByName((menuDef_t *) item->parent, name, qtrue); } return qtrue; } /* ================= Script_Show ================= */ qboolean Script_Show(itemDef_t *item, const char **args) { const char *name; if (String_Parse(args, &name)) { Menu_ShowItemByName((menuDef_t *) item->parent, name, qtrue); } return qtrue; } /* ================= Script_ShowMenu ================= */ qboolean Script_ShowMenu(itemDef_t *item, const char **args) { const char *name; if (String_Parse(args, &name)) { Menus_ShowItems(name); } return qtrue; } /* ================= Script_Hide ================= */ qboolean Script_Hide(itemDef_t *item, const char **args) { const char *name; if (String_Parse(args, &name)) { Menu_ShowItemByName((menuDef_t *) item->parent, name, qfalse); } return qtrue; } /* ================= Script_SetColor ================= */ qboolean Script_SetColor(itemDef_t *item, const char **args) { const char *name; int i; float f; vec4_t *out; // expecting type of color to set and 4 args for the color if (String_Parse(args, &name)) { out = NULL; if (Q_stricmp(name, "backcolor") == 0) { out = &item->window.backColor; item->window.flags |= WINDOW_BACKCOLORSET; } else if (Q_stricmp(name, "forecolor") == 0) { out = &item->window.foreColor; item->window.flags |= WINDOW_FORECOLORSET; } else if (Q_stricmp(name, "bordercolor") == 0) { out = &item->window.borderColor; } if (out) { for (i = 0; i < 4; i++) { // if (!Float_Parse(args, &f)) if (COM_ParseFloat( args, &f)) { return qtrue; } (*out)[i] = f; } } } return qtrue; } /* ================= Script_Open ================= */ qboolean Script_Open(itemDef_t *item, const char **args) { const char *name; if (String_Parse(args, &name)) { Menus_OpenByName(name); } return qtrue; } qboolean Script_OpenGoToMenu(itemDef_t *item, const char **args) { Menus_OpenByName(GoToMenu); // Give warning return qtrue; } /* ================= Script_Close ================= */ qboolean Script_Close(itemDef_t *item, const char **args) { const char *name; if (String_Parse(args, &name)) { if (Q_stricmp(name, "all") == 0) { Menus_CloseAll(); } else { Menus_CloseByName(name); } } return qtrue; } /* ================= Script_Activate ================= */ qboolean Script_Activate(itemDef_t *item, const char **args) { const char *name, *menu; if (String_Parse(args, &menu)) { if (String_Parse(args, &name)) { Item_ActivateByName(menu,name); } } return qtrue; } /* ================= Script_SetBackground ================= */ qboolean Script_SetBackground(itemDef_t *item, const char **args) { const char *name; // expecting name to set asset to if (String_Parse(args, &name)) { item->window.background = DC->registerShaderNoMip(name); } return qtrue; } /* ================= Script_SetAsset ================= */ qboolean Script_SetAsset(itemDef_t *item, const char **args) { const char *name; // expecting name to set asset to if (String_Parse(args, &name)) { // check for a model if (item->type == ITEM_TYPE_MODEL) { } } return qtrue; } /* ================= Script_SetFocus ================= */ qboolean Script_SetFocus(itemDef_t *item, const char **args) { const char *name; itemDef_t *focusItem; if (String_Parse(args, &name)) { focusItem = (itemDef_s *) Menu_FindItemByName((menuDef_t *) item->parent, name); if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION) && !(focusItem->window.flags & WINDOW_HASFOCUS)) { Menu_ClearFocus((menuDef_t *) item->parent); //JLF focusItem->window.flags |= WINDOW_HASFOCUS; //END JLF if (focusItem->onFocus) { Item_RunScript(focusItem, focusItem->onFocus); } if (DC->Assets.itemFocusSound) { DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND ); } } } return qtrue; } /* ================= Script_SetItemFlag ================= */ qboolean Script_SetItemFlag(itemDef_t *item, const char **args) { const char *itemName,*number; if (String_Parse(args, &itemName)) { item = (itemDef_s *) Menu_FindItemByName((menuDef_t *) item->parent, itemName); if (String_Parse(args, &number)) { int amount = atoi(number); item->window.flags |= amount; } } return qtrue; } void UI_SetItemVisible(menuDef_t *menu,const char *itemname,qboolean visible) { itemDef_t *item; int j; int count = Menu_ItemsMatchingGroup(menu, itemname); for (j = 0; j < count; j++) { item = Menu_GetMatchingItemByNumber(menu, j, itemname); if (item != NULL) { if (visible==qtrue) { item->window.flags |= WINDOW_VISIBLE; } else { item->window.flags &= ~WINDOW_VISIBLE; } } } } void UI_SetItemColor(itemDef_t *item,const char *itemname,const char *name,vec4_t color) { itemDef_t *item2; int i,j; vec4_t *out; int count = Menu_ItemsMatchingGroup((menuDef_t *) item->parent, itemname); for (j = 0; j < count; j++) { item2 = Menu_GetMatchingItemByNumber((menuDef_t *) item->parent, j, itemname); if (item2 != NULL) { out = NULL; if (Q_stricmp(name, "backcolor") == 0) { out = &item2->window.backColor; } else if (Q_stricmp(name, "forecolor") == 0) { out = &item2->window.foreColor; item2->window.flags |= WINDOW_FORECOLORSET; } else if (Q_stricmp(name, "bordercolor") == 0) { out = &item2->window.borderColor; } if (out) { for (i = 0; i < 4; i++) { (*out)[i] = color[i]; } } } } } /* ================= Script_SetItemColor ================= */ qboolean Script_SetItemColor(itemDef_t *item, const char **args) { const char *itemname; const char *name; vec4_t color; // expecting type of color to set and 4 args for the color if (String_Parse(args, &itemname) && String_Parse(args, &name)) { if (COM_ParseVec4(args, &color)) { return qtrue; } UI_SetItemColor(item,itemname,name,color); } return qtrue; } /* ================= Script_Defer Defers the rest of the script based on the defer condition. The deferred portion of the script can later be run with the "rundeferred" ================= */ qboolean Script_Defer ( itemDef_t* item, const char **args ) { // Should the script be deferred? if ( DC->deferScript ( args ) ) { // Need the item the script was being run on uiInfo.deferredScriptItem = item; // Save the rest of the script Q_strncpyz ( uiInfo.deferredScript, *args, MAX_DEFERRED_SCRIPT ); // No more running return qfalse; } // Keep running the script, its ok return qtrue; } /* ================= Script_RunDeferred Runs the last deferred script, there can only be one script deferred at a time so be careful of recursion ================= */ qboolean Script_RunDeferred ( itemDef_t* item, const char **args ) { // Make sure there is something to run. if ( !uiInfo.deferredScript[0] || !uiInfo.deferredScriptItem ) { return qtrue; } // Run the deferred script now Item_RunScript ( uiInfo.deferredScriptItem, uiInfo.deferredScript ); return qtrue; } /* ================= Script_Delay Delays the rest of the script for the specified amount of time ================= */ qboolean Script_Delay ( itemDef_t* item, const char **args ) { int time; if (Int_Parse(args, &time)) { item->window.flags |= WINDOW_SCRIPTWAITING; item->window.delayTime = DC->realTime + time; // Flag to set delay time on next paint item->window.delayedScript = (char *)*args; // Copy current location, we'll resume executing here later } else { Com_Printf(S_COLOR_YELLOW"WARNING: Script_Delay: error parsing\n" ); } // Stop running return qfalse; } /* ================= Script_Transition transition rtvscr 321 0 202 264 415 0 202 264 20 25 ================= */ qboolean Script_Transition(itemDef_t *item, const char **args) { const char *name; rectDef_t rectFrom, rectTo; int time; float amt; if (String_Parse(args, &name)) { if ( ParseRect(args, &rectFrom) && ParseRect(args, &rectTo) && Int_Parse(args, &time) && !COM_ParseFloat(args, &amt)) { Menu_TransitionItemByName((menuDef_t *) item->parent, name, &rectFrom, &rectTo, time, amt); } else { Com_Printf(S_COLOR_YELLOW"WARNING: Script_Transition: error parsing '%s'\n", name ); } } return qtrue; } /* ================= Script_Transition2 uses current origin instead of specifing a starting origin transition2 lfvscr 25 0 202 264 20 25 ================= */ qboolean Script_Transition2(itemDef_t *item, const char **args) { const char *name; rectDef_t rectTo; int time; float amt; if (String_Parse(args, &name)) { if ( ParseRect(args, &rectTo) && Int_Parse(args, &time) && !COM_ParseFloat(args, &amt)) { Menu_TransitionItemByName((menuDef_t *) item->parent, name, 0, &rectTo, time, amt); } else { Com_Printf(S_COLOR_YELLOW"WARNING: Script_Transition2: error parsing '%s'\n", name ); } } return qtrue; } #ifdef _TRANS3 /* JLF MPMOVED ================= Script_Transition3 used exclusively with model views uses current origin instead of specifing a starting origin transition3 lfvscr (min extent) (max extent) (fovx,y) 20 25 ================= */ qboolean Script_Transition3(itemDef_t *item, const char **args) { const char *name = NULL; const char *value = NULL; float minx, miny, minz, maxx, maxy, maxz, fovtx, fovty; int time; float amt; if (String_Parse(args, &name)) { if (String_Parse( args, &value)) { minx = atof(value); if (String_Parse( args, &value)) { miny = atof(value); if (String_Parse( args, &value)) { minz = atof(value); if (String_Parse( args, &value)) { maxx = atof(value); if (String_Parse( args, &value)) { maxy = atof(value); if (String_Parse( args, &value)) { maxz = atof(value); if (String_Parse( args, &value)) { fovtx = atof(value); if (String_Parse( args, &value)) { fovty = atof(value); if (String_Parse( args, &value)) { time = atoi(value); if (String_Parse( args, &value)) { amt = atof(value); //set up the variables Menu_Transition3ItemByName((menuDef_t *) item->parent, name, minx, miny, minz, maxx, maxy, maxz, fovtx, fovty, time, amt); return qtrue; } } } } } } } } } } } if ( name ) { Com_Printf( S_COLOR_YELLOW "WARNING: Script_Transition2: error parsing '%s'\n", name ); } return qtrue; } #endif //only works on some feeders int GetCurrentFeederIndex(itemDef_t * item) { float feederID = item->special; const char * name; int i, max; if (feederID == FEEDER_PLAYER_SPECIES) { return uiInfo.playerSpeciesIndex; } if (feederID == FEEDER_PLAYER_SKIN_HEAD) { name = Cvar_VariableString("ui_char_skin_head"); max = uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinHeadCount; for ( i = 0; i < max ; i++) { if (!Q_stricmp(name, uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinHead[i].name)) { return i; } // Cvar_Set("ui_char_skin_head", uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinHeadNames[index]); } return -1; } else if (feederID == FEEDER_PLAYER_SKIN_TORSO) { name = Cvar_VariableString("ui_char_skin_torso"); max = uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinTorsoCount; for ( i = 0; i < max ; i++) { if (!Q_stricmp(name, uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinTorso[i].name)) { return i; } // Cvar_Set("ui_char_skin_head", uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinHeadNames[index]); } return -1; } else if (feederID == FEEDER_PLAYER_SKIN_LEGS) { name = Cvar_VariableString("ui_char_skin_legs"); max = uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinLegCount; for ( i = 0; i < max ; i++) { if (!Q_stricmp(name, uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinLeg[i].name)) { return i; } // Cvar_Set("ui_char_skin_head", uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinHeadNames[index]); } return -1; // if (index >= 0 && index < uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinLegCount) // { // Cvar_Set("ui_char_skin_legs", uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinLegNames[index]); // } } else if (feederID == FEEDER_COLORCHOICES) { extern void Item_RunScript(itemDef_t *item, const char *s); //from ui_shared; int currR, currG, currB, newR, newG, newB; currR = Cvar_VariableIntegerValue( "ui_char_color_red"); currG = Cvar_VariableIntegerValue( "ui_char_color_green"); currB = Cvar_VariableIntegerValue( "ui_char_color_blue"); max = uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].ColorCount; for ( i = 0; i < max ; i++) { Item_RunScript(item, uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].Color[i].actionText); newR = Cvar_VariableIntegerValue( "ui_char_color_red"); newG = Cvar_VariableIntegerValue( "ui_char_color_green"); newB = Cvar_VariableIntegerValue( "ui_char_color_blue"); if ( currR == newR && currG == newG && currB == newB) return i; } return -1; //JLF junk copied code /* extern void Item_RunScript(itemDef_t *item, const char *s); //from ui_shared; name = Cvar_VariableString("ui_char_skin_legs"); max = uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].ColorCount; for ( i = 0; i < max ; i++) if (!qstrcmp(name, uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinLegNames[i])) { return i; // Cvar_Set("ui_char_skin_head", uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].SkinHeadNames[index]); } return -1; if (index >= 0 && index < uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].ColorCount) { Item_RunScript(item, uiInfo.playerSpecies[uiInfo.playerSpeciesIndex].ColorActionText[index]); } */ } return -1; } qboolean Script_IncrementFeeder(itemDef_t * item, const char ** args) { int feedercount = uiInfo.uiDC.feederCount(item->special); int value = GetCurrentFeederIndex(item); value++; if ( value >= feedercount) value = 0; DC->feederSelection(item->special, value, item); return qtrue; } qboolean Script_DecrementFeeder(itemDef_t * item, const char ** args) { int feedercount = uiInfo.uiDC.feederCount(item->special); int value = GetCurrentFeederIndex(item); value--; if ( value < 0) value = feedercount-1; DC->feederSelection(item->special, value, item); return qtrue; } /* ================= Script_SetCvar ================= */ qboolean Script_SetCvar(itemDef_t *item, const char **args) { const char *cvar, *val; if (String_Parse(args, &cvar) && String_Parse(args, &val)) { if(!Q_stricmp(val,"(NULL)")) { DC->setCVar(cvar, ""); } else { DC->setCVar(cvar, val); } } return qtrue; } /* ================= Script_Exec ================= */ qboolean Script_Exec ( itemDef_t *item, const char **args) { const char *val; if (String_Parse(args, &val)) { DC->executeText(EXEC_APPEND, va("%s ; ", val)); } return qtrue; } /* ================= Script_Play ================= */ static qboolean Script_Play(itemDef_t *item, const char **args) { const char *val; if (String_Parse(args, &val)) { DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_AUTO ); } return qtrue; } /* ================= Script_PlayVoice ================= */ static qboolean Script_PlayVoice(itemDef_t *item, const char **args) { const char *val; if (String_Parse(args, &val)) { DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_VOICE ); } return qtrue; } /* ================= Script_StopVoice ================= */ static qboolean Script_StopVoice(itemDef_t *item, const char **args) { DC->startLocalSound(uiInfo.uiDC.Assets.nullSound, CHAN_VOICE ); return qtrue; } /* ================= Script_playLooped ================= */ /* qboolean Script_playLooped(itemDef_t *item, const char **args) { const char *val; if (String_Parse(args, &val)) { // FIXME BOB - is this needed? DC->stopBackgroundTrack(); DC->startBackgroundTrack(val, val); } return qtrue; } */ /* ================= Script_Orbit ================= */ qboolean Script_Orbit(itemDef_t *item, const char **args) { const char *name; float cx, cy, x, y; int time; if (String_Parse(args, &name)) { // if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) if ( !COM_ParseFloat(args, &x) && !COM_ParseFloat(args, &y) && !COM_ParseFloat(args, &cx) && !COM_ParseFloat(args, &cy) && Int_Parse(args, &time) ) { Menu_OrbitItemByName((menuDef_t *) item->parent, name, x, y, cx, cy, time); } } return qtrue; } commandDef_t commandList[] = { {"activate", &Script_Activate}, // menu {"close", &Script_Close}, // menu {"exec", &Script_Exec}, // group/name {"fadein", &Script_FadeIn}, // group/name {"fadeout", &Script_FadeOut}, // group/name {"hide", &Script_Hide}, // group/name {"open", &Script_Open}, // menu {"openGoToMenu", &Script_OpenGoToMenu}, // {"orbit", &Script_Orbit}, // group/name {"play", &Script_Play}, // group/name {"playVoice", &Script_PlayVoice}, // group/name {"stopVoice", &Script_StopVoice}, // group/name // {"playlooped", &Script_playLooped}, // group/name {"setasset", &Script_SetAsset}, // works on this {"setbackground", &Script_SetBackground}, // works on this {"setcolor", &Script_SetColor}, // works on this {"setcvar", &Script_SetCvar}, // group/name {"setfocus", &Script_SetFocus}, // sets this background color to team color {"setitemcolor", &Script_SetItemColor}, // group/name {"setitemflag", &Script_SetItemFlag}, // name {"show", &Script_Show}, // group/name {"showMenu", &Script_ShowMenu}, // menu {"transition", &Script_Transition}, // group/name {"transition2", &Script_Transition2}, // group/name {"setitembackground", &Script_SetItemBackground}, // group/name {"setitemtext", &Script_SetItemText}, // group/name {"setitemrect", &Script_SetItemRect}, // group/name {"defer", &Script_Defer}, // {"rundeferred", &Script_RunDeferred}, // {"delay", &Script_Delay}, // works on this (script) {"transition3", &Script_Transition3}, // model exclusive transition {"incrementfeeder", &Script_IncrementFeeder}, {"decrementfeeder", &Script_DecrementFeeder} }; int scriptCommandCount = sizeof(commandList) / sizeof(commandDef_t); /* =============== Item_Init =============== */ void Item_Init(itemDef_t *item) { memset(item, 0, sizeof(itemDef_t)); item->textscale = 0.55f; Window_Init(&item->window); } /* =============== Item_Multi_Setting =============== */ const char *Item_Multi_Setting(itemDef_t *item) { char buff[1024]; float value = 0; int i; multiDef_t *multiPtr = (multiDef_t*)item->typeData; if (multiPtr) { if (multiPtr->strDef) { if (item->cvar) { DC->getCVarString(item->cvar, buff, sizeof(buff)); } else { } } else { if (item->cvar) // Was a cvar given? { value = DC->getCVarValue(item->cvar); } else { value = item->value; } } for (i = 0; i < multiPtr->count; i++) { if (multiPtr->strDef) { if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) { return multiPtr->cvarList[i]; } } else { if (multiPtr->cvarValue[i] == value) { return multiPtr->cvarList[i]; } } } } #ifdef JK2_MODE return "@MENUS1_CUSTOM"; #else return "@MENUS_CUSTOM"; #endif } //--------------------------------------------------------------------------------------------------------- // Item Keyword Parse functions //--------------------------------------------------------------------------------------------------------- /* =============== ItemParse_name name =============== */ qboolean ItemParse_name( itemDef_t *item) { if (!PC_ParseStringMem((const char **)&item->window.name)) { return qfalse; } return qtrue; } qboolean ItemParse_font( itemDef_t *item ) { if (PC_ParseInt(&item->font)) { return qfalse; } return qtrue; } /* =============== ItemParse_focusSound name =============== */ qboolean ItemParse_focusSound( itemDef_t *item) { const char *temp; if (PC_ParseString(&temp)) { return qfalse; } item->focusSound = DC->registerSound(temp, qfalse); return qtrue; } /* =============== ItemParse_text text =============== */ qboolean ItemParse_text( itemDef_t *item) { if (!PC_ParseStringMem((const char **) &item->text)) { return qfalse; } //#ifdef _DEBUG // UI_Debug_EnterReference("TEXT", item->text); //#endif return qtrue; } /* =============== ItemParse_descText text =============== */ qboolean ItemParse_descText( itemDef_t *item) { if (!PC_ParseStringMem((const char **) &item->descText)) { return qfalse; } //#ifdef _DEBUG // UI_Debug_EnterReference("DESC", item->descText); //#endif return qtrue; } /* =============== ItemParse_text text =============== */ qboolean ItemParse_text2( itemDef_t *item) { if (!PC_ParseStringMem((const char **) &item->text2)) { return qfalse; } //#ifdef _DEBUG // UI_Debug_EnterReference("TXT2", item->text2); //#endif return qtrue; } /* =============== ItemParse_group group =============== */ qboolean ItemParse_group( itemDef_t *item) { if (!PC_ParseStringMem((const char **)&item->window.group)) { return qfalse; } return qtrue; } /* =============== ItemParse_asset_model asset_model =============== */ qboolean ItemParse_asset_model_go( itemDef_t *item, const char *name ) { modelDef_t *modelPtr; Item_ValidateTypeData(item); modelPtr = (modelDef_t*)item->typeData; if (!Q_stricmp(&name[strlen(name) - 4], ".glm")) { //it's a ghoul2 model then if ( item->ghoul2.size() && item->ghoul2[0].mModelindex >= 0) { DC->g2_RemoveGhoul2Model( item->ghoul2, 0 ); item->flags &= ~ITF_G2VALID; } int g2Model = DC->g2_InitGhoul2Model(item->ghoul2, name, 0, 0, 0, 0, 0); if (g2Model >= 0) { item->flags |= ITF_G2VALID; if (modelPtr->g2anim) { //does the menu request this model be playing an animation? DC->g2hilev_SetAnim(&item->ghoul2[0], "model_root", modelPtr->g2anim, qfalse); } if ( modelPtr->g2skin ) { DC->g2_SetSkin( &item->ghoul2[0], 0, modelPtr->g2skin );//this is going to set the surfs on/off matching the skin file } } } else if(!(item->asset)) { //guess it's just an md3 item->asset = DC->registerModel(name); item->flags &= ~ITF_G2VALID; } return qtrue; } qboolean ItemParse_asset_model( itemDef_t *item ) { const char *temp; Item_ValidateTypeData(item); if (PC_ParseString(&temp)) { return qfalse; } char modelPath[MAX_QPATH]; if (!Q_stricmp(temp,"ui_char_model") ) { Com_sprintf( modelPath, sizeof( modelPath ), "models/players/%s/model.glm", Cvar_VariableString ( "g_char_model" ) ); } else { Com_sprintf( modelPath, sizeof( modelPath ), temp); } return (ItemParse_asset_model_go( item, modelPath )); } /* =============== ItemParse_asset_model asset_shader =============== */ qboolean ItemParse_asset_shader( itemDef_t *item) { const char *temp; if (PC_ParseString(&temp)) { return qfalse; } item->asset = DC->registerShaderNoMip(temp); return qtrue; } /* =============== ItemParse_asset_model model_origin =============== */ qboolean ItemParse_model_origin( itemDef_t *item) { modelDef_t *modelPtr; Item_ValidateTypeData(item); modelPtr = (modelDef_t*)item->typeData; if (PC_ParseFloat(&modelPtr->origin[0])) { if (PC_ParseFloat(&modelPtr->origin[1])) { if (PC_ParseFloat(&modelPtr->origin[2])) { return qtrue; } } } return qfalse; } /* =============== ItemParse_model_fovx model_fovx =============== */ qboolean ItemParse_model_fovx( itemDef_t *item) { modelDef_t *modelPtr; Item_ValidateTypeData(item); modelPtr = (modelDef_t*)item->typeData; if (PC_ParseFloat(&modelPtr->fov_x)) { return qfalse; } return qtrue; } /* =============== ItemParse_model_fovy model_fovy =============== */ qboolean ItemParse_model_fovy( itemDef_t *item) { modelDef_t *modelPtr; Item_ValidateTypeData(item); modelPtr = (modelDef_t*)item->typeData; if (PC_ParseFloat(&modelPtr->fov_y)) { return qfalse; } return qtrue; } /* =============== ItemParse_model_rotation model_rotation =============== */ qboolean ItemParse_model_rotation( itemDef_t *item) { modelDef_t *modelPtr; Item_ValidateTypeData(item); modelPtr = (modelDef_t*)item->typeData; if (PC_ParseInt(&modelPtr->rotationSpeed)) { return qfalse; } return qtrue; } /* =============== ItemParse_model_angle model_angle =============== */ qboolean ItemParse_model_angle( itemDef_t *item) { modelDef_t *modelPtr; Item_ValidateTypeData(item); modelPtr = (modelDef_t*)item->typeData; if (PC_ParseInt(&modelPtr->angle)) { return qfalse; } return qtrue; } // model_g2mins qboolean ItemParse_model_g2mins( itemDef_t *item ) { modelDef_t *modelPtr; Item_ValidateTypeData(item); modelPtr = (modelDef_t*)item->typeData; if (!PC_ParseFloat(&modelPtr->g2mins[0])) { if (!PC_ParseFloat(&modelPtr->g2mins[1])) { if (!PC_ParseFloat(&modelPtr->g2mins[2])) { return qtrue; } } } return qfalse; } // model_g2maxs qboolean ItemParse_model_g2maxs( itemDef_t *item ) { modelDef_t *modelPtr; Item_ValidateTypeData(item); modelPtr = (modelDef_t*)item->typeData; if (!PC_ParseFloat(&modelPtr->g2maxs[0])) { if (!PC_ParseFloat(&modelPtr->g2maxs[1])) { if (!PC_ParseFloat(&modelPtr->g2maxs[2])) { return qtrue; } } } return qfalse; } // model_g2skin qboolean ItemParse_model_g2skin_go( itemDef_t *item, const char *skinName ) { modelDef_t *modelPtr; Item_ValidateTypeData(item); modelPtr = (modelDef_t*)item->typeData; if (!skinName || !skinName[0]) { //it was parsed cor~rectly so still return true. modelPtr->g2skin = 0; DC->g2_SetSkin( &item->ghoul2[0], -1, 0 );//turn off custom skin return qtrue; } modelPtr->g2skin = DC->registerSkin(skinName); if ( item->ghoul2.IsValid() ) { DC->g2_SetSkin( &item->ghoul2[0], 0, modelPtr->g2skin );//this is going to set the surfs on/off matching the skin file } return qtrue; } qboolean ItemParse_model_g2skin( itemDef_t *item ) { const char *skinName; if (PC_ParseString(&skinName)) { return qfalse; } return (ItemParse_model_g2skin_go( item, skinName )); } // model_g2anim qboolean ItemParse_model_g2anim_go( itemDef_t *item, const char *animName ) { modelDef_t *modelPtr; int i = 0; Item_ValidateTypeData(item); modelPtr = (modelDef_t*)item->typeData; if (!animName || !animName[0]) { //it was parsed correctly so still return true. return qtrue; } while (i < MAX_ANIMATIONS) { if (!Q_stricmp(animName, animTable[i].name)) { //found it modelPtr->g2anim = animTable[i].id; return qtrue; } i++; } Com_Printf("Could not find '%s' in the anim table\n", animName); return qtrue; } qboolean ItemParse_model_g2anim( itemDef_t *item ) { const char *animName; if (PC_ParseString(&animName)) { return qfalse; } return ItemParse_model_g2anim_go( item, animName ); } /* =============== ItemParse_rect rect =============== */ qboolean ItemParse_rect( itemDef_t *item) { if (!PC_ParseRect(&item->window.rectClient)) { return qfalse; } return qtrue; } /* =============== ItemParse_flag flag =============== */ qboolean ItemParse_flag( itemDef_t *item) { int i; const char *tempStr; if (PC_ParseString(&tempStr)) { return qfalse; } i=0; while (itemFlags[i].string) { if (Q_stricmp(tempStr,itemFlags[i].string)==0) { item->window.flags |= itemFlags[i].value; break; } i++; } if (itemFlags[i].string == NULL) { PC_ParseWarning(va("Unknown item flag value '%s'",tempStr)); } return qtrue; } /* =============== ItemParse_style style =============== */ qboolean ItemParse_style( itemDef_t *item) { int i; const char *tempStr; if (PC_ParseString(&tempStr)) { return qfalse; } i=0; while (styles[i]) { if (Q_stricmp(tempStr,styles[i])==0) { item->window.style = i; break; } i++; } if (styles[i] == NULL) { PC_ParseWarning(va("Unknown item style value '%s'",tempStr)); } return qtrue; } /* =============== ItemParse_decoration decoration =============== */ qboolean ItemParse_decoration( itemDef_t *item ) { item->window.flags |= WINDOW_DECORATION; return qtrue; } /* =============== ItemParse_notselectable notselectable =============== */ qboolean ItemParse_notselectable( itemDef_t *item ) { listBoxDef_t *listPtr; Item_ValidateTypeData(item); listPtr = (listBoxDef_t*)item->typeData; if (item->type == ITEM_TYPE_LISTBOX && listPtr) { listPtr->notselectable = qtrue; } return qtrue; } /* =============== ItemParse_scrollhidden scrollhidden =============== */ qboolean ItemParse_scrollhidden( itemDef_t *item ) { listBoxDef_t *listPtr; Item_ValidateTypeData(item); listPtr = (listBoxDef_t*)item->typeData; if (item->type == ITEM_TYPE_LISTBOX && listPtr) { listPtr->scrollhidden = qtrue; } return qtrue; } /* =============== ItemParse_wrapped manually wrapped =============== */ qboolean ItemParse_wrapped( itemDef_t *item ) { item->window.flags |= WINDOW_WRAPPED; return qtrue; } /* =============== ItemParse_autowrapped auto wrapped =============== */ qboolean ItemParse_autowrapped( itemDef_t *item) { item->window.flags |= WINDOW_AUTOWRAPPED; return qtrue; } /* =============== ItemParse_horizontalscroll horizontalscroll =============== */ qboolean ItemParse_horizontalscroll( itemDef_t *item ) { item->window.flags |= WINDOW_HORIZONTAL; return qtrue; } /* =============== ItemParse_type type =============== */ qboolean ItemParse_type( itemDef_t *item ) { int i; const char *tempStr; if (PC_ParseString(&tempStr)) { return qfalse; } i=0; while (types[i]) { if (Q_stricmp(tempStr,types[i])==0) { item->type = i; break; } i++; } if (types[i] == NULL) { PC_ParseWarning(va("Unknown item type value '%s'",tempStr)); } else { Item_ValidateTypeData(item); } return qtrue; } /* =============== ItemParse_elementwidth elementwidth, used for listbox image elements uses textalignx for storage =============== */ qboolean ItemParse_elementwidth( itemDef_t *item ) { listBoxDef_t *listPtr; Item_ValidateTypeData(item); listPtr = (listBoxDef_t*)item->typeData; if (PC_ParseFloat(&listPtr->elementWidth)) { return qfalse; } return qtrue; } /* =============== ItemParse_elementheight elementheight, used for listbox image elements uses textaligny for storage =============== */ qboolean ItemParse_elementheight( itemDef_t *item ) { listBoxDef_t *listPtr; Item_ValidateTypeData(item); listPtr = (listBoxDef_t*)item->typeData; if (PC_ParseFloat(&listPtr->elementHeight)) { return qfalse; } return qtrue; } /* =============== ItemParse_feeder feeder =============== */ qboolean ItemParse_feeder( itemDef_t *item ) { if (PC_ParseFloat( &item->special)) { return qfalse; } return qtrue; } /* =============== ItemParse_elementtype elementtype, used to specify what type of elements a listbox contains uses textstyle for storage =============== */ qboolean ItemParse_elementtype( itemDef_t *item ) { listBoxDef_t *listPtr; Item_ValidateTypeData(item); if (!item->typeData) { return qfalse; } listPtr = (listBoxDef_t*)item->typeData; if (PC_ParseInt(&listPtr->elementStyle)) { return qfalse; } return qtrue; } /* =============== ItemParse_columns columns sets a number of columns and an x pos and width per.. =============== */ qboolean ItemParse_columns( itemDef_t *item) { int num, i; listBoxDef_t *listPtr; Item_ValidateTypeData(item); if (!item->typeData) { return qfalse; } listPtr = (listBoxDef_t*)item->typeData; if (!PC_ParseInt(&num)) { if (num > MAX_LB_COLUMNS) { num = MAX_LB_COLUMNS; } listPtr->numColumns = num; for (i = 0; i < num; i++) { int pos, width, maxChars; if (!PC_ParseInt(&pos) && !PC_ParseInt(&width) && !PC_ParseInt(&maxChars)) { listPtr->columnInfo[i].pos = pos; listPtr->columnInfo[i].width = width; listPtr->columnInfo[i].maxChars = maxChars; } else { return qfalse; } } } else { return qfalse; } return qtrue; } /* =============== ItemParse_border =============== */ qboolean ItemParse_border( itemDef_t *item) { if (PC_ParseInt(&item->window.border)) { return qfalse; } return qtrue; } /* =============== ItemParse_bordersize =============== */ qboolean ItemParse_bordersize( itemDef_t *item ) { if (PC_ParseFloat(&item->window.borderSize)) { return qfalse; } return qtrue; } /* =============== ItemParse_visible =============== */ qboolean ItemParse_visible( itemDef_t *item) { int i; if (PC_ParseInt(&i)) { return qfalse; } if (i) { item->window.flags |= WINDOW_VISIBLE; } return qtrue; } /* =============== ItemParse_ownerdraw =============== */ qboolean ItemParse_ownerdraw( itemDef_t *item) { if (PC_ParseInt(&item->window.ownerDraw)) { return qfalse; } item->type = ITEM_TYPE_OWNERDRAW; return qtrue; } /* =============== ItemParse_align =============== */ qboolean ItemParse_align( itemDef_t *item) { if (PC_ParseInt(&item->alignment)) { return qfalse; } return qtrue; } /* =============== ItemParse_align =============== */ qboolean ItemParse_Appearance_slot( itemDef_t *item) { if (PC_ParseInt(&item->appearanceSlot)) { return qfalse; } return qtrue; } /* =============== ItemParse_textalign =============== */ qboolean ItemParse_textalign( itemDef_t *item ) { const char *tempStr; int i; if (PC_ParseString(&tempStr)) { return qfalse; } i=0; while (alignment[i]) { if (Q_stricmp(tempStr,alignment[i])==0) { item->textalignment = i; break; } i++; } if (alignment[i] == NULL) { PC_ParseWarning(va("Unknown text alignment value '%s'",tempStr)); } return qtrue; } /* =============== ItemParse_text2alignx =============== */ qboolean ItemParse_text2alignx( itemDef_t *item) { if (PC_ParseFloat(&item->text2alignx)) { return qfalse; } return qtrue; } /* =============== ItemParse_text2aligny =============== */ qboolean ItemParse_text2aligny( itemDef_t *item) { if (PC_ParseFloat(&item->text2aligny)) { return qfalse; } return qtrue; } /* =============== ItemParse_textalignx =============== */ qboolean ItemParse_textalignx( itemDef_t *item) { if (PC_ParseFloat(&item->textalignx)) { return qfalse; } return qtrue; } /* =============== ItemParse_textaligny =============== */ qboolean ItemParse_textaligny( itemDef_t *item) { if (PC_ParseFloat(&item->textaligny)) { return qfalse; } return qtrue; } /* =============== ItemParse_textscale =============== */ qboolean ItemParse_textscale( itemDef_t *item ) { if (PC_ParseFloat(&item->textscale)) { return qfalse; } return qtrue; } /* =============== ItemParse_textstyle =============== */ qboolean ItemParse_textstyle( itemDef_t *item) { if (PC_ParseInt(&item->textStyle)) { return qfalse; } return qtrue; } /* =============== ItemParse_invertyesno =============== */ qboolean ItemParse_invertyesno( itemDef_t *item) { if (PC_ParseInt(&item->invertYesNo)) { return qfalse; } return qtrue; } /* =============== ItemParse_xoffset (used for yes/no and multi) =============== */ qboolean ItemParse_xoffset( itemDef_t *item) { if (PC_ParseInt(&item->xoffset)) { return qfalse; } return qtrue; } /* =============== ItemParse_backcolor =============== */ qboolean ItemParse_backcolor( itemDef_t *item) { int i; float f; for (i = 0; i < 4; i++) { if (PC_ParseFloat(&f)) { return qfalse; } item->window.backColor[i] = f; } return qtrue; } /* =============== ItemParse_forecolor =============== */ qboolean ItemParse_forecolor( itemDef_t *item) { int i; float f; for (i = 0; i < 4; i++) { if (PC_ParseFloat(&f)) { return qfalse; } if (f < 0) { //special case for player color item->window.flags |= WINDOW_PLAYERCOLOR; return qtrue; } item->window.foreColor[i] = f; item->window.flags |= WINDOW_FORECOLORSET; } return qtrue; } /* =============== ItemParse_bordercolor =============== */ qboolean ItemParse_bordercolor( itemDef_t *item) { int i; float f; for (i = 0; i < 4; i++) { if (PC_ParseFloat(&f)) { return qfalse; } item->window.borderColor[i] = f; } return qtrue; } /* =============== ItemParse_outlinecolor =============== */ qboolean ItemParse_outlinecolor( itemDef_t *item) { if (PC_ParseColor(&item->window.outlineColor)) { return qfalse; } return qtrue; } /* =============== ItemParse_background =============== */ qboolean ItemParse_background( itemDef_t *item) { const char *temp; if (PC_ParseString(&temp)) { return qfalse; } item->window.background = ui.R_RegisterShaderNoMip(temp); return qtrue; } /* =============== ItemParse_cinematic =============== */ qboolean ItemParse_cinematic( itemDef_t *item) { if (!PC_ParseStringMem((const char **) &item->window.cinematicName)) { return qfalse; } return qtrue; } /* =============== ItemParse_doubleClick =============== */ qboolean ItemParse_doubleClick( itemDef_t *item) { listBoxDef_t *listPtr; Item_ValidateTypeData(item); if (!item->typeData) { return qfalse; } listPtr = (listBoxDef_t*)item->typeData; if (!PC_Script_Parse(&listPtr->doubleClick)) { return qfalse; } return qtrue; } /* =============== ItemParse_onFocus =============== */ qboolean ItemParse_onFocus( itemDef_t *item) { if (!PC_Script_Parse(&item->onFocus)) { return qfalse; } return qtrue; } /* =============== ItemParse_leaveFocus =============== */ qboolean ItemParse_leaveFocus( itemDef_t *item ) { if (!PC_Script_Parse(&item->leaveFocus)) { return qfalse; } return qtrue; } /* =============== ItemParse_mouseEnter =============== */ qboolean ItemParse_mouseEnter( itemDef_t *item) { if (!PC_Script_Parse(&item->mouseEnter)) { return qfalse; } return qtrue; } /* =============== ItemParse_mouseExit =============== */ qboolean ItemParse_mouseExit( itemDef_t *item) { if (!PC_Script_Parse(&item->mouseExit)) { return qfalse; } return qtrue; } /* =============== ItemParse_mouseEnterText =============== */ qboolean ItemParse_mouseEnterText( itemDef_t *item) { if (!PC_Script_Parse(&item->mouseEnterText)) { return qfalse; } return qtrue; } /* =============== ItemParse_mouseExitText =============== */ qboolean ItemParse_mouseExitText( itemDef_t *item) { if (!PC_Script_Parse(&item->mouseExitText)) { return qfalse; } return qtrue; } /* =============== ItemParse_accept =============== */ qboolean ItemParse_accept( itemDef_t *item) { if (!PC_Script_Parse(&item->accept)) { return qfalse; } return qtrue; } //JLFDPADSCRIPT /* =============== ItemParse_selectionNext =============== */ qboolean ItemParse_selectionNext( itemDef_t *item) { if (!PC_Script_Parse(&item->selectionNext)) { return qfalse; } return qtrue; } /* =============== ItemParse_selectionPrev =============== */ qboolean ItemParse_selectionPrev( itemDef_t *item) { if (!PC_Script_Parse(&item->selectionPrev)) { return qfalse; } return qtrue; } // END JLFDPADSCRIPT /* =============== ItemParse_action =============== */ qboolean ItemParse_action( itemDef_t *item) { if (!PC_Script_Parse(&item->action)) { return qfalse; } return qtrue; } /* =============== ItemParse_special =============== */ qboolean ItemParse_special( itemDef_t *item) { if (PC_ParseFloat(&item->special)) { return qfalse; } return qtrue; } /* =============== ItemParse_cvarTest =============== */ qboolean ItemParse_cvarTest( itemDef_t *item) { if (!PC_ParseStringMem((const char **) &item->cvarTest)) { return qfalse; } return qtrue; } /* =============== ItemParse_cvar =============== */ qboolean ItemParse_cvar( itemDef_t *item) { editFieldDef_t *editPtr; Item_ValidateTypeData(item); if (!PC_ParseStringMem(&item->cvar)) { return qfalse; } if ( item->typeData) { switch ( item->type ) { case ITEM_TYPE_EDITFIELD: case ITEM_TYPE_NUMERICFIELD: case ITEM_TYPE_YESNO: case ITEM_TYPE_BIND: case ITEM_TYPE_SLIDER: case ITEM_TYPE_TEXT: case ITEM_TYPE_TEXTSCROLL: editPtr = (editFieldDef_t*)item->typeData; editPtr->minVal = -1; editPtr->maxVal = -1; editPtr->defVal = -1; break; } } return qtrue; } /* =============== ItemParse_maxChars =============== */ qboolean ItemParse_maxChars( itemDef_t *item) { editFieldDef_t *editPtr; int maxChars; Item_ValidateTypeData(item); if (!item->typeData) { return qfalse; } if (PC_ParseInt(&maxChars)) { return qfalse; } editPtr = (editFieldDef_t*)item->typeData; editPtr->maxChars = maxChars; return qtrue; } /* =============== ItemParse_maxPaintChars =============== */ qboolean ItemParse_maxPaintChars( itemDef_t *item) { editFieldDef_t *editPtr; int maxChars; Item_ValidateTypeData(item); if (!item->typeData) { return qfalse; } if (PC_ParseInt(&maxChars)) { return qfalse; } editPtr = (editFieldDef_t*)item->typeData; editPtr->maxPaintChars = maxChars; return qtrue; } qboolean ItemParse_lineHeight( itemDef_t *item) { textScrollDef_t *scrollPtr; int height; Item_ValidateTypeData(item); if (!item->typeData) { return qfalse; } if (PC_ParseInt(&height)) { return qfalse; } scrollPtr = (textScrollDef_t*)item->typeData; scrollPtr->lineHeight = height; return qtrue; } /* =============== ItemParse_cvarFloat =============== */ qboolean ItemParse_cvarFloat( itemDef_t *item) { editFieldDef_t *editPtr; Item_ValidateTypeData(item); if (!item->typeData) { return qfalse; } editPtr = (editFieldDef_t*)item->typeData; if (PC_ParseStringMem((const char **) &item->cvar) && !PC_ParseFloat(&editPtr->defVal) && !PC_ParseFloat(&editPtr->minVal) && !PC_ParseFloat(&editPtr->maxVal)) { if (!Q_stricmp(item->cvar,"r_ext_texture_filter_anisotropic")) {//hehe, hook up the correct max value here. editPtr->maxVal=cls.glconfig.maxTextureFilterAnisotropy; } return qtrue; } return qfalse; } /* =============== ItemParse_cvarStrList =============== */ qboolean ItemParse_cvarStrList( itemDef_t *item) { const char *token; multiDef_t *multiPtr; int pass; Item_ValidateTypeData(item); if (!item->typeData) { return qfalse; } multiPtr = (multiDef_t*)item->typeData; multiPtr->count = 0; multiPtr->strDef = qtrue; if (PC_ParseString(&token)) { return qfalse; } if (!Q_stricmp(token,"feeder") && item->special == FEEDER_PLAYER_SPECIES) { for (; multiPtr->count < uiInfo.playerSpeciesCount; multiPtr->count++) { multiPtr->cvarList[multiPtr->count] = String_Alloc(Q_strupr(va("@MENUS_%s",uiInfo.playerSpecies[multiPtr->count].Name ))); //look up translation multiPtr->cvarStr[multiPtr->count] = uiInfo.playerSpecies[multiPtr->count].Name; //value } return qtrue; } // languages if (!Q_stricmp(token,"feeder") && item->special == FEEDER_LANGUAGES) { for (; multiPtr->count < uiInfo.languageCount; multiPtr->count++) { // The displayed text multiPtr->cvarList[multiPtr->count] = "@MENUS_MYLANGUAGE"; // The cvar value that goes into se_language #ifndef JK2_MODE // FIXME multiPtr->cvarStr[multiPtr->count] = SE_GetLanguageName(multiPtr->count); #endif } return qtrue; } if (*token != '{') { return qfalse; } pass = 0; while ( 1 ) { if (!PC_ParseStringMem(&token)) { PC_ParseWarning("end of file inside menu item\n"); return qfalse; } if (*token == '}') { return qtrue; } if (*token == ',' || *token == ';') { continue; } if (pass == 0) { multiPtr->cvarList[multiPtr->count] = token; pass = 1; } else { multiPtr->cvarStr[multiPtr->count] = token; pass = 0; multiPtr->count++; if (multiPtr->count >= MAX_MULTI_CVARS) { return qfalse; } } } return qfalse; } /* =============== ItemParse_cvarFloatList =============== */ qboolean ItemParse_cvarFloatList( itemDef_t *item) { const char *token; multiDef_t *multiPtr; Item_ValidateTypeData(item); if (!item->typeData) { return qfalse; } multiPtr = (multiDef_t*)item->typeData; multiPtr->count = 0; multiPtr->strDef = qfalse; if (PC_ParseString(&token)) { return qfalse; } if (*token != '{') { return qfalse; } while ( 1 ) { if (!PC_ParseStringMem(&token)) { PC_ParseWarning("end of file inside menu item\n"); return qfalse; } if (*token == '}') { return qtrue; } if (*token == ',' || *token == ';') { continue; } multiPtr->cvarList[multiPtr->count] = token; //a StringAlloc ptr if (PC_ParseFloat(&multiPtr->cvarValue[multiPtr->count])) { return qfalse; } multiPtr->count++; if (multiPtr->count >= MAX_MULTI_CVARS) { return qfalse; } } return qfalse; } /* =============== ItemParse_addColorRange =============== */ qboolean ItemParse_addColorRange( itemDef_t *item) { colorRangeDef_t color; if (PC_ParseFloat(&color.low) && PC_ParseFloat(&color.high) && PC_ParseColor(&color.color) ) { if (item->numColors < MAX_COLOR_RANGES) { memcpy(&item->colorRanges[item->numColors], &color, sizeof(color)); item->numColors++; } return qtrue; } return qfalse; } /* =============== ItemParse_ownerdrawFlag =============== */ qboolean ItemParse_ownerdrawFlag( itemDef_t *item ) { int i; if (PC_ParseInt(&i)) { return qfalse; } item->window.ownerDrawFlags |= i; return qtrue; } /* =============== ItemParse_enableCvar =============== */ qboolean ItemParse_enableCvar( itemDef_t *item) { if (PC_Script_Parse(&item->enableCvar)) { item->cvarFlags = CVAR_ENABLE; return qtrue; } return qfalse; } /* =============== ItemParse_disableCvar =============== */ qboolean ItemParse_disableCvar( itemDef_t *item ) { if (PC_Script_Parse(&item->enableCvar)) { item->cvarFlags = CVAR_DISABLE; return qtrue; } return qfalse; } /* =============== ItemParse_showCvar =============== */ qboolean ItemParse_showCvar( itemDef_t *item ) { if (PC_Script_Parse(&item->enableCvar)) { item->cvarFlags = CVAR_SHOW; return qtrue; } return qfalse; } /* =============== ItemParse_hideCvar =============== */ qboolean ItemParse_hideCvar( itemDef_t *item ) { if (PC_Script_Parse(&item->enableCvar)) { item->cvarFlags = CVAR_HIDE; return qtrue; } return qfalse; } /* =============== ItemParse_cvarsubstring =============== */ qboolean ItemParse_cvarsubstring( itemDef_t *item ) { assert(item->cvarFlags); //need something set first, then we or in our flag. item->cvarFlags |= CVAR_SUBSTRING; return qtrue; } /* =============== Item_ValidateTypeData =============== */ void Item_ValidateTypeData(itemDef_t *item) { if (item->typeData) { return; } if (item->type == ITEM_TYPE_LISTBOX) { item->typeData = UI_Alloc(sizeof(listBoxDef_t)); memset(item->typeData, 0, sizeof(listBoxDef_t)); } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD || item->type == ITEM_TYPE_YESNO || item->type == ITEM_TYPE_BIND || item->type == ITEM_TYPE_SLIDER || item->type == ITEM_TYPE_TEXT) { item->typeData = UI_Alloc(sizeof(editFieldDef_t)); memset(item->typeData, 0, sizeof(editFieldDef_t)); if (item->type == ITEM_TYPE_EDITFIELD) { if (!((editFieldDef_t *) item->typeData)->maxPaintChars) { ((editFieldDef_t *) item->typeData)->maxPaintChars = MAX_EDITFIELD; } } } else if (item->type == ITEM_TYPE_MULTI) { item->typeData = UI_Alloc(sizeof(multiDef_t)); } else if (item->type == ITEM_TYPE_MODEL) { item->typeData = UI_Alloc(sizeof(modelDef_t)); memset(item->typeData, 0, sizeof(modelDef_t)); } else if (item->type == ITEM_TYPE_TEXTSCROLL ) { item->typeData = UI_Alloc(sizeof(textScrollDef_t)); } } qboolean ItemParse_isCharacter( itemDef_t *item ) { int i; if ( !PC_ParseInt(&i) ) { if ( i ) { item->flags |= ITF_ISCHARACTER; } else { item->flags &= ~ITF_ISCHARACTER; } return qtrue; } return qfalse; } qboolean ItemParse_isSaber( itemDef_t *item ) { extern void UI_SaberLoadParms( void ); extern qboolean ui_saber_parms_parsed; extern void UI_CacheSaberGlowGraphics( void ); int i; if ( !PC_ParseInt(&i) ) { if ( i ) { item->flags |= ITF_ISSABER; UI_CacheSaberGlowGraphics(); if ( !ui_saber_parms_parsed ) { UI_SaberLoadParms(); } } else { item->flags &= ~ITF_ISSABER; } return qtrue; } return qfalse; } qboolean ItemParse_isSaber2( itemDef_t *item ) { extern void UI_SaberLoadParms( void ); extern qboolean ui_saber_parms_parsed; extern void UI_CacheSaberGlowGraphics( void ); int i; if ( !PC_ParseInt(&i) ) { if ( i ) { item->flags |= ITF_ISSABER2; UI_CacheSaberGlowGraphics(); if ( !ui_saber_parms_parsed ) { UI_SaberLoadParms(); } } else { item->flags &= ~ITF_ISSABER2; } return qtrue; } return qfalse; } keywordHash_t itemParseKeywords[] = { {"accept", ItemParse_accept, }, {"selectNext", ItemParse_selectionNext, }, {"selectPrev", ItemParse_selectionPrev, }, {"action", ItemParse_action, }, {"addColorRange", ItemParse_addColorRange, }, {"align", ItemParse_align, }, {"appearance_slot", ItemParse_Appearance_slot, }, {"asset_model", ItemParse_asset_model, }, {"asset_shader", ItemParse_asset_shader, }, {"isCharacter", ItemParse_isCharacter, }, {"isSaber", ItemParse_isSaber, }, {"isSaber2", ItemParse_isSaber2, }, {"autowrapped", ItemParse_autowrapped, }, {"backcolor", ItemParse_backcolor, }, {"background", ItemParse_background, }, {"border", ItemParse_border, }, {"bordercolor", ItemParse_bordercolor, }, {"bordersize", ItemParse_bordersize, }, {"cinematic", ItemParse_cinematic, }, {"columns", ItemParse_columns, }, {"cvar", ItemParse_cvar, }, {"cvarFloat", ItemParse_cvarFloat, }, {"cvarFloatList", ItemParse_cvarFloatList, }, {"cvarSubString", ItemParse_cvarsubstring }, {"cvarStrList", ItemParse_cvarStrList, }, {"cvarTest", ItemParse_cvarTest, }, {"decoration", ItemParse_decoration, }, {"desctext", ItemParse_descText }, {"disableCvar", ItemParse_disableCvar, }, {"doubleclick", ItemParse_doubleClick, }, {"elementheight", ItemParse_elementheight, }, {"elementtype", ItemParse_elementtype, }, {"elementwidth", ItemParse_elementwidth, }, {"enableCvar", ItemParse_enableCvar, }, {"feeder", ItemParse_feeder, }, {"flag", ItemParse_flag, }, {"focusSound", ItemParse_focusSound, }, {"font", ItemParse_font, }, {"forecolor", ItemParse_forecolor, }, {"group", ItemParse_group, }, {"hideCvar", ItemParse_hideCvar, }, {"horizontalscroll",ItemParse_horizontalscroll, }, {"leaveFocus", ItemParse_leaveFocus, }, {"maxChars", ItemParse_maxChars, }, {"maxPaintChars", ItemParse_maxPaintChars, }, {"model_angle", ItemParse_model_angle, }, {"model_fovx", ItemParse_model_fovx, }, {"model_fovy", ItemParse_model_fovy, }, {"model_origin", ItemParse_model_origin, }, {"model_rotation", ItemParse_model_rotation, }, //rww - g2 begin {"model_g2mins", ItemParse_model_g2mins, }, {"model_g2maxs", ItemParse_model_g2maxs, }, {"model_g2skin", ItemParse_model_g2skin, }, {"model_g2anim", ItemParse_model_g2anim, }, //rww - g2 end {"mouseEnter", ItemParse_mouseEnter, }, {"mouseEnterText", ItemParse_mouseEnterText, }, {"mouseExit", ItemParse_mouseExit, }, {"mouseExitText", ItemParse_mouseExitText, }, {"name", ItemParse_name }, {"notselectable", ItemParse_notselectable, }, //JLF {"scrollhidden", ItemParse_scrollhidden, }, //JLF END {"onFocus", ItemParse_onFocus, }, {"outlinecolor", ItemParse_outlinecolor, }, {"ownerdraw", ItemParse_ownerdraw, }, {"ownerdrawFlag", ItemParse_ownerdrawFlag, }, {"rect", ItemParse_rect, }, {"showCvar", ItemParse_showCvar, }, {"special", ItemParse_special, }, {"style", ItemParse_style, }, {"text", ItemParse_text }, {"text2", ItemParse_text2 }, {"text2alignx", ItemParse_text2alignx, }, {"text2aligny", ItemParse_text2aligny, }, {"textalign", ItemParse_textalign, }, {"textalignx", ItemParse_textalignx, }, {"textaligny", ItemParse_textaligny, }, {"textscale", ItemParse_textscale, }, {"textstyle", ItemParse_textstyle, }, {"type", ItemParse_type, }, {"visible", ItemParse_visible, }, {"wrapped", ItemParse_wrapped, }, {"invertyesno", ItemParse_invertyesno }, {"xoffset", ItemParse_xoffset },//for yes/no and multi // Text scroll specific {"lineHeight", ItemParse_lineHeight, NULL }, {NULL, NULL, } }; keywordHash_t *itemParseKeywordHash[KEYWORDHASH_SIZE]; /* =============== Item_SetupKeywordHash =============== */ void Item_SetupKeywordHash(void) { int i; memset(itemParseKeywordHash, 0, sizeof(itemParseKeywordHash)); for (i = 0; itemParseKeywords[i].keyword; i++) { KeywordHash_Add(itemParseKeywordHash, &itemParseKeywords[i]); } } /* =============== Item_Parse =============== */ qboolean Item_Parse(itemDef_t *item) { keywordHash_t *key; const char *token; if (PC_ParseString(&token)) { return qfalse; } if (*token != '{') { return qfalse; } while ( 1 ) { if (PC_ParseString(&token)) { PC_ParseWarning("End of file inside menu item"); return qfalse; } if (*token == '}') { /* if (!item->window.name) { item->window.name = defaultString; Com_Printf(S_COLOR_YELLOW"WARNING: Menu item has no name\n"); } if (!item->window.group) { item->window.group = defaultString; Com_Printf(S_COLOR_YELLOW"WARNING: Menu item has no group\n"); } */ return qtrue; } key = (keywordHash_s *) KeywordHash_Find(itemParseKeywordHash, token); if (!key) { PC_ParseWarning(va("Unknown item keyword '%s'", token)); continue; } if ( !key->func(item) ) { PC_ParseWarning(va("Couldn't parse item keyword '%s'", token)); return qfalse; } } } static void Item_TextScroll_BuildLines ( itemDef_t* item ) { // new asian-aware line breaker... (pasted from elsewhere late @ night, hence aliasing-vars ;-) // textScrollDef_t* scrollPtr = (textScrollDef_t*) item->typeData; const char *psText = item->text; // for copy/paste ease int iBoxWidth = item->window.rect.w - SCROLLBAR_SIZE - 10; // this could probably be simplified now, but it was converted from something else I didn't originally write, // and it works anyway so wtf... // const char *psCurrentTextReadPos; const char *psReadPosAtLineStart; const char *psBestLineBreakSrcPos; const char *psLastGood_s; // needed if we get a full screen of chars with no punctuation or space (see usage notes) qboolean bIsTrailingPunctuation; unsigned int uiLetter; if (!psText) { return; } if (*psText == '@') // string reference { // trap_SP_GetStringTextString( &psText[1], text, sizeof(text)); psText = SE_GetString( &psText[1] ); } psCurrentTextReadPos = psText; psReadPosAtLineStart = psCurrentTextReadPos; psBestLineBreakSrcPos = psCurrentTextReadPos; scrollPtr->iLineCount = 0; memset((char*)scrollPtr->pLines,0,sizeof(scrollPtr->pLines)); while (*psCurrentTextReadPos && (scrollPtr->iLineCount < MAX_TEXTSCROLL_LINES) ) { char sLineForDisplay[2048]; // ott // construct a line... // psCurrentTextReadPos = psReadPosAtLineStart; sLineForDisplay[0] = '\0'; while ( *psCurrentTextReadPos ) { int iAdvanceCount; psLastGood_s = psCurrentTextReadPos; // read letter... // uiLetter = ui.AnyLanguage_ReadCharFromString((char *)psCurrentTextReadPos, &iAdvanceCount, &bIsTrailingPunctuation); psCurrentTextReadPos += iAdvanceCount; // concat onto string so far... // if (uiLetter == 32 && sLineForDisplay[0] == '\0') { psReadPosAtLineStart++; continue; // unless it's a space at the start of a line, in which case ignore it. } if (uiLetter > 255) { Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c%c",uiLetter >> 8, uiLetter & 0xFF)); } else { Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c",uiLetter & 0xFF)); } if (uiLetter == '\n') { // explicit new line... // sLineForDisplay[ strlen(sLineForDisplay)-1 ] = '\0'; // kill the CR psReadPosAtLineStart = psCurrentTextReadPos; psBestLineBreakSrcPos = psCurrentTextReadPos; // hack it to fit in with this code... // scrollPtr->pLines[ scrollPtr->iLineCount ] = String_Alloc ( sLineForDisplay ); break; // print this line } else if ( DC->textWidth( sLineForDisplay, item->textscale, item->font ) >= iBoxWidth ) { // reached screen edge, so cap off string at bytepos after last good position... // if (uiLetter > 255 && bIsTrailingPunctuation && !ui.Language_UsesSpaces()) { // Special case, don't consider line breaking if you're on an asian punctuation char of // a language that doesn't use spaces... // } else { if (psBestLineBreakSrcPos == psReadPosAtLineStart) { // aarrrggh!!!!! we'll only get here is someone has fed in a (probably) garbage string, // since it doesn't have a single space or punctuation mark right the way across one line // of the screen. So far, this has only happened in testing when I hardwired a taiwanese // string into this function while the game was running in english (which should NEVER happen // normally). On the other hand I suppose it's entirely possible that some taiwanese string // might have no punctuation at all, so... // psBestLineBreakSrcPos = psLastGood_s; // force a break after last good letter } sLineForDisplay[ psBestLineBreakSrcPos - psReadPosAtLineStart ] = '\0'; psReadPosAtLineStart = psCurrentTextReadPos = psBestLineBreakSrcPos; // hack it to fit in with this code... // scrollPtr->pLines[ scrollPtr->iLineCount ] = String_Alloc( sLineForDisplay ); break; // print this line } } // record last-good linebreak pos... (ie if we've just concat'd a punctuation point (western or asian) or space) // if (bIsTrailingPunctuation || uiLetter == ' ' || (uiLetter > 255 && !ui.Language_UsesSpaces())) { psBestLineBreakSrcPos = psCurrentTextReadPos; } } /// arrgghh, this is gettng horrible now... // if (scrollPtr->pLines[ scrollPtr->iLineCount ] == NULL && strlen(sLineForDisplay)) { // then this is the last line and we've just run out of text, no CR, no overflow etc... // scrollPtr->pLines[ scrollPtr->iLineCount ] = String_Alloc( sLineForDisplay ); } scrollPtr->iLineCount++; } } /* =============== Item_InitControls init's special control types =============== */ void Item_InitControls(itemDef_t *item) { if (item == NULL) { return; } if (item->type == ITEM_TYPE_LISTBOX) { listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData; item->cursorPos = 0; if (listPtr) { listPtr->cursorPos = 0; listPtr->startPos = 0; listPtr->endPos = 0; listPtr->cursorPos = 0; } } } /* ================= Int_Parse ================= */ qboolean Int_Parse(const char **p, int *i) { char *token; token = COM_ParseExt(p, qfalse); if (token && token[0] != 0) { *i = atoi(token); return qtrue; } else { return qfalse; } } /* ================= String_Parse ================= */ qboolean String_Parse(const char **p, const char **out) { char *token; token = COM_ParseExt(p, qfalse); if (token && token[0] != 0) { *out = String_Alloc(token); return (qboolean)(*out != NULL); } return qfalse; } /* =============== Item_RunScript =============== */ void Item_RunScript(itemDef_t *item, const char *s) { const char *p; int i; qboolean bRan; uiInfo.runScriptItem = item; if (item && s && s[0]) { p = s; COM_BeginParseSession(); while (1) { const char *command; // expect command then arguments, ; ends command, NULL ends script if (!String_Parse(&p, &command)) { break; } if (command[0] == ';' && command[1] == '\0') { continue; } bRan = qfalse; for (i = 0; i < scriptCommandCount; i++) { if (Q_stricmp(command, commandList[i].name) == 0) { if ( !(commandList[i].handler(item, &p)) ) { COM_EndParseSession(); return; } bRan = qtrue; break; } } // not in our auto list, pass to handler if (!bRan) { // Allow any script command to fail if ( !DC->runScript(&p) ) { break; } } } COM_EndParseSession(); } } /* =============== Menu_SetupKeywordHash =============== */ void Menu_SetupKeywordHash(void) { int i; memset(menuParseKeywordHash, 0, sizeof(menuParseKeywordHash)); for (i = 0; menuParseKeywords[i].keyword; i++) { KeywordHash_Add(menuParseKeywordHash, &menuParseKeywords[i]); } } /* =============== Menus_ActivateByName =============== */ void Menu_HandleMouseMove(menuDef_t *menu, float x, float y); menuDef_t *Menus_ActivateByName(const char *p) { int i; menuDef_t *m = NULL; menuDef_t *focus = Menu_GetFocused(); for (i = 0; i < menuCount; i++) { // Look for the name in the current list of windows if (Q_stricmp(Menus[i].window.name, p) == 0) { m = &Menus[i]; Menus_Activate(m); if (openMenuCount < MAX_OPEN_MENUS && focus != NULL) { menuStack[openMenuCount++] = focus; } } else { Menus[i].window.flags &= ~WINDOW_HASFOCUS; } } if (!m) { // A hack so we don't have to load all three mission menus before we know what tier we're on if (!Q_stricmp( p, "ingameMissionSelect1" ) ) { UI_LoadMenus("ui/tier1.txt",qfalse); Menus_CloseAll(); Menus_OpenByName("ingameMissionSelect1"); } else if (!Q_stricmp( p, "ingameMissionSelect2" ) ) { UI_LoadMenus("ui/tier2.txt",qfalse); Menus_CloseAll(); Menus_OpenByName("ingameMissionSelect2"); } else if (!Q_stricmp( p, "ingameMissionSelect3" ) ) { UI_LoadMenus("ui/tier3.txt",qfalse); Menus_CloseAll(); Menus_OpenByName("ingameMissionSelect3"); } else { Com_Printf(S_COLOR_YELLOW"WARNING: Menus_ActivateByName: Unable to find menu \"%s\"\n",p); } } // First time, show force select instructions if (!Q_stricmp( p, "ingameForceSelect" ) ) { int tier_storyinfo = Cvar_VariableIntegerValue( "tier_storyinfo" ); if (tier_storyinfo==1) { Menus_OpenByName("ingameForceHelp"); } } // First time, show weapons select instructions if (!Q_stricmp( p, "ingameWpnSelect" ) ) { int tier_storyinfo = Cvar_VariableIntegerValue( "tier_storyinfo" ); if (tier_storyinfo==1) { Menus_OpenByName("ingameWpnSelectHelp"); } } // Want to handle a mouse move on the new menu in case your already over an item Menu_HandleMouseMove ( m, DC->cursorx, DC->cursory ); return m; } /* =============== Menus_Activate =============== */ void Menus_Activate(menuDef_t *menu) { menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE); if (menu->onOpen) { itemDef_t item; item.parent = menu; item.window.flags = 0; //err, item is fake here, but we want a valid flag before calling runscript Item_RunScript(&item, menu->onOpen); if (item.window.flags & WINDOW_SCRIPTWAITING) //in case runscript set waiting, copy it up to the menu { menu->window.flags |= WINDOW_SCRIPTWAITING; menu->window.delayedScript = item.window.delayedScript; menu->window.delayTime = item.window.delayTime; } } // menu->appearanceTime = DC->realTime + 1000; menu->appearanceTime = 0; menu->appearanceCnt = 0; } static const char *g_bindCommands[] = { "+altattack", "+attack", "+back", #ifndef JK2_MODE "+force_drain", #endif "+force_grip", "+force_lightning", "+forward", "+left", "+lookdown", "+lookup", "+mlook", "+movedown", "+moveleft", "+moveright", "+moveup", "+right", "+speed", "+strafe", "+use", "+useforce", "centerview", "cg_thirdperson !", "datapad", "exitview", #ifndef JK2_MODE "force_absorb", #endif "force_distract", "force_heal", #ifndef JK2_MODE "force_protect", #endif "force_pull", #ifndef JK2_MODE "force_rage", "force_sight", #endif "force_speed", "force_throw", "forcenext", "forceprev", "invnext", "invprev", "invuse", "load auto", #ifdef JK2_MODE "load quik", #else "load quick", #endif "saberAttackCycle", #ifdef JK2_MODE "save quik*", #else "save quick", #endif "taunt", "uimenu ingameloadmenu", "uimenu ingamesavemenu", "use_bacta", "use_electrobinoculars", "use_lightamp_goggles", "use_seeker", "use_sentry", "weapnext", "weapon 0", "weapon 1", "weapon 10", "weapon 11", "weapon 12", "weapon 13", "weapon 2", "weapon 3", "weapon 4", "weapon 5", "weapon 6", "weapon 7", "weapon 8", "weapon 9", "weapprev", "zoom" }; #define g_bindCount ARRAY_LEN(g_bindCommands) static int g_bindKeys[g_bindCount][2]; /* ================= Controls_GetKeyAssignment ================= */ static void Controls_GetKeyAssignment( const char *command, int *twokeys ) { int count; int j; char b[256]; twokeys[0] = twokeys[1] = -1; count = 0; for ( j=0; jgetBindingBuf( j, b, sizeof( b ) ); if ( *b && !Q_stricmp( b, command ) ) { twokeys[count] = j; count++; if ( count == 2 ) break; } } } /* ================= Controls_GetConfig ================= */ void Controls_GetConfig( void ) { size_t i; // iterate each command, get its numeric binding for ( i = 0; i < g_bindCount; i++ ) Controls_GetKeyAssignment( g_bindCommands[i], g_bindKeys[i] ); } /* =============== Item_SetScreenCoords =============== */ void Item_SetScreenCoords(itemDef_t *item, float x, float y) { if (item == NULL) { return; } if (item->window.border != 0) { x += item->window.borderSize; y += item->window.borderSize; } item->window.rect.x = x + item->window.rectClient.x; item->window.rect.y = y + item->window.rectClient.y; item->window.rect.w = item->window.rectClient.w; item->window.rect.h = item->window.rectClient.h; // force the text rects to recompute item->textRect.w = 0; item->textRect.h = 0; switch ( item->type) { case ITEM_TYPE_TEXTSCROLL: { textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; if ( scrollPtr ) { scrollPtr->startPos = 0; scrollPtr->endPos = 0; } Item_TextScroll_BuildLines ( item ); break; } } } static void Menu_FreeGhoulItems(menuDef_t *menu) { int i,j; for (i = 0; i < menu->itemCount; i++) { for (j=0; j < menu->items[i]->ghoul2.size(); j++) { if ( menu->items[i]->ghoul2[j].mModelindex >= 0) { DC->g2_RemoveGhoul2Model( menu->items[i]->ghoul2, j ); } } (menu->items[i]->ghoul2).clear(); //clear is the public Free so i can actually remove this slot } } /* =============== Menu_Reset =============== */ void Menu_Reset(void) { //FIXME iterate menus to destoy G2 assets. int i; for (i = 0; i < menuCount; i++) { Menu_FreeGhoulItems( &Menus[i] ); } menuCount = 0; } /* =============== Menu_UpdatePosition =============== */ void Menu_UpdatePosition(menuDef_t *menu) { int i; float x, y; if (menu == NULL) { return; } x = menu->window.rect.x; y = menu->window.rect.y; if (menu->window.border != 0) { x += menu->window.borderSize; y += menu->window.borderSize; } for (i = 0; i < menu->itemCount; i++) { Item_SetScreenCoords(menu->items[i], x, y); } } /* =============== Menu_PostParse =============== */ void Menu_PostParse(menuDef_t *menu) { if (menu == NULL) { return; } if (menu->fullScreen) { menu->window.rect.x = 0; menu->window.rect.y = 0; menu->window.rect.w = 640; menu->window.rect.h = 480; } Menu_UpdatePosition(menu); } /* =============== Menu_Init =============== */ void Menu_Init(menuDef_t *menu) { memset(menu, 0, sizeof(menuDef_t)); menu->cursorItem = -1; UI_Cursor_Show(qtrue); if (DC) { menu->fadeAmount = DC->Assets.fadeAmount; menu->fadeClamp = DC->Assets.fadeClamp; menu->fadeCycle = DC->Assets.fadeCycle; } Window_Init(&menu->window); } /* =============== Menu_Parse =============== */ qboolean Menu_Parse(char *inbuffer, menuDef_t *menu) { // pc_token_t token; keywordHash_t *key; char *token2; char * buffer; bool nest= false; buffer = inbuffer; token2 = PC_ParseExt(); if (!token2) { return qfalse; } if (*token2 != '{') { PC_ParseWarning("Misplaced {"); return qfalse; } while ( 1 ) { token2 = PC_ParseExt(); if (!token2) { PC_ParseWarning("End of file inside menu."); return qfalse; } if (*token2 == '}') { return qtrue; } if (nest && (*token2 == 0)) { PC_EndParseSession(buffer); nest = false; continue; } key = KeywordHash_Find(menuParseKeywordHash, token2); if (!key) { PC_ParseWarning(va("Unknown menu keyword %s",token2)); continue; } if ( !key->func((itemDef_t*)menu) ) { PC_ParseWarning(va("Couldn't parse menu keyword %s as %s",token2, key->keyword)); return qfalse; } } } /* =============== Menu_New =============== */ void Menu_New(char *buffer) { menuDef_t *menu = &Menus[menuCount]; if (menuCount < MAX_MENUS) { Menu_Init(menu); if (Menu_Parse(buffer, menu)) { Menu_PostParse(menu); menuCount++; } } } /* =============== Menus_CloseAll =============== */ void Menus_CloseAll(void) { int i; for (i = 0; i < menuCount; i++) { Menu_RunCloseScript ( &Menus[i] ); Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE); } // Clear the menu stack openMenuCount = 0; } /* =============== PC_StartParseSession =============== */ int PC_StartParseSession(const char *fileName,char **buffer) { int len; // Try to open file and read it in. len = ui.FS_ReadFile( fileName,(void **) buffer ); // Not there? if ( len>0 ) { COM_BeginParseSession(); Q_strncpyz(parseData[parseDataCount].fileName, fileName, sizeof (parseData[0].fileName)); parseData[parseDataCount].bufferStart = *buffer; parseData[parseDataCount].bufferCurrent = *buffer; } return len; } /* =============== PC_EndParseSession =============== */ void PC_EndParseSession(char *buffer) { COM_EndParseSession(); ui.FS_FreeFile( buffer ); //let go of the buffer } /* =============== PC_ParseWarning =============== */ void PC_ParseWarning(const char *message) { ui.Printf(S_COLOR_YELLOW "WARNING: %s Line #%d of File '%s'\n", message,parseData[parseDataCount].com_lines,parseData[parseDataCount].fileName); } char *PC_ParseExt(void) { if(parseDataCount < 0) Com_Error(ERR_FATAL, "PC_ParseExt: parseDataCount < 0 (be sure to call PC_StartParseSession!)"); return (COM_ParseExt(&parseData[parseDataCount].bufferCurrent, qtrue)); } qboolean PC_ParseString(const char **string) { int hold; if(parseDataCount < 0) Com_Error(ERR_FATAL, "PC_ParseString: parseDataCount < 0 (be sure to call PC_StartParseSession!)"); hold = COM_ParseString(&parseData[parseDataCount].bufferCurrent,string); while (hold==0 && **string == 0) { hold = COM_ParseString(&parseData[parseDataCount].bufferCurrent,string); } return (qboolean)(hold != 0); } qboolean PC_ParseInt(int *number) { if(parseDataCount < 0) Com_Error(ERR_FATAL, "PC_ParseInt: parseDataCount < 0 (be sure to call PC_StartParseSession!)"); return(COM_ParseInt(&parseData[parseDataCount].bufferCurrent,number)); } qboolean PC_ParseFloat(float *number) { if(parseDataCount < 0) Com_Error(ERR_FATAL, "PC_ParseFloat: parseDataCount < 0 (be sure to call PC_StartParseSession!)"); return(COM_ParseFloat(&parseData[parseDataCount].bufferCurrent,number)); } qboolean PC_ParseColor(vec4_t *color) { if(parseDataCount < 0) Com_Error(ERR_FATAL, "PC_ParseColor: parseDataCount < 0 (be sure to call PC_StartParseSession!)"); return(COM_ParseVec4(&parseData[parseDataCount].bufferCurrent, color)); } /* ================= Menu_Count ================= */ int Menu_Count(void) { return menuCount; } /* ================= Menu_PaintAll ================= */ void Menu_PaintAll(void) { int i; if (captureFunc) { captureFunc(captureData); } for (i = 0; i < menuCount; i++) { Menu_Paint(&Menus[i], qfalse); } if (uis.debugMode) { vec4_t v = {1, 1, 1, 1}; DC->drawText(5, 25, .75, v, va("(%d,%d)",DC->cursorx,DC->cursory), 0, 0, DC->Assets.qhMediumFont); DC->drawText(5, 10, .75, v, va("fps: %f", DC->FPS), 0, 0, DC->Assets.qhMediumFont); } } /* ================= Menu_Paint ================= */ void Menu_Paint(menuDef_t *menu, qboolean forcePaint) { int i; if (menu == NULL) { return; } if (menu->window.flags & WINDOW_SCRIPTWAITING) { if (DC->realTime > menu->window.delayTime) { // Time has elapsed, resume running whatever script we saved itemDef_t item; item.parent = menu; item.window.flags = 0; //clear before calling RunScript menu->window.flags &= ~WINDOW_SCRIPTWAITING; Item_RunScript(&item, menu->window.delayedScript); // Could have hit another delay. Need to hoist from fake item if (item.window.flags & WINDOW_SCRIPTWAITING) { menu->window.flags |= WINDOW_SCRIPTWAITING; menu->window.delayedScript = item.window.delayedScript; menu->window.delayTime = item.window.delayTime; } } } if (!(menu->window.flags & WINDOW_VISIBLE) && !forcePaint) { return; } // if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags)) // { // return; // } if (forcePaint) { menu->window.flags |= WINDOW_FORCED; } // draw the background if necessary if (menu->fullScreen) { vec4_t color; color[0] = menu->window.backColor[0]; color[1] = menu->window.backColor[1]; color[2] = menu->window.backColor[2]; color[3] = menu->window.backColor[3]; ui.R_SetColor( color); if (menu->window.background==0) // No background shader given? Make it blank { menu->window.background = uis.whiteShader; } DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background ); } else if (menu->window.background) { // this allows a background shader without being full screen //UI_DrawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader); } // paint the background and or border Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle ); // Loop through all items for the menu and paint them int iSlotsVisible = 0; for (i = 0; i < menu->itemCount; i++) { if (!menu->items[i]->appearanceSlot) { Item_Paint(menu->items[i], qtrue); } else // Timed order of appearance { if (Item_Paint(menu->items[i], qfalse) ) { iSlotsVisible++; //It would paint } if (menu->items[i]->appearanceSlot<=menu->appearanceCnt) { Item_Paint(menu->items[i], qtrue); } } } if (iSlotsVisible && menu->appearanceTime < DC->realTime && menu->appearanceCnt < menu->itemCount) // Time to show another item { menu->appearanceTime = DC->realTime + menu->appearanceIncrement; menu->appearanceCnt++; } if (uis.debugMode) { vec4_t color; color[0] = color[2] = color[3] = 1; color[1] = 0; DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color); } } /* ================= Item_EnableShowViaCvar ================= */ qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) { if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) { char script[1024]; const char *p; char buff[1024]; if (item->cvarFlags & CVAR_SUBSTRING) { const char *val; p = item->enableCvar; COM_BeginParseSession(); if (!String_Parse(&p, &val)) {//strip the quotes off COM_EndParseSession(); return (item->cvarFlags & flag) ? qfalse : qtrue; } COM_EndParseSession(); Q_strncpyz(buff, val, sizeof(buff)); DC->getCVarString(item->cvarTest, script, sizeof(script)); p = script; } else { DC->getCVarString(item->cvarTest, buff, sizeof(buff)); Q_strncpyz(script, item->enableCvar, sizeof(script)); p = script; } COM_BeginParseSession(); while (1) { const char *val; // expect value then ; or NULL, NULL ends list if (!String_Parse(&p, &val)) { COM_EndParseSession(); return (item->cvarFlags & flag) ? qfalse : qtrue; } if (val[0] == ';' && val[1] == '\0') { continue; } // enable it if any of the values are true if (item->cvarFlags & flag) { if (Q_stricmp(buff, val) == 0) { COM_EndParseSession(); return qtrue; } } else { // disable it if any of the values are true if (Q_stricmp(buff, val) == 0) { COM_EndParseSession(); return qfalse; } } } COM_EndParseSession(); return (item->cvarFlags & flag) ? qfalse : qtrue; } return qtrue; } bool HasStringLanguageChanged ( const itemDef_t *item ) { if ( !item->text || item->text[0] == '\0' ) { return false; } int modificationCount; #ifdef JK2_MODE modificationCount = sp_language->modificationCount; #else modificationCount = se_language->modificationCount; #endif return item->asset != modificationCount; } /* ================= Item_SetTextExtents ================= */ void Item_SetTextExtents(itemDef_t *item, int *width, int *height, const char *text) { const char *textPtr = (text) ? text : item->text; if (textPtr == NULL ) { return; } *width = item->textRect.w; *height = item->textRect.h; // keeps us from computing the widths and heights more than once if (*width == 0 || (item->type == ITEM_TYPE_OWNERDRAW && item->textalignment == ITEM_ALIGN_CENTER) || HasStringLanguageChanged (item)) { int originalWidth; originalWidth = DC->textWidth(textPtr, item->textscale, item->font); if (item->type == ITEM_TYPE_OWNERDRAW && (item->textalignment == ITEM_ALIGN_CENTER || item->textalignment == ITEM_ALIGN_RIGHT)) { originalWidth += DC->ownerDrawWidth(item->window.ownerDraw, item->textscale); } else if (item->type == ITEM_TYPE_EDITFIELD && item->textalignment == ITEM_ALIGN_CENTER && item->cvar) { char buff[256]; DC->getCVarString(item->cvar, buff, 256); originalWidth += DC->textWidth(buff, item->textscale, item->font); } *width = DC->textWidth(textPtr, item->textscale, item->font); *height = DC->textHeight(textPtr, item->textscale, item->font); item->textRect.w = *width; item->textRect.h = *height; item->textRect.x = item->textalignx; item->textRect.y = item->textaligny; if (item->textalignment == ITEM_ALIGN_RIGHT) { item->textRect.x = item->textalignx - originalWidth; } else if (item->textalignment == ITEM_ALIGN_CENTER) { item->textRect.x = item->textalignx - originalWidth / 2; } ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window); #ifdef JK2_MODE if(item->text && item->text[0]=='@') item->asset = sp_language->modificationCount; #else if (item->text && item->text[0]=='@' )//string package item->asset = se_language->modificationCount; //mark language #endif } } /* ================= Item_TextColor ================= */ void Item_TextColor(itemDef_t *item, vec4_t *newColor) { vec4_t lowLight; const vec4_t greyColor = { .5, .5, .5, 1}; menuDef_t *parent = (menuDef_t*)item->parent; Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount); if ( !(item->type == ITEM_TYPE_TEXT && item->window.flags & WINDOW_AUTOWRAPPED) && item->window.flags & WINDOW_HASFOCUS) { lowLight[0] = 0.8 * parent->focusColor[0]; lowLight[1] = 0.8 * parent->focusColor[1]; lowLight[2] = 0.8 * parent->focusColor[2]; lowLight[3] = 0.8 * parent->focusColor[3]; LerpColor(parent->focusColor,lowLight,*newColor,0.5+0.5*sin((float)(DC->realTime / PULSE_DIVISOR))); } /* else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) { lowLight[0] = 0.8 * item->window.foreColor[0]; lowLight[1] = 0.8 * item->window.foreColor[1]; lowLight[2] = 0.8 * item->window.foreColor[2]; lowLight[3] = 0.8 * item->window.foreColor[3]; LerpColor(item->window.foreColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR)); } */ else { memcpy(newColor, &item->window.foreColor, sizeof(vec4_t)); } if (item->disabled) { memcpy(newColor, &parent->disableColor, sizeof(vec4_t)); } // items can be enabled and disabled based on cvars if (item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) { if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) { memcpy(newColor, &parent->disableColor, sizeof(vec4_t)); } } if (item->window.flags & WINDOW_INACTIVE) { memcpy(newColor, &greyColor, sizeof(vec4_t)); } } /* ================= Item_Text_Wrapped_Paint ================= */ void Item_Text_Wrapped_Paint(itemDef_t *item) { char text[1024]; const char *p, *start, *textPtr; char buff[1024]; int width, height; float x, y; vec4_t color; // now paint the text and/or any optional images // default to left if (item->text == NULL) { if (item->cvar == NULL) { return; } else { DC->getCVarString(item->cvar, text, sizeof(text)); textPtr = text; } } else { textPtr = item->text; } if (*textPtr == '@') // string reference { textPtr = SE_GetString( &textPtr[1] ); } if (*textPtr == '\0') { return; } Item_TextColor(item, &color); Item_SetTextExtents(item, &width, &height, textPtr); x = item->textRect.x; y = item->textRect.y; start = textPtr; p = strchr(textPtr, '\r'); while (p && *p) { strncpy(buff, start, p-start+1); buff[p-start] = '\0'; DC->drawText(x, y, item->textscale, color, buff, 0, item->textStyle, item->font); y += height + 5; start += p - start + 1; p = strchr(p+1, '\r'); } DC->drawText(x, y, item->textscale, color, start, 0, item->textStyle, item->font); } /* ================= Menu_Paint ================= */ void Item_Text_Paint(itemDef_t *item) { char text[1024]; const char *textPtr; int height, width; vec4_t color; if (item->window.flags & WINDOW_WRAPPED) { Item_Text_Wrapped_Paint(item); return; } if (item->window.flags & WINDOW_AUTOWRAPPED) { Item_Text_AutoWrapped_Paint(item); return; } if (item->text == NULL) { if (item->cvar == NULL) { return; } else { DC->getCVarString(item->cvar, text, sizeof(text)); textPtr = text; } } else { textPtr = item->text; } #ifdef JK2_MODE if (*textPtr == '@') { textPtr = JK2SP_GetStringTextString(&textPtr[1]); } #else if (*textPtr == '@') // string reference { textPtr = SE_GetString( &textPtr[1] ); } #endif // this needs to go here as it sets extents for cvar types as well Item_SetTextExtents(item, &width, &height, textPtr); if (*textPtr == '\0') { return; } Item_TextColor(item, &color); DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, item->textStyle, item->font); if (item->text2) // Is there a second line of text? { textPtr = item->text2; if (*textPtr == '@') // string reference { textPtr = SE_GetString( &textPtr[1] ); } Item_TextColor(item, &color); DC->drawText(item->textRect.x + item->text2alignx, item->textRect.y + item->text2aligny, item->textscale, color, textPtr, 0, item->textStyle, item->font); } } /* ================= Item_UpdatePosition ================= */ // FIXME: consolidate this with nearby stuff void Item_UpdatePosition(itemDef_t *item) { float x, y; menuDef_t *menu; if (item == NULL || item->parent == NULL) { return; } menu = (menuDef_t *) item->parent; x = menu->window.rect.x; y = menu->window.rect.y; if (menu->window.border != 0) { x += menu->window.borderSize; y += menu->window.borderSize; } Item_SetScreenCoords(item, x, y); } /* ================= Item_TextField_Paint ================= */ void Item_TextField_Paint(itemDef_t *item) { char buff[1024]; vec4_t newColor, lowLight; int offset; menuDef_t *parent = (menuDef_t*)item->parent; editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData; Item_Text_Paint(item); buff[0] = '\0'; if (item->cvar) { DC->getCVarString(item->cvar, buff, sizeof(buff)); } if (item->window.flags & WINDOW_HASFOCUS) { lowLight[0] = 0.8 * parent->focusColor[0]; lowLight[1] = 0.8 * parent->focusColor[1]; lowLight[2] = 0.8 * parent->focusColor[2]; lowLight[3] = 0.8 * parent->focusColor[3]; LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin((float)(DC->realTime / PULSE_DIVISOR))); } else { memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t)); } offset = 8;//(item->text && *item->text) ? 8 : 0; if (item->window.flags & WINDOW_HASFOCUS && g_editingField) { char cursor = DC->getOverstrikeMode() ? '_' : '|'; DC->drawTextWithCursor(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, item->cursorPos - editPtr->paintOffset , cursor, /*editPtr->maxPaintChars*/ item->window.rect.w, item->textStyle, item->font); } else { DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, /*editPtr->maxPaintChars*/ item->window.rect.w, item->textStyle, item->font); } } void Item_TextScroll_Paint(itemDef_t *item) { char cvartext[1024]; float x, y, size, count, thumb; int i; textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; size = item->window.rect.h - 2; // Re-arranged this function. Previous version had a plethora of bugs. // Still a little iffy - BTO (VV) if (item->cvar) { DC->getCVarString(item->cvar, cvartext, sizeof(cvartext)); item->text = cvartext; } Item_TextScroll_BuildLines ( item ); count = scrollPtr->iLineCount; // Draw scroll bar if text goes beyond bottom if (( scrollPtr->iLineCount * scrollPtr->lineHeight ) > size) { // draw scrollbar to right side of the window x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1; y = item->window.rect.y + 1; DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp); y += SCROLLBAR_SIZE - 1; scrollPtr->endPos = scrollPtr->startPos; size = item->window.rect.h - (SCROLLBAR_SIZE * 2); DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar); y += size - 1; DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown); // thumb thumb = Item_TextScroll_ThumbDrawPosition(item); if (thumb > y - SCROLLBAR_SIZE - 1) { thumb = y - SCROLLBAR_SIZE - 1; } DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb); } // adjust size for item painting size = item->window.rect.h - 2; x = item->window.rect.x + item->textalignx + 1; y = item->window.rect.y + item->textaligny + 1; for (i = scrollPtr->startPos; i < count; i++) { const char *text; text = scrollPtr->pLines[i]; if (!text) { continue; } DC->drawText(x + 4, y, item->textscale, item->window.foreColor, text, 0, item->textStyle, item->font); size -= scrollPtr->lineHeight; if (size < scrollPtr->lineHeight) { scrollPtr->drawPadding = scrollPtr->lineHeight - size; break; } scrollPtr->endPos++; y += scrollPtr->lineHeight; } } /* ================= Item_ListBox_Paint ================= */ void Item_ListBox_Paint(itemDef_t *item) { float x, y, size; int count, i, thumb; qhandle_t image; qhandle_t optionalImage; listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData; // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction // elements are enumerated from the DC and either text or image handles are acquired from the DC as well // textscale is used to size the text, textalignx and textaligny are used to size image elements // there is no clipping available so only the last completely visible item is painted count = DC->feederCount(item->special); if (listPtr->startPos > (count?count-1:count)) {//probably changed feeders, so reset listPtr->startPos = 0; } if (item->cursorPos > (count?count-1:count)) {//probably changed feeders, so reset item->cursorPos = 0; } // default is vertical if horizontal flag is not here if (item->window.flags & WINDOW_HORIZONTAL) { //JLF new variable (code just indented) if (!listPtr->scrollhidden) { // draw scrollbar in bottom of the window // bar if (Item_ListBox_MaxScroll(item) > 0) { x = item->window.rect.x + 1; y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE - 1; DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft); x += SCROLLBAR_SIZE - 1; size = item->window.rect.w - (SCROLLBAR_SIZE * 2); DC->drawHandlePic(x, y, size+1, SCROLLBAR_SIZE, DC->Assets.scrollBar); x += size - 1; DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowRight); // thumb thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item); if (thumb > x - SCROLLBAR_SIZE - 1) { thumb = x - SCROLLBAR_SIZE - 1; } DC->drawHandlePic(thumb, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb); } else if (listPtr->startPos > 0) { listPtr->startPos = 0; } } //JLF end // listPtr->endPos = listPtr->startPos; size = item->window.rect.w - 2; // items // size contains max available space if (listPtr->elementStyle == LISTBOX_IMAGE) { // fit = 0; x = item->window.rect.x + 1; y = item->window.rect.y + 1; for (i = listPtr->startPos; i < count; i++) { // always draw at least one // which may overdraw the box if it is too small for the element image = DC->feederItemImage(item->special, i); if (image) { if (item->window.flags & WINDOW_PLAYERCOLOR) { vec4_t color; color[0] = ui_char_color_red.integer/255.0f; color[1] = ui_char_color_green.integer/255.0f; color[2] = ui_char_color_blue.integer/255.0f; color[3] = 1; ui.R_SetColor(color); } DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image); } if (i == item->cursorPos) { DC->drawRect(x, y, listPtr->elementWidth-1, listPtr->elementHeight-1, item->window.borderSize, item->window.borderColor); } size -= listPtr->elementWidth; if (size < listPtr->elementWidth) { listPtr->drawPadding = size; //listPtr->elementWidth - size; break; } x += listPtr->elementWidth; listPtr->endPos++; // fit++; } } else { // } } else { //JLF new variable (code idented with if) if (!listPtr->scrollhidden) { // draw scrollbar to right side of the window x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1; y = item->window.rect.y + 1; DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp); y += SCROLLBAR_SIZE - 1; listPtr->endPos = listPtr->startPos; size = item->window.rect.h - (SCROLLBAR_SIZE * 2); DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar); y += size - 1; DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown); // thumb thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item); if (thumb > y - SCROLLBAR_SIZE - 1) { thumb = y - SCROLLBAR_SIZE - 1; } DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb); } //JLF end // adjust size for item painting size = item->window.rect.h - 2; if (listPtr->elementStyle == LISTBOX_IMAGE) { // fit = 0; x = item->window.rect.x + 1; y = item->window.rect.y + 1; for (i = listPtr->startPos; i < count; i++) { // always draw at least one // which may overdraw the box if it is too small for the element image = DC->feederItemImage(item->special, i); if (image) { DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image); } if (i == item->cursorPos) { DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.borderColor); } listPtr->endPos++; size -= listPtr->elementHeight; if (size < listPtr->elementHeight) { listPtr->drawPadding = listPtr->elementHeight - size; break; } y += listPtr->elementHeight; // fit++; } } else { x = item->window.rect.x + 1; y = item->window.rect.y + 1 - listPtr->elementHeight; i = listPtr->startPos; for (; i < count; i++) { const char *text; // always draw at least one // which may overdraw the box if it is too small for the element if (listPtr->numColumns > 0) { int j; for (j = 0; j < listPtr->numColumns; j++) { text = DC->feederItemText(item->special, i, j, &optionalImage); if (text[0]=='@') { text = SE_GetString( &text[1] ); } if (optionalImage >= 0) { DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage); } else if (text) { vec4_t *color; menuDef_t *parent = (menuDef_t*)item->parent; // Use focus color is it has focus. if (i == item->cursorPos) { color = &parent->focusColor; } else { color = &item->window.foreColor; } int textyOffset; textyOffset = 0; DC->drawText(x + 4 + listPtr->columnInfo[j].pos, y + listPtr->elementHeight+ textyOffset, item->textscale, *color, text, listPtr->columnInfo[j].maxChars, item->textStyle, item->font); } } } else { text = DC->feederItemText(item->special, i, 0, &optionalImage); if (optionalImage >= 0) { //DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage); } else if (text) { DC->drawText(x + 4, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, item->textStyle, item->font); } } // The chosen text if (i == item->cursorPos) { DC->fillRect(x + 2, y + listPtr->elementHeight + 2, item->window.rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight+2, item->window.outlineColor); } size -= listPtr->elementHeight; if (size < listPtr->elementHeight) { listPtr->drawPadding = listPtr->elementHeight - size; break; } listPtr->endPos++; y += listPtr->elementHeight; // fit++; } } } } /* ================= BindingIDFromName ================= */ int BindingIDFromName( const char *name ) { size_t i; // iterate each command, set its default binding for ( i = 0; i < g_bindCount; i++ ) { if ( !Q_stricmp( name, g_bindCommands[i] ) ) return i; } return -1; } char g_nameBind[96]; /* ================= BindingFromName ================= */ void BindingFromName( const char *cvar ) { size_t i; int b1, b2; char sOR[32]; // iterate each command, set its default binding for ( i=0; i < g_bindCount; i++ ) { if ( !Q_stricmp(cvar, g_bindCommands[i] ) ) { b2 = g_bindKeys[i][1]; b1 = g_bindKeys[i][0]; if ( b1 == -1 ) break; if ( b2 != -1 ) { char keyname[2][32]; DC->keynumToStringBuf( b1, keyname[0], sizeof( keyname[0] ) ); // do NOT do this or it corrupts asian text!!! Q_strupr(keyname[0]); DC->keynumToStringBuf( b2, keyname[1], sizeof( keyname[1] ) ); // do NOT do this or it corrupts asian text!!! Q_strupr(keyname[1]); #ifdef JK2_MODE Q_strncpyz( sOR, ui.SP_GetStringTextString( "MENUS3_KEYBIND_OR" ), sizeof(sOR) ); #else Q_strncpyz( sOR, SE_GetString( "MENUS_KEYBIND_OR" ), sizeof(sOR) ); #endif Com_sprintf( g_nameBind, sizeof( g_nameBind ), "%s %s %s", keyname[0], sOR, keyname[1] ); } else { DC->keynumToStringBuf( b1, g_nameBind, sizeof( g_nameBind ) ); // do NOT do this or it corrupts asian text!!! Q_strupr(g_nameBind); } return; } } Q_strncpyz( g_nameBind, "???", sizeof( g_nameBind ) ); } /* ================= Item_Bind_Paint ================= */ void Item_Bind_Paint(itemDef_t *item) { vec4_t newColor, lowLight; float value,textScale,textWidth; int maxChars = 0, textHeight,yAdj,startingXPos; menuDef_t *parent = (menuDef_t*)item->parent; editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData; if (editPtr) { maxChars = editPtr->maxPaintChars; } value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0; if (item->window.flags & WINDOW_HASFOCUS) { if (g_bindItem == item) { lowLight[0] = 0.8f * 1.0f; lowLight[1] = 0.8f * 0.0f; lowLight[2] = 0.8f * 0.0f; lowLight[3] = 0.8f * 1.0f; } else { lowLight[0] = 0.8f * parent->focusColor[0]; lowLight[1] = 0.8f * parent->focusColor[1]; lowLight[2] = 0.8f * parent->focusColor[2]; lowLight[3] = 0.8f * parent->focusColor[3]; } LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin((float)(DC->realTime / PULSE_DIVISOR))); } else { Item_TextColor( item,&newColor); } if (item->text) { Item_Text_Paint(item); BindingFromName(item->cvar); // If the text runs past the limit bring the scale down until it fits. textScale = item->textscale; textWidth = DC->textWidth(g_nameBind,(float) textScale, uiInfo.uiDC.Assets.qhMediumFont); startingXPos = (item->textRect.x + item->textRect.w + 8); while ((startingXPos + textWidth) >= SCREEN_WIDTH) { textScale -= .05f; textWidth = DC->textWidth(g_nameBind,(float) textScale, uiInfo.uiDC.Assets.qhMediumFont); } // Try to adjust it's y placement if the scale has changed. yAdj = 0; if (textScale != item->textscale) { textHeight = DC->textHeight(g_nameBind, item->textscale, uiInfo.uiDC.Assets.qhMediumFont); yAdj = textHeight - DC->textHeight(g_nameBind, textScale, uiInfo.uiDC.Assets.qhMediumFont); } DC->drawText(startingXPos, item->textRect.y + yAdj, textScale, newColor, g_nameBind, maxChars/*item->textRect.w*/, item->textStyle, item->font); } else { DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "FIXME 1" : "FIXME 0", maxChars/*item->textRect.w*/, item->textStyle, item->font); } } void UI_ScaleModelAxis(refEntity_t *ent) { // scale the model should we need to if (ent->modelScale[0] && ent->modelScale[0] != 1.0f) { VectorScale( ent->axis[0], ent->modelScale[0] , ent->axis[0] ); ent->nonNormalizedAxes = qtrue; } if (ent->modelScale[1] && ent->modelScale[1] != 1.0f) { VectorScale( ent->axis[1], ent->modelScale[1] , ent->axis[1] ); ent->nonNormalizedAxes = qtrue; } if (ent->modelScale[2] && ent->modelScale[2] != 1.0f) { VectorScale( ent->axis[2], ent->modelScale[2] , ent->axis[2] ); ent->nonNormalizedAxes = qtrue; } } /* ================= Item_Model_Paint ================= */ extern int s_entityWavVol[MAX_GENTITIES]; //from snd_dma.cpp void UI_TalkingHead(itemDef_t *item) { // static int facial_blink = DC->realTime + Q_flrand(4000.0, 8000.0); static int facial_timer = DC->realTime + Q_flrand(10000.0, 30000.0); // static animNumber_t facial_anim = FACE_ALERT; int anim = -1; //are we blinking? /* if (facial_blink < 0) { // yes, check if we are we done blinking ? if (-(facial_blink) < DC->realTime) { // yes, so reset blink timer facial_blink = DC->realTime + Q_flrand(4000.0, 8000.0); CG_G2SetHeadBlink( cent, qfalse ); //stop the blink } } else // no we aren't blinking { if (facial_blink < DC->realTime)// but should we start ? { CG_G2SetHeadBlink( cent, qtrue ); if (facial_blink == 1) {//requested to stay shut by SET_FACEEYESCLOSED facial_blink = -(DC->realTime + 99999999.0f);// set blink timer } else { facial_blink = -(DC->realTime + 300.0f);// set blink timer } } } */ if (s_entityWavVol[0] > 0) // if we aren't talking, then it will be 0, -1 for talking but paused { anim = FACE_TALK1 + s_entityWavVol[0]-1; if( anim > FACE_TALK4 ) { anim = FACE_TALK4; } // reset timers so we don't start right away after talking facial_timer = DC->realTime + Q_flrand(2000.0, 7000.0); } else if (s_entityWavVol[0] == -1) {// talking, but silent anim = FACE_TALK0; // reset timers so we don't start right away after talking facial_timer = DC->realTime + Q_flrand(2000.0, 7000.0); } /* else if (s_entityWavVol[0] == 0) //don't anim if in a slient part of speech {//not talking if (facial_timer < 0) // are animating ? { //yes if (-(facial_timer) < DC->realTime)// are we done animating ? { // yes, reset timer facial_timer = DC->realTime + Q_flrand(10000.0, 30000.0); } else { // not yet, so choose anim anim = facial_anim; } } else // no we aren't animating { // but should we start ? if (facial_timer < DC->realTime) {//yes facial_anim = FACE_ALERT + Q_irand(0,2); //alert, smile, frown // set aux timer facial_timer = -(DC->realTime + 2000.0); anim = facial_anim; } } }//talking */ if (facial_timer < DC->realTime) {//restart the base anim // modelDef_t *modelPtr = (modelDef_t*)item->typeData; //ItemParse_model_g2anim_go( item, "BOTH_STAND5IDLE1" ); // facial_timer = DC->realTime + Q_flrand(2000.0, 7000.0) + DC->g2hilev_SetAnim(&item->ghoul2[0], "model_root", modelPtr->g2anim, qtrue); } if (anim != -1) { DC->g2hilev_SetAnim(&item->ghoul2[0], "face", anim, qfalse); } } /* ================= Item_Model_Paint ================= */ extern void UI_SaberDrawBlades( itemDef_t *item, vec3_t origin, float curYaw ); void Item_Model_Paint(itemDef_t *item) { float x, y, w, h; refdef_t refdef; refEntity_t ent; vec3_t mins, maxs, origin; vec3_t angles; const modelDef_t *modelPtr = (modelDef_t*)item->typeData; if (modelPtr == NULL) { return; } // Fuck all the logic --eez #ifdef JK2_MODE // setup the refdef memset( &refdef, 0, sizeof( refdef ) ); refdef.rdflags = RDF_NOWORLDMODEL; AxisClear( refdef.viewaxis ); x = item->window.rect.x+1; y = item->window.rect.y+1; w = item->window.rect.w-2; h = item->window.rect.h-2; refdef.x = x * DC->xscale; refdef.y = y * DC->yscale; refdef.width = w * DC->xscale; refdef.height = h * DC->yscale; DC->modelBounds( item->asset, mins, maxs ); origin[2] = -0.5 * ( mins[2] + maxs[2] ); origin[1] = 0.5 * ( mins[1] + maxs[1] ); // calculate distance so the model nearly fills the box if (qtrue) { float len = 0.5 * ( maxs[2] - mins[2] ); origin[0] = len / 0.268; // len / tan( fov/2 ) //origin[0] = len / tan(w/2); } else { origin[0] = item->textscale; } // WTF..? --eez //refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w; //refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h; refdef.fov_x = 45; refdef.fov_y = 45; //refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f); //xx = refdef.width / tan( refdef.fov_x / 360 * M_PI ); //refdef.fov_y = atan2( refdef.height, xx ); //refdef.fov_y *= ( 360 / M_PI ); DC->clearScene(); refdef.time = DC->realTime; // add the model memset( &ent, 0, sizeof(ent) ); //adjust = 5.0 * sin( (float)uis.realtime / 500 ); //adjust = 360 % (int)((float)uis.realtime / 1000); //VectorSet( angles, 0, 0, 1 ); // use item storage to track /* if (modelPtr->rotationSpeed) { if (DC->realTime > item->window.nextTime) { item->window.nextTime = DC->realTime + modelPtr->rotationSpeed; modelPtr->angle = (int)(modelPtr->angle + 1) % 360; } } VectorSet( angles, 0, modelPtr->angle, 0 ); */ VectorSet( angles, 0, (float)(refdef.time/20.0f), 0); AnglesToAxis( angles, ent.axis ); ent.hModel = item->asset; VectorCopy( origin, ent.origin ); VectorCopy( ent.origin, ent.oldorigin ); // Set up lighting VectorCopy( refdef.vieworg, ent.lightingOrigin ); ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW; DC->addRefEntityToScene( &ent ); DC->renderScene( &refdef ); #else // a moves datapad anim is playing if (uiInfo.moveAnimTime && (uiInfo.moveAnimTime < uiInfo.uiDC.realTime)) { modelDef_t *modelPtr; modelPtr = (modelDef_t*)item->typeData; if (modelPtr) { //HACKHACKHACK: check for any multi-part anim sequences, and play the next anim, if needbe switch( modelPtr->g2anim ) { case BOTH_FORCEWALLREBOUND_FORWARD: case BOTH_FORCEJUMP1: ItemParse_model_g2anim_go( item, animTable[BOTH_FORCEINAIR1].name ); uiInfo.moveAnimTime = DC->g2hilev_SetAnim(&item->ghoul2[0], "model_root", modelPtr->g2anim, qtrue); if ( !uiInfo.moveAnimTime ) { uiInfo.moveAnimTime = 500; } uiInfo.moveAnimTime += uiInfo.uiDC.realTime; break; case BOTH_FORCEINAIR1: ItemParse_model_g2anim_go( item, animTable[BOTH_FORCELAND1].name ); uiInfo.moveAnimTime = DC->g2hilev_SetAnim(&item->ghoul2[0], "model_root", modelPtr->g2anim, qtrue); uiInfo.moveAnimTime += uiInfo.uiDC.realTime; break; case BOTH_FORCEWALLRUNFLIP_START: ItemParse_model_g2anim_go( item, animTable[BOTH_FORCEWALLRUNFLIP_END].name ); uiInfo.moveAnimTime = DC->g2hilev_SetAnim(&item->ghoul2[0], "model_root", modelPtr->g2anim, qtrue); uiInfo.moveAnimTime += uiInfo.uiDC.realTime; break; case BOTH_FORCELONGLEAP_START: ItemParse_model_g2anim_go( item, animTable[BOTH_FORCELONGLEAP_LAND].name ); uiInfo.moveAnimTime = DC->g2hilev_SetAnim(&item->ghoul2[0], "model_root", modelPtr->g2anim, qtrue); uiInfo.moveAnimTime += uiInfo.uiDC.realTime; break; case BOTH_KNOCKDOWN3://on front - into force getup DC->startLocalSound(uiInfo.uiDC.Assets.datapadmoveJumpSound, CHAN_LOCAL ); ItemParse_model_g2anim_go( item, animTable[BOTH_FORCE_GETUP_F1].name ); uiInfo.moveAnimTime = DC->g2hilev_SetAnim(&item->ghoul2[0], "model_root", modelPtr->g2anim, qtrue); uiInfo.moveAnimTime += uiInfo.uiDC.realTime; break; case BOTH_KNOCKDOWN2://on back - kick forward getup DC->startLocalSound(uiInfo.uiDC.Assets.datapadmoveJumpSound, CHAN_LOCAL ); ItemParse_model_g2anim_go( item, animTable[BOTH_GETUP_BROLL_F].name ); uiInfo.moveAnimTime = DC->g2hilev_SetAnim(&item->ghoul2[0], "model_root", modelPtr->g2anim, qtrue); uiInfo.moveAnimTime += uiInfo.uiDC.realTime; break; case BOTH_KNOCKDOWN1://on back - roll-away DC->startLocalSound(uiInfo.uiDC.Assets.datapadmoveRollSound, CHAN_LOCAL ); ItemParse_model_g2anim_go( item, animTable[BOTH_GETUP_BROLL_R].name ); uiInfo.moveAnimTime = DC->g2hilev_SetAnim(&item->ghoul2[0], "model_root", modelPtr->g2anim, qtrue); uiInfo.moveAnimTime += uiInfo.uiDC.realTime; break; default: ItemParse_model_g2anim_go( item, uiInfo.movesBaseAnim ); DC->g2hilev_SetAnim(&item->ghoul2[0], "model_root", modelPtr->g2anim, qtrue); uiInfo.moveAnimTime = 0; break; } } } // setup the refdef memset( &refdef, 0, sizeof( refdef ) ); refdef.rdflags = RDF_NOWORLDMODEL; AxisClear( refdef.viewaxis ); x = item->window.rect.x+1; y = item->window.rect.y+1; w = item->window.rect.w-2; h = item->window.rect.h-2; refdef.x = x * DC->xscale; refdef.y = y * DC->yscale; refdef.width = w * DC->xscale; refdef.height = h * DC->yscale; if (item->flags&ITF_G2VALID) { //ghoul2 models don't have bounds, so we have to parse them. VectorCopy(modelPtr->g2mins, mins); VectorCopy(modelPtr->g2maxs, maxs); if (!mins[0] && !mins[1] && !mins[2] && !maxs[0] && !maxs[1] && !maxs[2]) { //we'll use defaults then I suppose. VectorSet(mins, -16, -16, -24); VectorSet(maxs, 16, 16, 32); } } else { DC->modelBounds( item->asset, mins, maxs ); } origin[2] = -0.5 * ( mins[2] + maxs[2] ); origin[1] = 0.5 * ( mins[1] + maxs[1] ); refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : (int)((float)refdef.width / 640.0f * 90.0f); refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : atan2( refdef.height, refdef.width / tan( refdef.fov_x / 360 * M_PI ) ) * ( 360 / M_PI ); // refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : refdef.width; // refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : refdef.height; // calculate distance so the model nearly fills the box float len = 0.5 * ( maxs[2] - mins[2] ); origin[0] = len / 0.268; DC->clearScene(); refdef.time = DC->realTime; // add the model memset( &ent, 0, sizeof(ent) ); // use item storage to track float curYaw = modelPtr->angle; if (modelPtr->rotationSpeed) { curYaw += (float)refdef.time/modelPtr->rotationSpeed; } if ( item->flags&ITF_ISANYSABER && !(item->flags&ITF_ISCHARACTER) ) {//hack to put saber on it's side VectorSet( angles, curYaw, 0, 90 ); } else { VectorSet( angles, 0, curYaw, 0 ); } AnglesToAxis( angles, ent.axis ); if (item->flags&ITF_G2VALID) { ent.ghoul2 = &item->ghoul2; ent.radius = 1000; ent.customSkin = modelPtr->g2skin; if ( (item->flags&ITF_ISCHARACTER) ) { ent.shaderRGBA[0] = ui_char_color_red.integer; ent.shaderRGBA[1] = ui_char_color_green.integer; ent.shaderRGBA[2] = ui_char_color_blue.integer; ent.shaderRGBA[3] = 255; UI_TalkingHead(item); } if ( item->flags&ITF_ISANYSABER ) {//UGH, draw the saber blade! UI_SaberDrawBlades( item, origin, curYaw ); } } else { ent.hModel = item->asset; } VectorCopy( origin, ent.origin ); VectorCopy( ent.origin, ent.oldorigin ); // Set up lighting //VectorCopy( refdef.vieworg, ent.lightingOrigin ); ent.renderfx = RF_NOSHADOW; ui.R_AddLightToScene(refdef.vieworg, 500, 1, 1, 1); //fixme: specify in menu file! DC->addRefEntityToScene( &ent ); DC->renderScene( &refdef ); #endif } /* ================= Item_OwnerDraw_Paint ================= */ void Item_OwnerDraw_Paint(itemDef_t *item) { menuDef_t *parent; if (item == NULL) { return; } parent = (menuDef_t*)item->parent; if (DC->ownerDrawItem) { vec4_t color, lowLight; Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount); memcpy(&color, &item->window.foreColor, sizeof(color)); if (item->numColors > 0 && DC->getValue) { // if the value is within one of the ranges then set color to that, otherwise leave at default int i; float f = DC->getValue(item->window.ownerDraw); for (i = 0; i < item->numColors; i++) { if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high) { memcpy(&color, &item->colorRanges[i].color, sizeof(color)); break; } } } if (item->window.flags & WINDOW_HASFOCUS) { lowLight[0] = 0.8 * parent->focusColor[0]; lowLight[1] = 0.8 * parent->focusColor[1]; lowLight[2] = 0.8 * parent->focusColor[2]; lowLight[3] = 0.8 * parent->focusColor[3]; LerpColor(parent->focusColor,lowLight,color,0.5+0.5*sin((float)(DC->realTime / PULSE_DIVISOR))); } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) { lowLight[0] = 0.8 * item->window.foreColor[0]; lowLight[1] = 0.8 * item->window.foreColor[1]; lowLight[2] = 0.8 * item->window.foreColor[2]; lowLight[3] = 0.8 * item->window.foreColor[3]; LerpColor(item->window.foreColor,lowLight,color,0.5+0.5*sin((float)(DC->realTime / PULSE_DIVISOR))); } if ( item->disabled ) memcpy( color, parent->disableColor, sizeof( vec4_t ) ); if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) { memcpy(color, parent->disableColor, sizeof(vec4_t)); } if (item->text) { Item_Text_Paint(item); // +8 is an offset kludge to properly align owner draw items that have text combined with them DC->ownerDrawItem(item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle, item->font ); } else { DC->ownerDrawItem(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, item->textalignx, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle, item->font ); } } } void Item_YesNo_Paint(itemDef_t *item) { vec4_t color; float value; value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0; #ifdef JK2_MODE const char *psYes = ui.SP_GetStringTextString( "MENUS0_YES" ); const char *psNo = ui.SP_GetStringTextString( "MENUS0_NO" ); #else const char *psYes = SE_GetString( "MENUS_YES" ); const char *psNo = SE_GetString( "MENUS_NO" ); #endif const char *yesnovalue; if (item->invertYesNo) yesnovalue = (value == 0) ? psYes : psNo; else yesnovalue = (value != 0) ? psYes : psNo; Item_TextColor(item, &color); if (item->text) { Item_Text_Paint(item); DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, color, yesnovalue, 0, item->textStyle, item->font); } else { DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, yesnovalue , 0, item->textStyle, item->font); } } /* ================= Item_Multi_Paint ================= */ void Item_Multi_Paint(itemDef_t *item) { vec4_t color; const char *text = ""; text = Item_Multi_Setting(item); if (*text == '@') // string reference { text = SE_GetString( &text[1] ); } Item_TextColor(item, &color); if (item->text) { Item_Text_Paint(item); DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, color, text, 0, item->textStyle, item->font); } else { //JLF added xoffset DC->drawText(item->textRect.x +item->xoffset, item->textRect.y, item->textscale, color, text, 0, item->textStyle, item->font); } } int Item_TextScroll_MaxScroll ( itemDef_t *item ) { textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; int count = scrollPtr->iLineCount; int max = count - (int)(item->window.rect.h / scrollPtr->lineHeight) + 1; if (max < 0) { return 0; } return max; } int Item_TextScroll_ThumbPosition ( itemDef_t *item ) { float max, pos, size; textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; max = Item_TextScroll_MaxScroll ( item ); size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2; if (max > 0) { pos = (size-SCROLLBAR_SIZE) / (float) max; } else { pos = 0; } pos *= scrollPtr->startPos; return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos; } int Item_TextScroll_ThumbDrawPosition ( itemDef_t *item ) { int min, max; if (itemCapture == item) { min = item->window.rect.y + SCROLLBAR_SIZE + 1; max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1; if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) { return DC->cursory - SCROLLBAR_SIZE/2; } return Item_TextScroll_ThumbPosition(item); } return Item_TextScroll_ThumbPosition(item); } int Item_TextScroll_OverLB ( itemDef_t *item, float x, float y ) { rectDef_t r; textScrollDef_t *scrollPtr; int thumbstart; scrollPtr = (textScrollDef_t*)item->typeData; // Scroll bar isn't drawing so ignore this input if ((( scrollPtr->iLineCount * scrollPtr->lineHeight ) <= (item->window.rect.h - 2)) && (item->type == ITEM_TYPE_TEXTSCROLL)) { return 0; } r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE; r.y = item->window.rect.y; r.h = r.w = SCROLLBAR_SIZE; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_LEFTARROW; } r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_RIGHTARROW; } thumbstart = Item_TextScroll_ThumbPosition(item); r.y = thumbstart; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_THUMB; } r.y = item->window.rect.y + SCROLLBAR_SIZE; r.h = thumbstart - r.y; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_PGUP; } r.y = thumbstart + SCROLLBAR_SIZE; r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_PGDN; } return 0; } void Item_TextScroll_MouseEnter (itemDef_t *item, float x, float y) { item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN); item->window.flags |= Item_TextScroll_OverLB(item, x, y); } /* ================= Item_Slider_ThumbPosition ================= */ int Item_ListBox_ThumbDrawPosition(itemDef_t *item) { int min, max; if (itemCapture == item) { if (item->window.flags & WINDOW_HORIZONTAL) { min = item->window.rect.x + SCROLLBAR_SIZE + 1; max = item->window.rect.x + item->window.rect.w - 2*SCROLLBAR_SIZE - 1; if (DC->cursorx >= min + SCROLLBAR_SIZE/2 && DC->cursorx <= max + SCROLLBAR_SIZE/2) { return DC->cursorx - SCROLLBAR_SIZE/2; } else { return Item_ListBox_ThumbPosition(item); } } else { min = item->window.rect.y + SCROLLBAR_SIZE + 1; max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1; if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) { return DC->cursory - SCROLLBAR_SIZE/2; } else { return Item_ListBox_ThumbPosition(item); } } } else { return Item_ListBox_ThumbPosition(item); } } /* ================= Item_Slider_ThumbPosition ================= */ float Item_Slider_ThumbPosition(itemDef_t *item) { float value, range, x; editFieldDef_t *editDef = (editFieldDef_t *) item->typeData; if (item->text) { x = item->textRect.x + item->textRect.w + 8; } else { x = item->window.rect.x; } if (!editDef || !item->cvar) { return x; } value = DC->getCVarValue(item->cvar); if (value < editDef->minVal) { value = editDef->minVal; } else if (value > editDef->maxVal) { value = editDef->maxVal; } range = editDef->maxVal - editDef->minVal; value -= editDef->minVal; value /= range; //value /= (editDef->maxVal - editDef->minVal); value *= SLIDER_WIDTH; x += value; // vm fuckage //x = x + (((float)value / editDef->maxVal) * SLIDER_WIDTH); return x; } /* ================= Item_Slider_Paint ================= */ void Item_Slider_Paint(itemDef_t *item) { vec4_t newColor, lowLight; float x, y; menuDef_t *parent = (menuDef_t*)item->parent; if (item->window.flags & WINDOW_HASFOCUS) { lowLight[0] = 0.8 * parent->focusColor[0]; lowLight[1] = 0.8 * parent->focusColor[1]; lowLight[2] = 0.8 * parent->focusColor[2]; lowLight[3] = 0.8 * parent->focusColor[3]; LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin((float)(DC->realTime / PULSE_DIVISOR))); } else { memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t)); } y = item->window.rect.y; if (item->text) { Item_Text_Paint(item); x = item->textRect.x + item->textRect.w + 8; } else { x = item->window.rect.x; } DC->setColor(newColor); DC->drawHandlePic( x, y+2, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar ); x = Item_Slider_ThumbPosition(item); // DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y - 2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb ); DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y+2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb ); } /* ================= Item_Paint ================= */ static qboolean Item_Paint(itemDef_t *item, qboolean bDraw) { int xPos,textWidth; vec4_t red; menuDef_t *parent; red[0] = red[3] = 1; red[1] = red[2] = 0; if (item == NULL) { return qfalse; } parent = (menuDef_t*)item->parent; if (item->window.flags & WINDOW_SCRIPTWAITING) { if (DC->realTime > item->window.delayTime) { // Time has elapsed, resume running whatever script we saved item->window.flags &= ~WINDOW_SCRIPTWAITING; Item_RunScript(item, item->window.delayedScript); } } if (item->window.flags & WINDOW_ORBITING) { if (DC->realTime > item->window.nextTime) { float rx, ry, a, c, s, w, h; item->window.nextTime = DC->realTime + item->window.offsetTime; // translate w = item->window.rectClient.w / 2; h = item->window.rectClient.h / 2; rx = item->window.rectClient.x + w - item->window.rectEffects.x; ry = item->window.rectClient.y + h - item->window.rectEffects.y; a = (float) (3 * M_PI / 180); c = cos(a); s = sin(a); item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w; item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h; Item_UpdatePosition(item); } } if (item->window.flags & WINDOW_INTRANSITION) { if (DC->realTime > item->window.nextTime) { int done = 0; item->window.nextTime = DC->realTime + item->window.offsetTime; // transition the x,y if (item->window.rectClient.x == item->window.rectEffects.x) { done++; } else { if (item->window.rectClient.x < item->window.rectEffects.x) { item->window.rectClient.x += item->window.rectEffects2.x; if (item->window.rectClient.x > item->window.rectEffects.x) { item->window.rectClient.x = item->window.rectEffects.x; done++; } } else { item->window.rectClient.x -= item->window.rectEffects2.x; if (item->window.rectClient.x < item->window.rectEffects.x) { item->window.rectClient.x = item->window.rectEffects.x; done++; } } } if (item->window.rectClient.y == item->window.rectEffects.y) { done++; } else { if (item->window.rectClient.y < item->window.rectEffects.y) { item->window.rectClient.y += item->window.rectEffects2.y; if (item->window.rectClient.y > item->window.rectEffects.y) { item->window.rectClient.y = item->window.rectEffects.y; done++; } } else { item->window.rectClient.y -= item->window.rectEffects2.y; if (item->window.rectClient.y < item->window.rectEffects.y) { item->window.rectClient.y = item->window.rectEffects.y; done++; } } } if (item->window.rectClient.w == item->window.rectEffects.w) { done++; } else { if (item->window.rectClient.w < item->window.rectEffects.w) { item->window.rectClient.w += item->window.rectEffects2.w; if (item->window.rectClient.w > item->window.rectEffects.w) { item->window.rectClient.w = item->window.rectEffects.w; done++; } } else { item->window.rectClient.w -= item->window.rectEffects2.w; if (item->window.rectClient.w < item->window.rectEffects.w) { item->window.rectClient.w = item->window.rectEffects.w; done++; } } } if (item->window.rectClient.h == item->window.rectEffects.h) { done++; } else { if (item->window.rectClient.h < item->window.rectEffects.h) { item->window.rectClient.h += item->window.rectEffects2.h; if (item->window.rectClient.h > item->window.rectEffects.h) { item->window.rectClient.h = item->window.rectEffects.h; done++; } } else { item->window.rectClient.h -= item->window.rectEffects2.h; if (item->window.rectClient.h < item->window.rectEffects.h) { item->window.rectClient.h = item->window.rectEffects.h; done++; } } } Item_UpdatePosition(item); if (done == 4) { item->window.flags &= ~WINDOW_INTRANSITION; } } } #ifdef _TRANS3 //JLF begin model transition stuff if (item->window.flags & WINDOW_INTRANSITIONMODEL) { if ( item->type == ITEM_TYPE_MODEL) { //fields ing modelptr // vec3_t g2mins2, g2maxs2, g2minsEffect, g2maxsEffect; // float fov_x2, fov_y2, fov_Effectx, fov_Effecty; modelDef_t * modelptr = (modelDef_t *)item->typeData; if (DC->realTime > item->window.nextTime) { int done = 0; item->window.nextTime = DC->realTime + item->window.offsetTime; // transition the x,y,z max if (modelptr->g2maxs[0] == modelptr->g2maxs2[0]) { done++; } else { if (modelptr->g2maxs[0] < modelptr->g2maxs2[0]) { modelptr->g2maxs[0] += modelptr->g2maxsEffect[0]; if (modelptr->g2maxs[0] > modelptr->g2maxs2[0]) { modelptr->g2maxs[0] = modelptr->g2maxs2[0]; done++; } } else { modelptr->g2maxs[0] -= modelptr->g2maxsEffect[0]; if (modelptr->g2maxs[0] < modelptr->g2maxs2[0]) { modelptr->g2maxs[0] = modelptr->g2maxs2[0]; done++; } } } //y if (modelptr->g2maxs[1] == modelptr->g2maxs2[1]) { done++; } else { if (modelptr->g2maxs[1] < modelptr->g2maxs2[1]) { modelptr->g2maxs[1] += modelptr->g2maxsEffect[1]; if (modelptr->g2maxs[1] > modelptr->g2maxs2[1]) { modelptr->g2maxs[1] = modelptr->g2maxs2[1]; done++; } } else { modelptr->g2maxs[1] -= modelptr->g2maxsEffect[1]; if (modelptr->g2maxs[1] < modelptr->g2maxs2[1]) { modelptr->g2maxs[1] = modelptr->g2maxs2[1]; done++; } } } //z if (modelptr->g2maxs[2] == modelptr->g2maxs2[2]) { done++; } else { if (modelptr->g2maxs[2] < modelptr->g2maxs2[2]) { modelptr->g2maxs[2] += modelptr->g2maxsEffect[2]; if (modelptr->g2maxs[2] > modelptr->g2maxs2[2]) { modelptr->g2maxs[2] = modelptr->g2maxs2[2]; done++; } } else { modelptr->g2maxs[2] -= modelptr->g2maxsEffect[2]; if (modelptr->g2maxs[2] < modelptr->g2maxs2[2]) { modelptr->g2maxs[2] = modelptr->g2maxs2[2]; done++; } } } // transition the x,y,z min if (modelptr->g2mins[0] == modelptr->g2mins2[0]) { done++; } else { if (modelptr->g2mins[0] < modelptr->g2mins2[0]) { modelptr->g2mins[0] += modelptr->g2minsEffect[0]; if (modelptr->g2mins[0] > modelptr->g2mins2[0]) { modelptr->g2mins[0] = modelptr->g2mins2[0]; done++; } } else { modelptr->g2mins[0] -= modelptr->g2minsEffect[0]; if (modelptr->g2mins[0] < modelptr->g2mins2[0]) { modelptr->g2mins[0] = modelptr->g2mins2[0]; done++; } } } //y if (modelptr->g2mins[1] == modelptr->g2mins2[1]) { done++; } else { if (modelptr->g2mins[1] < modelptr->g2mins2[1]) { modelptr->g2mins[1] += modelptr->g2minsEffect[1]; if (modelptr->g2mins[1] > modelptr->g2mins2[1]) { modelptr->g2mins[1] = modelptr->g2mins2[1]; done++; } } else { modelptr->g2mins[1] -= modelptr->g2minsEffect[1]; if (modelptr->g2mins[1] < modelptr->g2mins2[1]) { modelptr->g2mins[1] = modelptr->g2mins2[1]; done++; } } } //z if (modelptr->g2mins[2] == modelptr->g2mins2[2]) { done++; } else { if (modelptr->g2mins[2] < modelptr->g2mins2[2]) { modelptr->g2mins[2] += modelptr->g2minsEffect[2]; if (modelptr->g2mins[2] > modelptr->g2mins2[2]) { modelptr->g2mins[2] = modelptr->g2mins2[2]; done++; } } else { modelptr->g2mins[2] -= modelptr->g2minsEffect[2]; if (modelptr->g2mins[2] < modelptr->g2mins2[2]) { modelptr->g2mins[2] = modelptr->g2mins2[2]; done++; } } } //fovx if (modelptr->fov_x == modelptr->fov_x2) { done++; } else { if (modelptr->fov_x < modelptr->fov_x2) { modelptr->fov_x += modelptr->fov_Effectx; if (modelptr->fov_x > modelptr->fov_x2) { modelptr->fov_x = modelptr->fov_x2; done++; } } else { modelptr->fov_x -= modelptr->fov_Effectx; if (modelptr->fov_x < modelptr->fov_x2) { modelptr->fov_x = modelptr->fov_x2; done++; } } } //fovy if (modelptr->fov_y == modelptr->fov_y2) { done++; } else { if (modelptr->fov_y < modelptr->fov_y2) { modelptr->fov_y += modelptr->fov_Effecty; if (modelptr->fov_y > modelptr->fov_y2) { modelptr->fov_y = modelptr->fov_y2; done++; } } else { modelptr->fov_y -= modelptr->fov_Effecty; if (modelptr->fov_y < modelptr->fov_y2) { modelptr->fov_y = modelptr->fov_y2; done++; } } } if (done == 5) { item->window.flags &= ~WINDOW_INTRANSITIONMODEL; } } } } #endif //JLF end transition stuff for models if (item->window.ownerDrawFlags && DC->ownerDrawVisible) { if (!DC->ownerDrawVisible(item->window.ownerDrawFlags)) { item->window.flags &= ~WINDOW_VISIBLE; } else { item->window.flags |= WINDOW_VISIBLE; } } if (item->disabled && item->disabledHidden) { return qfalse; } if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE)) { if (!Item_EnableShowViaCvar(item, CVAR_SHOW)) { return qfalse; } } if (item->window.flags & WINDOW_TIMEDVISIBLE) { } if (!(item->window.flags & WINDOW_VISIBLE)) { return qfalse; } if (!bDraw) { return qtrue; } //okay to paint //JLFMOUSE if (item->window.flags & WINDOW_MOUSEOVER) { if (item->descText && !Display_KeyBindPending()) { // Make DOUBLY sure that this item should have desctext. // NOTE : we can't just check the mouse position on this, what if we TABBED // to the current menu item -- in that case our mouse isn't over the item. // Removing the WINDOW_MOUSEOVER flag just prevents the item's OnExit script from running // if (!Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) // { // It isn't something that should, because it isn't live anymore. // item->window.flags &= ~WINDOW_MOUSEOVER; // } // else //END JLFMOUSE // items can be enabled and disabled based on cvars if( !(item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) ) { // Draw the desctext const char *textPtr = item->descText; if (*textPtr == '@') // string reference { textPtr = SE_GetString( &textPtr[1] ); } vec4_t color = {1, 1, 1, 1}; Item_TextColor(item, &color); float fDescScale = parent->descScale ? parent->descScale : 1; float fDescScaleCopy = fDescScale; while (1) { // FIXME - add some type of parameter in the menu file like descfont to specify the font for the descriptions for this menu. textWidth = DC->textWidth(textPtr, fDescScale, 4); // item->font); if (parent->descAlignment == ITEM_ALIGN_RIGHT) { xPos = parent->descX - textWidth; // Right justify } else if (parent->descAlignment == ITEM_ALIGN_CENTER) { xPos = parent->descX - (textWidth/2); // Center justify } else // Left justify { xPos = parent->descX; } if (parent->descAlignment == ITEM_ALIGN_CENTER) { // only this one will auto-shrink the scale until we eventually fit... // if (xPos + textWidth > (SCREEN_WIDTH-4)) { fDescScale -= 0.001f; continue; } } // Try to adjust it's y placement if the scale has changed... // int iYadj = 0; if (fDescScale != fDescScaleCopy) { int iOriginalTextHeight = DC->textHeight(textPtr, fDescScaleCopy, uiInfo.uiDC.Assets.qhMediumFont); iYadj = iOriginalTextHeight - DC->textHeight(textPtr, fDescScale, uiInfo.uiDC.Assets.qhMediumFont); } // FIXME - add some type of parameter in the menu file like descfont to specify the font for the descriptions for this menu. DC->drawText(xPos, parent->descY + iYadj, fDescScale, parent->descColor, textPtr, 0, parent->descTextStyle, 4); //item->font); break; } } } } // paint the rect first.. Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle); // Print a box showing the extents of the rectangle, when in debug mode if (uis.debugMode) { vec4_t color; color[1] = color[3] = 1; color[0] = color[2] = 0; DC->drawRect( item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, color); } //DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red); switch (item->type) { case ITEM_TYPE_OWNERDRAW: Item_OwnerDraw_Paint(item); break; case ITEM_TYPE_TEXT: case ITEM_TYPE_BUTTON: Item_Text_Paint(item); break; case ITEM_TYPE_RADIOBUTTON: break; case ITEM_TYPE_CHECKBOX: break; case ITEM_TYPE_EDITFIELD: case ITEM_TYPE_NUMERICFIELD: Item_TextField_Paint(item); break; case ITEM_TYPE_COMBO: break; case ITEM_TYPE_LISTBOX: Item_ListBox_Paint(item); break; case ITEM_TYPE_TEXTSCROLL: Item_TextScroll_Paint ( item ); break; case ITEM_TYPE_MODEL: Item_Model_Paint(item); break; case ITEM_TYPE_YESNO: Item_YesNo_Paint(item); break; case ITEM_TYPE_MULTI: Item_Multi_Paint(item); break; case ITEM_TYPE_BIND: Item_Bind_Paint(item); break; case ITEM_TYPE_SLIDER: Item_Slider_Paint(item); break; default: break; } return qtrue; } /* ================= LerpColor ================= */ void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t) { int i; // lerp and clamp each component for (i=0; i<4; i++) { c[i] = a[i] + t*(b[i]-a[i]); if (c[i] < 0) { c[i] = 0; } else if (c[i] > 1.0) { c[i] = 1.0; } } } /* ================= Fade ================= */ void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount) { if (*flags & (WINDOW_FADINGOUT | WINDOW_FADINGIN)) { if (DC->realTime > *nextTime) { *nextTime = DC->realTime + offsetTime; if (*flags & WINDOW_FADINGOUT) { *f -= fadeAmount; if (bFlags && *f <= 0.0) { *flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE); } } else { *f += fadeAmount; if (*f >= clamp) { *f = clamp; if (bFlags) { *flags &= ~WINDOW_FADINGIN; } } } } } } /* ================= GradientBar_Paint ================= */ void GradientBar_Paint(rectDef_t *rect, vec4_t color) { // gradient bar takes two paints DC->setColor( color ); DC->drawHandlePic(rect->x, rect->y, rect->w, rect->h, DC->Assets.gradientBar); DC->setColor( NULL ); } /* ================= Window_Paint ================= */ void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle) { //float bordersize = 0; vec4_t color; rectDef_t fillRect = w->rect; if (uis.debugMode) { color[0] = color[1] = color[2] = color[3] = 1; DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, 1, color); } if (w == NULL || (w->style == 0 && w->border == 0)) { return; } if (w->border != 0) { fillRect.x += w->borderSize; fillRect.y += w->borderSize; fillRect.w -= w->borderSize + 1; fillRect.h -= w->borderSize + 1; } if (w->style == WINDOW_STYLE_FILLED) { // box, but possible a shader that needs filled if (w->background) { Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount); DC->setColor(w->backColor); DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background); DC->setColor(NULL); } else { DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor); } } else if (w->style == WINDOW_STYLE_GRADIENT) { GradientBar_Paint(&fillRect, w->backColor); // gradient bar } else if (w->style == WINDOW_STYLE_SHADER) { if (w->flags & WINDOW_PLAYERCOLOR) { vec4_t color; color[0] = ui_char_color_red.integer/255.0f; color[1] = ui_char_color_green.integer/255.0f; color[2] = ui_char_color_blue.integer/255.0f; color[3] = 1; ui.R_SetColor(color); } else if (w->flags & WINDOW_FORECOLORSET) { DC->setColor(w->foreColor); } DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background); DC->setColor(NULL); } if (w->border == WINDOW_BORDER_FULL) { // full // HACK HACK HACK if (w->style == WINDOW_STYLE_TEAMCOLOR) { if (color[0] > 0) { // red color[0] = 1; color[1] = color[2] = .5; } else { color[2] = 1; color[0] = color[1] = .5; } color[3] = 1; DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, color); } else { DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor); } } else if (w->border == WINDOW_BORDER_HORZ) { // top/bottom DC->setColor(w->borderColor); DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize); DC->setColor( NULL ); } else if (w->border == WINDOW_BORDER_VERT) { // left right DC->setColor(w->borderColor); DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize); DC->setColor( NULL ); } else if (w->border == WINDOW_BORDER_KCGRADIENT) { // this is just two gradient bars along each horz edge rectDef_t r = w->rect; r.h = w->borderSize; GradientBar_Paint(&r, w->borderColor); r.y = w->rect.y + w->rect.h - 1; GradientBar_Paint(&r, w->borderColor); } } /* ================= Display_KeyBindPending ================= */ qboolean Display_KeyBindPending(void) { return g_waitingForKey; } /* ================= ToWindowCoords ================= */ void ToWindowCoords(float *x, float *y, windowDef_t *window) { if (window->border != 0) { *x += window->borderSize; *y += window->borderSize; } *x += window->rect.x; *y += window->rect.y; } /* ================= Item_Text_AutoWrapped_Paint ================= */ void Item_Text_AutoWrapped_Paint(itemDef_t *item) { char text[1024]; const char *p, *textPtr, *newLinePtr; char buff[1024]; int height, len, textWidth, newLine, newLineWidth; float y; vec4_t color; textWidth = 0; newLinePtr = NULL; if (item->text == NULL) { if (item->cvar == NULL) { return; } else { DC->getCVarString(item->cvar, text, sizeof(text)); textPtr = text; } } else { textPtr = item->text; } if (*textPtr == '@') // string reference { textPtr = SE_GetString( &textPtr[1] ); } if (*textPtr == '\0') { return; } Item_TextColor(item, &color); //Item_SetTextExtents(item, &width, &height, textPtr); if (item->value == 0) { item->value = (int)(0.5 + (float)DC->textWidth(textPtr, item->textscale, item->font) / item->window.rect.w); } height = DC->textHeight(textPtr, item->textscale, item->font); item->special = 0; y = item->textaligny; len = 0; buff[0] = '\0'; newLine = 0; newLineWidth = 0; p = textPtr; int line = 1; while (1) //findmeste (this will break widechar languages)! { if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\0') { newLine = len; newLinePtr = p+1; newLineWidth = textWidth; } textWidth = DC->textWidth(buff, item->textscale, 0); if ( (newLine && textWidth >= item->window.rect.w - item->textalignx) || *p == '\n' || *p == '\0') { if (line > item->cursorPos) //scroll { if (len) { if (item->textalignment == ITEM_ALIGN_LEFT) { item->textRect.x = item->textalignx; } else if (item->textalignment == ITEM_ALIGN_RIGHT) { item->textRect.x = item->textalignx - newLineWidth; } else if (item->textalignment == ITEM_ALIGN_CENTER) { item->textRect.x = item->textalignx - newLineWidth / 2; } item->textRect.y = y; ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window); // buff[newLine] = '\0'; if ( *p && y + height + 4 > item->window.rect.h - height) { item->special = 1; strcat(buff,"...");//uhh, let's render some ellipses } DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, buff, 0, item->textStyle, item->font); } y += height + 4; if ( y > item->window.rect.h - height) {//reached the bottom of the box, so stop break; } len = 0; } else { strcpy(buff,"..."); len = 3; } if (*p == '\0') { //end of string break; } p = newLinePtr; newLine = 0; newLineWidth = 0; line++; } buff[len++] = *p++; buff[len] = '\0'; } item->textRect = item->window.rect; } /* ================= Rect_ContainsPoint ================= */ static qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) { //JLF ignore mouse pointer location // return true; // END JLF if (rect) { // if ((x > rect->x) && (x < (rect->x + rect->w)) && (y > rect->y) && (y < (rect->y + rect->h))) if ((x > rect->x) && (x < (rect->x + rect->w))) { if ((y > rect->y) && (y < (rect->y + rect->h))) { return qtrue; } } } return qfalse; } qboolean Item_TextScroll_HandleKey ( itemDef_t *item, int key, qboolean down, qboolean force) { textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; int max; int viewmax; if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) { max = Item_TextScroll_MaxScroll(item); viewmax = (item->window.rect.h / scrollPtr->lineHeight); if ( key == A_CURSOR_UP || key == A_KP_8 ) { scrollPtr->startPos--; if (scrollPtr->startPos < 0) { scrollPtr->startPos = 0; } return qtrue; } if ( key == A_CURSOR_DOWN || key == A_KP_2 ) { scrollPtr->startPos++; if (scrollPtr->startPos > max) { scrollPtr->startPos = max; } return qtrue; } //Raz: Added if ( key == A_MWHEELUP ) { scrollPtr->startPos--; if (scrollPtr->startPos < 0) { scrollPtr->startPos = 0; Display_MouseMove(NULL, DC->cursorx, DC->cursory); return qfalse; } Display_MouseMove(NULL, DC->cursorx, DC->cursory); return qtrue; } if ( key == A_MWHEELDOWN ) { scrollPtr->startPos++; if (scrollPtr->startPos > max) { scrollPtr->startPos = max; Display_MouseMove(NULL, DC->cursorx, DC->cursory); return qfalse; } Display_MouseMove(NULL, DC->cursorx, DC->cursory); return qtrue; } // mouse hit if (key == A_MOUSE1 || key == A_MOUSE2) { if (item->window.flags & WINDOW_LB_LEFTARROW) { scrollPtr->startPos--; if (scrollPtr->startPos < 0) { scrollPtr->startPos = 0; } } else if (item->window.flags & WINDOW_LB_RIGHTARROW) { // one down scrollPtr->startPos++; if (scrollPtr->startPos > max) { scrollPtr->startPos = max; } } else if (item->window.flags & WINDOW_LB_PGUP) { // page up scrollPtr->startPos -= viewmax; if (scrollPtr->startPos < 0) { scrollPtr->startPos = 0; } } else if (item->window.flags & WINDOW_LB_PGDN) { // page down scrollPtr->startPos += viewmax; if (scrollPtr->startPos > max) { scrollPtr->startPos = max; } } else if (item->window.flags & WINDOW_LB_THUMB) { // Display_SetCaptureItem(item); } return qtrue; } if ( key == A_HOME || key == A_KP_7) { // home scrollPtr->startPos = 0; return qtrue; } if ( key == A_END || key == A_KP_1) { // end scrollPtr->startPos = max; return qtrue; } if (key == A_PAGE_UP || key == A_KP_9 ) { scrollPtr->startPos -= viewmax; if (scrollPtr->startPos < 0) { scrollPtr->startPos = 0; } return qtrue; } if ( key == A_PAGE_DOWN || key == A_KP_3 ) { scrollPtr->startPos += viewmax; if (scrollPtr->startPos > max) { scrollPtr->startPos = max; } return qtrue; } } return qfalse; } /* ================= Item_ListBox_MaxScroll ================= */ int Item_ListBox_MaxScroll(itemDef_t *item) { listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData; int count = DC->feederCount(item->special); int max; if (item->window.flags & WINDOW_HORIZONTAL) { max = count - (item->window.rect.w / listPtr->elementWidth) + 1; } else { max = count - (item->window.rect.h / listPtr->elementHeight) + 1; } if (max < 0) { return 0; } return max; } /* ================= Item_ListBox_ThumbPosition ================= */ int Item_ListBox_ThumbPosition(itemDef_t *item) { float max, pos, size; listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData; max = Item_ListBox_MaxScroll(item); if (item->window.flags & WINDOW_HORIZONTAL) { size = item->window.rect.w - (SCROLLBAR_SIZE * 2) - 2; if (max > 0) { pos = (size-SCROLLBAR_SIZE) / (float) max; } else { pos = 0; } pos *= listPtr->startPos; return item->window.rect.x + 1 + SCROLLBAR_SIZE + pos; } else { size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2; if (max > 0) { pos = (size-SCROLLBAR_SIZE) / (float) max; } else { pos = 0; } pos *= listPtr->startPos; return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos; } } /* ================= Item_ListBox_OverLB ================= */ int Item_ListBox_OverLB(itemDef_t *item, float x, float y) { rectDef_t r; int thumbstart; if (item->window.flags & WINDOW_HORIZONTAL) { // check if on left arrow r.x = item->window.rect.x; r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE; r.h = r.w = SCROLLBAR_SIZE; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_LEFTARROW; } // check if on right arrow r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_RIGHTARROW; } // check if on thumb thumbstart = Item_ListBox_ThumbPosition(item); r.x = thumbstart; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_THUMB; } r.x = item->window.rect.x + SCROLLBAR_SIZE; r.w = thumbstart - r.x; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_PGUP; } r.x = thumbstart + SCROLLBAR_SIZE; r.w = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_PGDN; } } else { r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE; r.y = item->window.rect.y; r.h = r.w = SCROLLBAR_SIZE; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_LEFTARROW; } r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_RIGHTARROW; } thumbstart = Item_ListBox_ThumbPosition(item); r.y = thumbstart; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_THUMB; } r.y = item->window.rect.y + SCROLLBAR_SIZE; r.h = thumbstart - r.y; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_PGUP; } r.y = thumbstart + SCROLLBAR_SIZE; r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_PGDN; } } return 0; } /* ================= Item_ListBox_MouseEnter ================= */ void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y) { rectDef_t r; listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData; item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN); item->window.flags |= Item_ListBox_OverLB(item, x, y); if (item->window.flags & WINDOW_HORIZONTAL) { if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) { // check for selection hit as we have exausted buttons and thumb if (listPtr->elementStyle == LISTBOX_IMAGE) { r.x = item->window.rect.x; r.y = item->window.rect.y; r.h = item->window.rect.h - SCROLLBAR_SIZE; r.w = item->window.rect.w - listPtr->drawPadding; if (Rect_ContainsPoint(&r, x, y)) { listPtr->cursorPos = (int)((x - r.x) / listPtr->elementWidth) + listPtr->startPos; if (listPtr->cursorPos > listPtr->endPos) { listPtr->cursorPos = listPtr->endPos; } } } else { // text hit.. } } } else if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) { r.x = item->window.rect.x; r.y = item->window.rect.y; r.w = item->window.rect.w - SCROLLBAR_SIZE; r.h = item->window.rect.h - listPtr->drawPadding; if (Rect_ContainsPoint(&r, x, y)) { listPtr->cursorPos = (int)((y - 2 - r.y) / listPtr->elementHeight) + listPtr->startPos; if (listPtr->cursorPos > listPtr->endPos) { listPtr->cursorPos = listPtr->endPos; } } } } /* ================= Item_MouseEnter ================= */ void Item_MouseEnter(itemDef_t *item, float x, float y) { rectDef_t r; //JLFMOUSE if (item) { r = item->textRect; // r.y -= r.h; // NOt sure why this is here, but I commented it out. // in the text rect? // items can be enabled and disabled if (item->disabled) { return; } // items can be enabled and disabled based on cvars if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) { return; } if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) { return; } //JLFMOUSE if (Rect_ContainsPoint(&r, x, y)) { if (!(item->window.flags & WINDOW_MOUSEOVERTEXT)) { Item_RunScript(item, item->mouseEnterText); item->window.flags |= WINDOW_MOUSEOVERTEXT; } if (!(item->window.flags & WINDOW_MOUSEOVER)) { Item_RunScript(item, item->mouseEnter); item->window.flags |= WINDOW_MOUSEOVER; } } else { // not in the text rect if (item->window.flags & WINDOW_MOUSEOVERTEXT) { // if we were Item_RunScript(item, item->mouseExitText); item->window.flags &= ~WINDOW_MOUSEOVERTEXT; } if (!(item->window.flags & WINDOW_MOUSEOVER)) { Item_RunScript(item, item->mouseEnter); item->window.flags |= WINDOW_MOUSEOVER; } if (item->type == ITEM_TYPE_LISTBOX) { Item_ListBox_MouseEnter(item, x, y); } else if ( item->type == ITEM_TYPE_TEXTSCROLL ) { Item_TextScroll_MouseEnter ( item, x, y ); } } } } /* ================= Item_SetFocus ================= */ // will optionaly set focus to this item qboolean Item_SetFocus(itemDef_t *item, float x, float y) { int i; itemDef_t *oldFocus; sfxHandle_t *sfx = &DC->Assets.itemFocusSound; qboolean playSound = qfalse; // sanity check, non-null, not a decoration and does not already have the focus if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS || !(item->window.flags & WINDOW_VISIBLE) || (item->window.flags & WINDOW_INACTIVE)) { return qfalse; } menuDef_t *parent = (menuDef_t*)item->parent; // items can be enabled and disabled if (item->disabled) { return qfalse; } // items can be enabled and disabled based on cvars if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) { return qfalse; } if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) { return qfalse; } oldFocus = Menu_ClearFocus((menuDef_t *) item->parent); if (item->type == ITEM_TYPE_TEXT) { rectDef_t r; r = item->textRect; //r.y -= r.h; //JLFMOUSE if (Rect_ContainsPoint(&r, x, y)) { item->window.flags |= WINDOW_HASFOCUS; if (item->focusSound) { sfx = &item->focusSound; } playSound = qtrue; } else { if (oldFocus) { oldFocus->window.flags |= WINDOW_HASFOCUS; if (oldFocus->onFocus) { Item_RunScript(oldFocus, oldFocus->onFocus); } } } } else { item->window.flags |= WINDOW_HASFOCUS; if (item->onFocus) { Item_RunScript(item, item->onFocus); } if (item->focusSound) { sfx = &item->focusSound; } playSound = qtrue; } if (playSound && sfx) { DC->startLocalSound( *sfx, CHAN_LOCAL_SOUND ); } for (i = 0; i < parent->itemCount; i++) { if (parent->items[i] == item) { parent->cursorItem = i; break; } } return qtrue; } /* ================= IsVisible ================= */ qboolean IsVisible(int flags) { return (qboolean)((flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT)) != 0); } /* ================= Item_MouseLeave ================= */ void Item_MouseLeave(itemDef_t *item) { if (item) { if (item->window.flags & WINDOW_MOUSEOVERTEXT) { Item_RunScript(item, item->mouseExitText); item->window.flags &= ~WINDOW_MOUSEOVERTEXT; } Item_RunScript(item, item->mouseExit); item->window.flags &= ~(WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW); } } /* ================= Item_SetMouseOver ================= */ void Item_SetMouseOver(itemDef_t *item, qboolean focus) { if (item) { if (focus) { item->window.flags |= WINDOW_MOUSEOVER; } else { item->window.flags &= ~WINDOW_MOUSEOVER; } } } /* ================= Menu_HandleMouseMove ================= */ void Menu_HandleMouseMove(menuDef_t *menu, float x, float y) { int i, pass; qboolean focusSet = qfalse; itemDef_t *overItem; if (menu == NULL) { return; } if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) { return; } if (itemCapture) { //Item_MouseMove(itemCapture, x, y); return; } if (g_waitingForKey || g_editingField) { return; } // FIXME: this is the whole issue of focus vs. mouse over.. // need a better overall solution as i don't like going through everything twice for (pass = 0; pass < 2; pass++) { for (i = 0; i < menu->itemCount; i++) { // turn off focus each item // menu->items[i].window.flags &= ~WINDOW_HASFOCUS; if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) { continue; } if (menu->items[i]->window.flags & WINDOW_INACTIVE) { continue; } if (menu->items[i]->disabled) { continue; } // items can be enabled and disabled based on cvars if (menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE)) { continue; } if (menu->items[i]->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_SHOW)) { continue; } if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) { if (pass == 1) { overItem = menu->items[i]; if (overItem->type == ITEM_TYPE_TEXT && overItem->text) { if (!Rect_ContainsPoint(&overItem->window.rect, x, y)) { continue; } } // if we are over an item if (IsVisible(overItem->window.flags)) { // different one Item_MouseEnter(overItem, x, y); // Item_SetMouseOver(overItem, qtrue); // if item is not a decoration see if it can take focus if (!focusSet) { focusSet = Item_SetFocus(overItem, x, y); } } } } else if (menu->items[i]->window.flags & WINDOW_MOUSEOVER) { Item_MouseLeave(menu->items[i]); Item_SetMouseOver(menu->items[i], qfalse); } } } } /* ================= Display_MouseMove ================= */ qboolean Display_MouseMove(void *p, int x, int y) { int i; menuDef_t *menu = (menuDef_t *) p; if (menu == NULL) { menu = Menu_GetFocused(); if (menu) { if (menu->window.flags & WINDOW_POPUP) { Menu_HandleMouseMove(menu, x, y); return qtrue; } } for (i = 0; i < menuCount; i++) { Menu_HandleMouseMove(&Menus[i], x, y); } } else { menu->window.rect.x += x; menu->window.rect.y += y; Menu_UpdatePosition(menu); } return qtrue; } /* ================= Menus_AnyFullScreenVisible ================= */ qboolean Menus_AnyFullScreenVisible(void) { int i; for (i = 0; i < menuCount; i++) { if (Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen) { return qtrue; } } return qfalse; } /* ================= Controls_SetConfig ================= */ void Controls_SetConfig( void ) { size_t i; // iterate each command, get its numeric binding for ( i=0; isetBinding( g_bindKeys[i][0], g_bindCommands[i] ); if ( g_bindKeys[i][1] != -1 ) DC->setBinding( g_bindKeys[i][1], g_bindCommands[i] ); } } } void Controls_SetDefaults( void ) { size_t i; for ( i=0; iparent; for (i=0;iitemCount;++i) { if (menu->items[i] == item) { continue; } menu->items[i]->window.flags &= ~WINDOW_INACTIVE; } } /* ================= Item_Bind_HandleKey ================= */ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) { int id; int i; menuDef_t *menu; if (key == A_MOUSE1 && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey) { if (down) { g_waitingForKey = qtrue; g_bindItem = item; // Set all others in the menu to grey menu = (menuDef_t *) item->parent; for (i=0;iitemCount;++i) { if (menu->items[i] == item) { continue; } menu->items[i]->window.flags |= WINDOW_INACTIVE; } } return qtrue; } else if (key == A_ENTER && !g_waitingForKey) { if (down) { g_waitingForKey = qtrue; g_bindItem = item; // Set all others in the menu to grey menu = (menuDef_t *) item->parent; for (i=0;iitemCount;++i) { if (menu->items[i] == item) { continue; } menu->items[i]->window.flags |= WINDOW_INACTIVE; } } return qtrue; } else { if (!g_waitingForKey || g_bindItem == NULL) { return qfalse; } if (key & K_CHAR_FLAG) { return qtrue; } switch (key) { case A_ESCAPE: g_waitingForKey = qfalse; Item_Bind_Ungrey(item); return qtrue; case A_BACKSPACE: id = BindingIDFromName(item->cvar); if ( id != -1 ) { if ( g_bindKeys[id][0] != -1 ) DC->setBinding( g_bindKeys[id][0], "" ); if ( g_bindKeys[id][1] != -1 ) DC->setBinding( g_bindKeys[id][1], "" ); g_bindKeys[id][0] = -1; g_bindKeys[id][1] = -1; } Controls_SetConfig(); g_waitingForKey = qfalse; g_bindItem = NULL; Item_Bind_Ungrey(item); return qtrue; break; case '`': return qtrue; } } // Is the same key being bound to something else? if ( key != -1 ) { size_t b; for ( b=0; bcvar ); if ( id != -1 ) { if ( key == -1 ) { if ( g_bindKeys[id][0] != -1 ) { DC->setBinding( g_bindKeys[id][0], "" ); g_bindKeys[id][0] = -1; } if ( g_bindKeys[id][1] != -1 ) { DC->setBinding( g_bindKeys[id][1], "" ); g_bindKeys[id][1] = -1; } } else if ( g_bindKeys[id][0] == -1 ) g_bindKeys[id][0] = key; else if ( g_bindKeys[id][0] != key && g_bindKeys[id][1] == -1 ) g_bindKeys[id][1] = key; else { DC->setBinding( g_bindKeys[id][0], "" ); DC->setBinding( g_bindKeys[id][1], "" ); g_bindKeys[id][0] = key; g_bindKeys[id][1] = -1; } } Controls_SetConfig(); g_waitingForKey = qfalse; Item_Bind_Ungrey(item); return qtrue; } /* ================= Menu_SetNextCursorItem ================= */ itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu) { qboolean wrapped = qfalse; int oldCursor = menu->cursorItem; if (menu->cursorItem == -1) { menu->cursorItem = 0; wrapped = qtrue; } while (menu->cursorItem < menu->itemCount) { menu->cursorItem++; if (menu->cursorItem >= menu->itemCount && !wrapped) { wrapped = qtrue; menu->cursorItem = 0; } if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) { Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1); return menu->items[menu->cursorItem]; } } menu->cursorItem = oldCursor; return NULL; } /* ================= Menu_SetPrevCursorItem ================= */ itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu) { qboolean wrapped = qfalse; int oldCursor = menu->cursorItem; if (menu->cursorItem < 0) { menu->cursorItem = menu->itemCount-1; wrapped = qtrue; } while (menu->cursorItem > -1) { menu->cursorItem--; if (menu->cursorItem < 0 ) { if (wrapped) { break; } wrapped = qtrue; menu->cursorItem = menu->itemCount -1; } if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) { Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1); return menu->items[menu->cursorItem]; } } menu->cursorItem = oldCursor; return NULL; } /* ================= Item_TextField_HandleKey ================= */ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) { char buff[1024]; int len; itemDef_t *newItem = NULL; editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData; if (item->cvar) { memset(buff, 0, sizeof(buff)); DC->getCVarString(item->cvar, buff, sizeof(buff)); len = strlen(buff); if (editPtr->maxChars && len > editPtr->maxChars) { len = editPtr->maxChars; } if ( key & K_CHAR_FLAG ) { key &= ~K_CHAR_FLAG; if (key == 'h' - 'a' + 1 ) { // ctrl-h is backspace if ( item->cursorPos > 0 ) { memmove( &buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos); item->cursorPos--; if (item->cursorPos < editPtr->paintOffset) { editPtr->paintOffset--; } } DC->setCVar(item->cvar, buff); return qtrue; } // // ignore any non printable chars // if ( key < 32 || !item->cvar) { return qtrue; } if (item->type == ITEM_TYPE_NUMERICFIELD) { if (key < '0' || key > '9') { return qfalse; } } if (!DC->getOverstrikeMode()) { if (( len == MAX_EDITFIELD - 1 ) || (editPtr->maxChars && len >= editPtr->maxChars)) { return qtrue; } memmove( &buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos ); } else { if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars) { return qtrue; } } buff[item->cursorPos] = key; DC->setCVar(item->cvar, buff); if (item->cursorPos < len + 1) { item->cursorPos++; if (editPtr->maxPaintChars && item->cursorPos > editPtr->maxPaintChars) { editPtr->paintOffset++; } } } else { if ( key == A_DELETE || key == A_KP_PERIOD ) { if ( item->cursorPos < len ) { memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos); DC->setCVar(item->cvar, buff); } return qtrue; } if ( key == A_CURSOR_RIGHT || key == A_KP_6 ) { if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) { item->cursorPos++; editPtr->paintOffset++; return qtrue; } if (item->cursorPos < len) { item->cursorPos++; } return qtrue; } if ( key == A_CURSOR_LEFT|| key == A_KP_4 ) { if ( item->cursorPos > 0 ) { item->cursorPos--; } if (item->cursorPos < editPtr->paintOffset) { editPtr->paintOffset--; } return qtrue; } if ( key == A_HOME || key == A_KP_7) { item->cursorPos = 0; editPtr->paintOffset = 0; return qtrue; } if ( key == A_END || key == A_KP_1) { item->cursorPos = len; if(item->cursorPos > editPtr->maxPaintChars) { editPtr->paintOffset = len - editPtr->maxPaintChars; } return qtrue; } if ( key == A_INSERT || key == A_KP_0 ) { DC->setOverstrikeMode((qboolean)(!DC->getOverstrikeMode())); return qtrue; } } if (key == A_TAB || key == A_CURSOR_DOWN || key == A_KP_2) { newItem = Menu_SetNextCursorItem((menuDef_t *) item->parent); if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) { g_editItem = newItem; } } if (key == A_CURSOR_UP || key == A_KP_8) { newItem = Menu_SetPrevCursorItem((menuDef_t *) item->parent); if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) { g_editItem = newItem; } } if ( key == A_ENTER || key == A_KP_ENTER || key == A_ESCAPE) { return qfalse; } return qtrue; } return qfalse; } static void Scroll_TextScroll_AutoFunc (void *p) { scrollInfo_t *si = (scrollInfo_t*)p; if (DC->realTime > si->nextScrollTime) { // need to scroll which is done by simulating a click to the item // this is done a bit sideways as the autoscroll "knows" that the item is a listbox // so it calls it directly Item_TextScroll_HandleKey(si->item, si->scrollKey, qtrue, qfalse); si->nextScrollTime = DC->realTime + si->adjustValue; } if (DC->realTime > si->nextAdjustTime) { si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST; if (si->adjustValue > SCROLL_TIME_FLOOR) { si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET; } } } static void Scroll_TextScroll_ThumbFunc(void *p) { scrollInfo_t *si = (scrollInfo_t*)p; rectDef_t r; int pos; int max; textScrollDef_t *scrollPtr = (textScrollDef_t*)si->item->typeData; if (DC->cursory != si->yStart) { r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1; r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1; r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2; r.w = SCROLLBAR_SIZE; max = Item_TextScroll_MaxScroll(si->item); // pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE); if (pos < 0) { pos = 0; } else if (pos > max) { pos = max; } scrollPtr->startPos = pos; si->yStart = DC->cursory; } if (DC->realTime > si->nextScrollTime) { // need to scroll which is done by simulating a click to the item // this is done a bit sideways as the autoscroll "knows" that the item is a listbox // so it calls it directly Item_TextScroll_HandleKey(si->item, si->scrollKey, qtrue, qfalse); si->nextScrollTime = DC->realTime + si->adjustValue; } if (DC->realTime > si->nextAdjustTime) { si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST; if (si->adjustValue > SCROLL_TIME_FLOOR) { si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET; } } } /* ================= Menu_OverActiveItem ================= */ static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y) { if (menu && menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)) { if (Rect_ContainsPoint(&menu->window.rect, x, y)) { int i; for (i = 0; i < menu->itemCount; i++) { // turn off focus each item // menu->items[i].window.flags &= ~WINDOW_HASFOCUS; if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) { continue; } if (menu->items[i]->window.flags & WINDOW_DECORATION) { continue; } if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) { itemDef_t *overItem = menu->items[i]; if (overItem->type == ITEM_TYPE_TEXT && overItem->text) { if (Rect_ContainsPoint(&overItem->window.rect, x, y)) { return qtrue; } else { continue; } } else { return qtrue; } } } } } return qfalse; } /* ================= Display_VisibleMenuCount ================= */ int Display_VisibleMenuCount(void) { int i, count; count = 0; for (i = 0; i < menuCount; i++) { if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE)) { count++; } } return count; } /* ================= Window_CloseCinematic ================= */ static void Window_CloseCinematic(windowDef_t *window) { if (window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0) { DC->stopCinematic(window->cinematic); window->cinematic = -1; } } /* ================= Menu_CloseCinematics ================= */ static void Menu_CloseCinematics(menuDef_t *menu) { if (menu) { int i; Window_CloseCinematic(&menu->window); for (i = 0; i < menu->itemCount; i++) { Window_CloseCinematic(&menu->items[i]->window); if (menu->items[i]->type == ITEM_TYPE_OWNERDRAW) { DC->stopCinematic(0-menu->items[i]->window.ownerDraw); } } } } /* ================= Display_CloseCinematics ================= */ static void Display_CloseCinematics() { int i; for (i = 0; i < menuCount; i++) { Menu_CloseCinematics(&Menus[i]); } } /* ================= Menus_HandleOOBClick ================= */ void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down) { if (menu) { int i; // basically the behaviour we are looking for is if there are windows in the stack.. see if // the cursor is within any of them.. if not close them otherwise activate them and pass the // key on.. force a mouse move to activate focus and script stuff if (down && menu->window.flags & WINDOW_OOB_CLICK) { Menu_RunCloseScript(menu); menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE); } for (i = 0; i < menuCount; i++) { if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory)) { Menu_RunCloseScript(menu); menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE); // Menus_Activate(&Menus[i]); Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory); Menu_HandleKey(&Menus[i], key, down); } } if (Display_VisibleMenuCount() == 0) { if (DC->Pause) { DC->Pause(qfalse); } } Display_CloseCinematics(); } } /* ================= Item_StopCapture ================= */ void Item_StopCapture(itemDef_t *item) { } /* ================= Item_ListBox_HandleKey ================= */ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force) { listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData; int count = DC->feederCount(item->special); int max, viewmax; if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) { max = Item_ListBox_MaxScroll(item); if (item->window.flags & WINDOW_HORIZONTAL) { viewmax = (item->window.rect.w / listPtr->elementWidth); if ( key == A_CURSOR_LEFT || key == A_KP_4 ) { if (!listPtr->notselectable) { listPtr->cursorPos--; if (listPtr->cursorPos < 0) { listPtr->cursorPos = 0; } if (listPtr->cursorPos < listPtr->startPos) { listPtr->startPos = listPtr->cursorPos; } if (listPtr->cursorPos >= listPtr->startPos + viewmax) { listPtr->startPos = listPtr->cursorPos - viewmax + 1; } item->cursorPos = listPtr->cursorPos; DC->feederSelection(item->special, item->cursorPos, item); } else { listPtr->startPos--; if (listPtr->startPos < 0) { listPtr->startPos = 0; } } return qtrue; } if ( key == A_CURSOR_RIGHT || key == A_KP_6 ) { if (!listPtr->notselectable) { listPtr->cursorPos++; if (listPtr->cursorPos < listPtr->startPos) { listPtr->startPos = listPtr->cursorPos; } if (listPtr->cursorPos >= count) { listPtr->cursorPos = count-1; } if (listPtr->cursorPos >= listPtr->startPos + viewmax) { listPtr->startPos = listPtr->cursorPos - viewmax + 1; } item->cursorPos = listPtr->cursorPos; DC->feederSelection(item->special, item->cursorPos, item); } else { listPtr->startPos++; if (listPtr->startPos >= count) { listPtr->startPos = count-1; } } return qtrue; } } else { viewmax = (item->window.rect.h / listPtr->elementHeight); if ( key == A_CURSOR_UP || key == A_KP_8 ) { if (!listPtr->notselectable) { listPtr->cursorPos--; if (listPtr->cursorPos < 0) { listPtr->cursorPos = 0; } if (listPtr->cursorPos < listPtr->startPos) { listPtr->startPos = listPtr->cursorPos; } if (listPtr->cursorPos >= listPtr->startPos + viewmax) { listPtr->startPos = listPtr->cursorPos - viewmax + 1; } item->cursorPos = listPtr->cursorPos; DC->feederSelection(item->special, item->cursorPos, item); } else { listPtr->startPos--; if (listPtr->startPos < 0) { listPtr->startPos = 0; } } return qtrue; } if ( key == A_CURSOR_DOWN || key == A_KP_2 ) { if (!listPtr->notselectable) { listPtr->cursorPos++; if (listPtr->cursorPos < listPtr->startPos) { listPtr->startPos = listPtr->cursorPos; } if (listPtr->cursorPos >= count) { listPtr->cursorPos = count-1; } if (listPtr->cursorPos >= listPtr->startPos + viewmax) { listPtr->startPos = listPtr->cursorPos - viewmax + 1; } item->cursorPos = listPtr->cursorPos; DC->feederSelection(item->special, item->cursorPos, item); } else { listPtr->startPos++; if (listPtr->startPos > max) { listPtr->startPos = max; } } return qtrue; } //Raz: Added if ( key == A_MWHEELUP ) { listPtr->startPos -= ((int)item->special == FEEDER_Q3HEADS) ? viewmax : 1; if (listPtr->startPos < 0) { listPtr->startPos = 0; Display_MouseMove(NULL, DC->cursorx, DC->cursory); return qfalse; } Display_MouseMove(NULL, DC->cursorx, DC->cursory); return qtrue; } if ( key == A_MWHEELDOWN ) { listPtr->startPos += ((int)item->special == FEEDER_Q3HEADS) ? viewmax : 1; if (listPtr->startPos > max) { listPtr->startPos = max; Display_MouseMove(NULL, DC->cursorx, DC->cursory); return qfalse; } Display_MouseMove(NULL, DC->cursorx, DC->cursory); return qtrue; } } // mouse hit if (key == A_MOUSE1 || key == A_MOUSE2) { if (item->window.flags & WINDOW_LB_LEFTARROW) { listPtr->startPos--; if (listPtr->startPos < 0) { listPtr->startPos = 0; } } else if (item->window.flags & WINDOW_LB_RIGHTARROW) { // one down listPtr->startPos++; if (listPtr->startPos > max) { listPtr->startPos = max; } } else if (item->window.flags & WINDOW_LB_PGUP) { // page up listPtr->startPos -= viewmax; if (listPtr->startPos < 0) { listPtr->startPos = 0; } } else if (item->window.flags & WINDOW_LB_PGDN) { // page down listPtr->startPos += viewmax; if (listPtr->startPos > max) { listPtr->startPos = max; } } else if (item->window.flags & WINDOW_LB_THUMB) { // Display_SetCaptureItem(item); } else { // select an item if (DC->realTime < lastListBoxClickTime && listPtr->doubleClick) { Item_RunScript(item, listPtr->doubleClick); } lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY; item->cursorPos = listPtr->cursorPos; DC->feederSelection(item->special, item->cursorPos, item); } return qtrue; } if ( key == A_HOME || key == A_KP_7) { // home listPtr->startPos = 0; return qtrue; } if ( key == A_END || key == A_KP_1) { // end listPtr->startPos = max; return qtrue; } if (key == A_PAGE_UP || key == A_KP_9 ) { // page up if (!listPtr->notselectable) { listPtr->cursorPos -= viewmax; if (listPtr->cursorPos < 0) { listPtr->cursorPos = 0; } if (listPtr->cursorPos < listPtr->startPos) { listPtr->startPos = listPtr->cursorPos; } if (listPtr->cursorPos >= listPtr->startPos + viewmax) { listPtr->startPos = listPtr->cursorPos - viewmax + 1; } item->cursorPos = listPtr->cursorPos; DC->feederSelection(item->special, item->cursorPos, item); } else { listPtr->startPos -= viewmax; if (listPtr->startPos < 0) { listPtr->startPos = 0; } } return qtrue; } if ( key == A_PAGE_DOWN || key == A_KP_3 ) { // page down if (!listPtr->notselectable) { listPtr->cursorPos += viewmax; if (listPtr->cursorPos < listPtr->startPos) { listPtr->startPos = listPtr->cursorPos; } if (listPtr->cursorPos >= count) { listPtr->cursorPos = count-1; } if (listPtr->cursorPos >= listPtr->startPos + viewmax) { listPtr->startPos = listPtr->cursorPos - viewmax + 1; } item->cursorPos = listPtr->cursorPos; DC->feederSelection(item->special, item->cursorPos, item); } else { listPtr->startPos += viewmax; if (listPtr->startPos > max) { listPtr->startPos = max; } } return qtrue; } } return qfalse; } /* ================= Scroll_ListBox_AutoFunc ================= */ static void Scroll_ListBox_AutoFunc(void *p) { scrollInfo_t *si = (scrollInfo_t*)p; if (DC->realTime > si->nextScrollTime) { // need to scroll which is done by simulating a click to the item // this is done a bit sideways as the autoscroll "knows" that the item is a listbox // so it calls it directly Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse); si->nextScrollTime = DC->realTime + si->adjustValue; } if (DC->realTime > si->nextAdjustTime) { si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST; if (si->adjustValue > SCROLL_TIME_FLOOR) { si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET; } } } /* ================= Scroll_ListBox_ThumbFunc ================= */ static void Scroll_ListBox_ThumbFunc(void *p) { scrollInfo_t *si = (scrollInfo_t*)p; rectDef_t r; int pos, max; listBoxDef_t *listPtr = (listBoxDef_t*)si->item->typeData; if (si->item->window.flags & WINDOW_HORIZONTAL) { if (DC->cursorx == si->xStart) { return; } r.x = si->item->window.rect.x + SCROLLBAR_SIZE + 1; r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_SIZE - 1; r.h = SCROLLBAR_SIZE; r.w = si->item->window.rect.w - (SCROLLBAR_SIZE*2) - 2; max = Item_ListBox_MaxScroll(si->item); // pos = (DC->cursorx - r.x - SCROLLBAR_SIZE/2) * max / (r.w - SCROLLBAR_SIZE); if (pos < 0) { pos = 0; } else if (pos > max) { pos = max; } listPtr->startPos = pos; si->xStart = DC->cursorx; } else if (DC->cursory != si->yStart) { r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1; r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1; r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2; r.w = SCROLLBAR_SIZE; max = Item_ListBox_MaxScroll(si->item); // pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE); if (pos < 0) { pos = 0; } else if (pos > max) { pos = max; } listPtr->startPos = pos; si->yStart = DC->cursory; } if (DC->realTime > si->nextScrollTime) { // need to scroll which is done by simulating a click to the item // this is done a bit sideways as the autoscroll "knows" that the item is a listbox // so it calls it directly Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse); si->nextScrollTime = DC->realTime + si->adjustValue; } if (DC->realTime > si->nextAdjustTime) { si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST; if (si->adjustValue > SCROLL_TIME_FLOOR) { si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET; } } } /* ================= Item_Slider_OverSlider ================= */ int Item_Slider_OverSlider(itemDef_t *item, float x, float y) { rectDef_t r; r.x = Item_Slider_ThumbPosition(item) - (SLIDER_THUMB_WIDTH / 2); r.y = item->window.rect.y - 2; r.w = SLIDER_THUMB_WIDTH; r.h = SLIDER_THUMB_HEIGHT; if (Rect_ContainsPoint(&r, x, y)) { return WINDOW_LB_THUMB; } return 0; } /* ================= Scroll_Slider_ThumbFunc ================= */ static void Scroll_Slider_ThumbFunc(void *p) { float x, value, cursorx; scrollInfo_t *si = (scrollInfo_t*)p; editFieldDef_t *editDef = (struct editFieldDef_s *) si->item->typeData; if (si->item->text) { x = si->item->textRect.x + si->item->textRect.w + 8; } else { x = si->item->window.rect.x; } cursorx = DC->cursorx; if (cursorx < x) { cursorx = x; } else if (cursorx > x + SLIDER_WIDTH) { cursorx = x + SLIDER_WIDTH; } value = cursorx - x; value /= SLIDER_WIDTH; value *= (editDef->maxVal - editDef->minVal); value += editDef->minVal; DC->setCVar(si->item->cvar, va("%f", value)); } /* ================= Item_StartCapture ================= */ void Item_StartCapture(itemDef_t *item, int key) { int flags; switch (item->type) { case ITEM_TYPE_EDITFIELD: case ITEM_TYPE_NUMERICFIELD: case ITEM_TYPE_LISTBOX: { flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory); if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) { scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START; scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST; scrollInfo.adjustValue = SCROLL_TIME_START; scrollInfo.scrollKey = key; scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse; scrollInfo.item = item; captureData = &scrollInfo; captureFunc = &Scroll_ListBox_AutoFunc; itemCapture = item; } else if (flags & WINDOW_LB_THUMB) { scrollInfo.scrollKey = key; scrollInfo.item = item; scrollInfo.xStart = DC->cursorx; scrollInfo.yStart = DC->cursory; captureData = &scrollInfo; captureFunc = &Scroll_ListBox_ThumbFunc; itemCapture = item; } break; } case ITEM_TYPE_TEXTSCROLL: flags = Item_TextScroll_OverLB (item, DC->cursorx, DC->cursory); if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) { scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START; scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST; scrollInfo.adjustValue = SCROLL_TIME_START; scrollInfo.scrollKey = key; scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse; scrollInfo.item = item; captureData = &scrollInfo; captureFunc = &Scroll_TextScroll_AutoFunc; itemCapture = item; } else if (flags & WINDOW_LB_THUMB) { scrollInfo.scrollKey = key; scrollInfo.item = item; scrollInfo.xStart = DC->cursorx; scrollInfo.yStart = DC->cursory; captureData = &scrollInfo; captureFunc = &Scroll_TextScroll_ThumbFunc; itemCapture = item; } break; case ITEM_TYPE_SLIDER: { flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory); if (flags & WINDOW_LB_THUMB) { scrollInfo.scrollKey = key; scrollInfo.item = item; scrollInfo.xStart = DC->cursorx; scrollInfo.yStart = DC->cursory; captureData = &scrollInfo; captureFunc = &Scroll_Slider_ThumbFunc; itemCapture = item; } break; } } } /* ================= Item_YesNo_HandleKey ================= */ qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) { if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) { if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3) { DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar))); return qtrue; } } return qfalse; } /* ================= Item_Multi_FindCvarByValue ================= */ int Item_Multi_FindCvarByValue(itemDef_t *item) { char buff[1024]; float value = 0; int i; multiDef_t *multiPtr = (multiDef_t*)item->typeData; if (multiPtr) { if (multiPtr->strDef) { DC->getCVarString(item->cvar, buff, sizeof(buff)); } else { value = DC->getCVarValue(item->cvar); } for (i = 0; i < multiPtr->count; i++) { if (multiPtr->strDef) { if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) { return i; } } else { if (multiPtr->cvarValue[i] == value) { return i; } } } } return 0; } /* ================= Item_Multi_CountSettings ================= */ int Item_Multi_CountSettings(itemDef_t *item) { multiDef_t *multiPtr = (multiDef_t*)item->typeData; if (multiPtr == NULL) { return 0; } return multiPtr->count; } /* ================= Item_OwnerDraw_HandleKey ================= */ qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) { if (item && DC->ownerDrawHandleKey) { return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key); } return qfalse; } /* ================= Item_Text_HandleKey ================= */ qboolean Item_Text_HandleKey(itemDef_t *item, int key) { if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_AUTOWRAPPED) { if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3) { if (key == A_MOUSE2) { item->cursorPos--; if ( item->cursorPos < 0 ) { item->cursorPos = 0; } } else if (item->special) { item->cursorPos++; if ( item->cursorPos >= item->value ) { item->cursorPos = 0; } } return qtrue; } } return qfalse; } /* ================= Item_Multi_HandleKey ================= */ qboolean Item_Multi_HandleKey(itemDef_t *item, int key) { multiDef_t *multiPtr = (multiDef_t*)item->typeData; if (multiPtr) { if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS) { //Raz: Scroll on multi buttons! if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3 || key == A_MWHEELDOWN || key == A_MWHEELUP) //if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3) { if (item->cvar) { int current = Item_Multi_FindCvarByValue(item); int max = Item_Multi_CountSettings(item); if (key == A_MOUSE2 || key == A_MWHEELDOWN) { current--; if ( current < 0 ) { current = max-1; } } else { current++; if ( current >= max ) { current = 0; } } if (multiPtr->strDef) { DC->setCVar(item->cvar, multiPtr->cvarStr[current]); } else { float value = multiPtr->cvarValue[current]; if (((float)((int) value)) == value) { DC->setCVar(item->cvar, va("%i", (int) value )); } else { DC->setCVar(item->cvar, va("%f", value )); } } if (item->special) {//its a feeder? DC->feederSelection(item->special, current, item); } } else { int max = Item_Multi_CountSettings(item); if (key == A_MOUSE2 || key == A_MWHEELDOWN) { item->value--; if ( item->value < 0 ) { item->value = max; } } else { item->value++; if ( item->value >= max ) { item->value = 0; } } if (item->special) {//its a feeder? DC->feederSelection(item->special, item->value, item); } } return qtrue; } } } return qfalse; } /* ================= Item_Slider_HandleKey ================= */ qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) { //DC->Print("slider handle key\n"); //JLF MPMOVED float x, value, width, work; if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) { if (key == A_MOUSE1 || key == A_ENTER || key == A_MOUSE2 || key == A_MOUSE3) { editFieldDef_t *editDef = (editFieldDef_s *) item->typeData; if (editDef) { rectDef_t testRect; width = SLIDER_WIDTH; if (item->text) { x = item->textRect.x + item->textRect.w + 8; } else { x = item->window.rect.x; } testRect = item->window.rect; testRect.x = x; value = (float)SLIDER_THUMB_WIDTH / 2; testRect.x -= value; //DC->Print("slider x: %f\n", testRect.x); testRect.w = (SLIDER_WIDTH + (float)SLIDER_THUMB_WIDTH / 2); //DC->Print("slider w: %f\n", testRect.w); if (Rect_ContainsPoint(&testRect, DC->cursorx, DC->cursory)) { work = DC->cursorx - x; value = work / width; value *= (editDef->maxVal - editDef->minVal); // vm fuckage // value = (((float)(DC->cursorx - x)/ SLIDER_WIDTH) * (editDef->maxVal - editDef->minVal)); value += editDef->minVal; DC->setCVar(item->cvar, va("%f", value)); return qtrue; } } } } //DC->Print("slider handle key exit\n"); return qfalse; } /* ================= Item_HandleKey ================= */ qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) { if (itemCapture) { Item_StopCapture(itemCapture); itemCapture = NULL; captureFunc = NULL; captureData = NULL; } else { if (down && (key == A_MOUSE1 || key == A_MOUSE2 || key == A_MOUSE3)) { Item_StartCapture(item, key); } } if (!down) { return qfalse; } switch (item->type) { case ITEM_TYPE_BUTTON: return qfalse; break; case ITEM_TYPE_RADIOBUTTON: return qfalse; break; case ITEM_TYPE_CHECKBOX: return qfalse; break; case ITEM_TYPE_EDITFIELD: case ITEM_TYPE_NUMERICFIELD: //return Item_TextField_HandleKey(item, key); return qfalse; break; case ITEM_TYPE_COMBO: return qfalse; break; case ITEM_TYPE_LISTBOX: return Item_ListBox_HandleKey(item, key, down, qfalse); break; case ITEM_TYPE_TEXTSCROLL: return Item_TextScroll_HandleKey(item, key, down, qfalse); break; case ITEM_TYPE_YESNO: return Item_YesNo_HandleKey(item, key); break; case ITEM_TYPE_MULTI: return Item_Multi_HandleKey(item, key); break; case ITEM_TYPE_OWNERDRAW: return Item_OwnerDraw_HandleKey(item, key); break; case ITEM_TYPE_BIND: return Item_Bind_HandleKey(item, key, down); break; case ITEM_TYPE_SLIDER: return Item_Slider_HandleKey(item, key, down); break; //JLF MPMOVED case ITEM_TYPE_TEXT: return Item_Text_HandleKey(item, key); break; default: return qfalse; break; } //return qfalse; } //JLFACCEPT MPMOVED /* ----------------------------------------- Item_HandleAccept If Item has an accept script, run it. ------------------------------------------- */ qboolean Item_HandleAccept(itemDef_t * item) { if (item->accept) { Item_RunScript(item, item->accept); return qtrue; } return qfalse; } //JLFDPADSCRIPT MPMOVED /* ----------------------------------------- Item_HandleSelectionNext If Item has an selectionNext script, run it. ------------------------------------------- */ qboolean Item_HandleSelectionNext(itemDef_t * item) { if (item->selectionNext) { Item_RunScript(item, item->selectionNext); return qtrue; } return qfalse; } //JLFDPADSCRIPT MPMOVED /* ----------------------------------------- Item_HandleSelectionPrev If Item has an selectionPrev script, run it. ------------------------------------------- */ qboolean Item_HandleSelectionPrev(itemDef_t * item) { if (item->selectionPrev) { Item_RunScript(item, item->selectionPrev); return qtrue; } return qfalse; } /* ================= Item_Action ================= */ void Item_Action(itemDef_t *item) { if (item) { Item_RunScript(item, item->action); } } /* ================= Menu_HandleKey ================= */ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) { int i; itemDef_t *item = NULL; qboolean inHandler = qfalse; if (inHandler) { return; } inHandler = qtrue; if (g_waitingForKey && down) { Item_Bind_HandleKey(g_bindItem, key, down); inHandler = qfalse; return; } if (g_editingField && down) { if (!Item_TextField_HandleKey(g_editItem, key)) { g_editingField = qfalse; g_editItem = NULL; inHandler = qfalse; return; } else if (key == A_MOUSE1 || key == A_MOUSE2 || key == A_MOUSE3) { g_editingField = qfalse; g_editItem = NULL; Display_MouseMove(NULL, DC->cursorx, DC->cursory); } else if (key == A_TAB || key == A_CURSOR_UP || key == A_CURSOR_DOWN) { return; } } if (menu == NULL) { inHandler = qfalse; return; } //JLFMOUSE MPMOVED // see if the mouse is within the window bounds and if so is this a mouse click if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) { static qboolean inHandleKey = qfalse; if (!inHandleKey && (key == A_MOUSE1 || key == A_MOUSE2 || key == A_MOUSE3)) { inHandleKey = qtrue; Menus_HandleOOBClick(menu, key, down); inHandleKey = qfalse; inHandler = qfalse; return; } } // get the item with focus for (i = 0; i < menu->itemCount; i++) { if (menu->items[i]->window.flags & WINDOW_HASFOCUS) { item = menu->items[i]; break; } } // Ignore if disabled if (item && item->disabled) { return; } if (item != NULL) { if (Item_HandleKey(item, key, down)) //JLFLISTBOX { // It is possible for an item to be disable after Item_HandleKey is run (like in Voice Chat) if (!item->disabled) { Item_Action(item); } inHandler = qfalse; return; } } if (!down) { inHandler = qfalse; return; } // Special Data Pad key handling (gotta love the datapad) if (!(key & K_CHAR_FLAG) ) { //only check keys not chars char b[256]; DC->getBindingBuf( key, b, 256 ); if (Q_stricmp(b,"datapad") == 0) // They hit the datapad key again. { if (( Q_stricmp(menu->window.name,"datapadMissionMenu") == 0) || (Q_stricmp(menu->window.name,"datapadWeaponsMenu") == 0) || (Q_stricmp(menu->window.name,"datapadForcePowersMenu") == 0) || (Q_stricmp(menu->window.name,"datapadInventoryMenu") == 0)) { key = A_ESCAPE; //pop on outta here } } } // default handling switch ( key ) { case A_F11: if (DC->getCVarValue("developer")) { uis.debugMode = (qboolean)!uis.debugMode; } break; case A_F12: if (DC->getCVarValue("developer")) { switch ( DC->screenshotFormat ) { case SSF_JPEG: DC->executeText(EXEC_APPEND, "screenshot\n"); break; case SSF_TGA: DC->executeText(EXEC_APPEND, "screenshot_tga\n"); break; case SSF_PNG: DC->executeText(EXEC_APPEND, "screenshot_png\n"); break; default: if (DC->Print) { DC->Print(S_COLOR_YELLOW "Menu_HandleKey[F12]: Unknown screenshot format assigned! This should not happen.\n"); } break; } } break; case A_KP_8: case A_CURSOR_UP: Menu_SetPrevCursorItem(menu); break; case A_ESCAPE: if (!g_waitingForKey && menu->onESC) { itemDef_t it; it.parent = menu; Item_RunScript(&it, menu->onESC); } break; case A_TAB: case A_KP_2: case A_CURSOR_DOWN: Menu_SetNextCursorItem(menu); break; case A_MOUSE1: case A_MOUSE2: if (item) { if (item->type == ITEM_TYPE_TEXT) { if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) { if ( item->action ) Item_Action(item); else { if (menu->onAccept) { itemDef_t it; it.parent = menu; Item_RunScript(&it, menu->onAccept); } } } } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) { if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) { item->cursorPos = 0; g_editingField = qtrue; g_editItem = item; //DC->setOverstrikeMode(qtrue); } } //JLFACCEPT // add new types here as needed /* Notes: Most controls will use the dpad to move through the selection possibilies. Buttons are the only exception. Buttons will be assumed to all be on one menu together. If the start or A button is pressed on a control focus, that means that the menu is accepted and move onto the next menu. If the start or A button is pressed on a button focus it should just process the action and not support the accept functionality. */ //JLFACCEPT else if ( item->type == ITEM_TYPE_MULTI || item->type == ITEM_TYPE_YESNO || item->type == ITEM_TYPE_SLIDER) { if (Item_HandleAccept(item)) { //Item processed it overriding the menu processing return; } else if (menu->onAccept) { itemDef_t it; it.parent = menu; Item_RunScript(&it, menu->onAccept); } } //END JLFACCEPT else { if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) { Item_Action(item); } } } else if (menu->onAccept) { itemDef_t it; it.parent = menu; Item_RunScript(&it, menu->onAccept); } break; case A_JOY0: case A_JOY1: case A_JOY2: case A_JOY3: case A_JOY4: case A_AUX0: case A_AUX1: case A_AUX2: case A_AUX3: case A_AUX4: case A_AUX5: case A_AUX6: case A_AUX7: case A_AUX8: case A_AUX9: case A_AUX10: case A_AUX11: case A_AUX12: case A_AUX13: case A_AUX14: case A_AUX15: case A_AUX16: break; case A_KP_ENTER: case A_ENTER: if (item) { if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) { item->cursorPos = 0; g_editingField = qtrue; g_editItem = item; //DC->setOverstrikeMode(qtrue); } else { Item_Action(item); } } break; } inHandler = qfalse; } /* ================= ParseRect ================= */ qboolean ParseRect(const char **p, rectDef_t *r) { if (!COM_ParseFloat(p, &r->x)) { if (!COM_ParseFloat(p, &r->y)) { if (!COM_ParseFloat(p, &r->w)) { if (!COM_ParseFloat(p, &r->h)) { return qtrue; } } } } return qfalse; } /* ================= Menus_HideItems ================= */ void Menus_HideItems(const char *menuName) { menuDef_t *menu; int i; menu =Menus_FindByName(menuName); // Get menu if (!menu) { Com_Printf(S_COLOR_YELLOW"WARNING: No menu was found. Could not hide items.\n"); return; } menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE); for (i = 0; i < menu->itemCount; i++) { menu->items[i]->cvarFlags = CVAR_HIDE; } } /* ================= Menus_ShowItems ================= */ void Menus_ShowItems(const char *menuName) { menuDef_t *menu; int i; menu =Menus_FindByName(menuName); // Get menu if (!menu) { Com_Printf(S_COLOR_YELLOW"WARNING: No menu was found. Could not show items.\n"); return; } menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE); for (i = 0; i < menu->itemCount; i++) { menu->items[i]->cvarFlags = CVAR_SHOW; } } /* ================= UI_Cursor_Show ================= */ void UI_Cursor_Show(qboolean flag) { DC->cursorShow = flag; if ((DC->cursorShow != qtrue) && (DC->cursorShow != qfalse)) { DC->cursorShow = qtrue; } }