/* =========================================================================== Return to Castle Wolfenstein multiplayer GPL Source Code Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”). RTCW MP Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. RTCW MP Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RTCW MP Source Code. If not, see . In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ // // string allocation/managment #include "ui_shared.h" #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 void ( *captureFunc )( void *p ) = NULL; static void *captureData = NULL; static itemDef_t *itemCapture = NULL; // item that has the mouse captured ( if any ) displayContextDef_t *DC = NULL; qboolean g_waitingForKey = qfalse; qboolean g_editingField = qfalse; static itemDef_t *g_bindItem = NULL; itemDef_t *g_editItem = NULL; menuDef_t Menus[MAX_MENUS]; // defined menus int menuCount = 0; // how many // TTimo // a stack for modal menus only, stores the menus to come back to // (an item can be NULL, goes back to main menu / no action required) menuDef_t *modalMenuStack[MAX_MODAL_MENUS]; int modalMenuCount = 0; static qboolean debugMode = qfalse; #define DOUBLE_CLICK_DELAY 300 static int lastListBoxClickTime = 0; void Item_RunScript( itemDef_t *item, const char *s ); void Item_SetupKeywordHash( void ); void Menu_SetupKeywordHash( void ); int BindingIDFromName( const char *name ); qboolean Item_Bind_HandleKey( itemDef_t *item, int key, qboolean down ); itemDef_t *Menu_SetPrevCursorItem( menuDef_t *menu ); itemDef_t *Menu_SetNextCursorItem( menuDef_t *menu ); static qboolean Menu_OverActiveItem( menuDef_t *menu, float x, float y ); #ifdef CGAME #define MEM_POOL_SIZE 128 * 1024 #else #define MEM_POOL_SIZE 1024 * 1024 #endif static char memoryPool[MEM_POOL_SIZE]; static int allocPoint, outOfMemory; /* =============== 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" ); } //DC->trap_Print(S_COLOR_YELLOW"WARNING: UI 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; } qboolean UI_OutOfMemory() { return outOfMemory; } #define HASH_TABLE_SIZE 2048 /* ================ return a hash value for the string ================ */ static long hashForString( const char *str ) { int i; long hash; char letter; hash = 0; i = 0; while ( str[i] != '\0' ) { letter = tolower( str[i] ); hash += (long)( letter ) * ( i + 119 ); i++; } hash &= ( HASH_TABLE_SIZE - 1 ); return hash; } typedef struct stringDef_s { struct stringDef_s *next; const char *str; } stringDef_t; static int strPoolIndex = 0; static char strPool[STRING_POOL_SIZE]; static int strHandleCount = 0; static stringDef_t *strHandle[HASH_TABLE_SIZE]; const char *String_Alloc( const char *p ) { int len; long 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 ( str && str->next ) { last = str; str = str->next; } str = UI_Alloc( sizeof( stringDef_t ) ); str->next = NULL; str->str = &strPool[ph]; if ( last ) { last->next = str; } else { strHandle[hash] = str; } return &strPool[ph]; } return NULL; } void String_Report() { 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() { int i; for ( i = 0; i < HASH_TABLE_SIZE; i++ ) { strHandle[i] = 0; } strHandleCount = 0; strPoolIndex = 0; menuCount = 0; modalMenuCount = 0; UI_InitMemory(); Item_SetupKeywordHash(); Menu_SetupKeywordHash(); if ( DC && DC->getBindingBuf ) { Controls_GetConfig(); } } /* ================= PC_SourceWarning ================= */ void PC_SourceWarning( int handle, char *format, ... ) { int line; char filename[128]; va_list argptr; static char string[4096]; va_start( argptr, format ); vsprintf( string, format, argptr ); va_end( argptr ); filename[0] = '\0'; line = 0; trap_PC_SourceFileAndLine( handle, filename, &line ); Com_Printf( S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string ); } /* ================= 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 ); vsprintf( string, format, argptr ); va_end( argptr ); filename[0] = '\0'; line = 0; trap_PC_SourceFileAndLine( handle, filename, &line ); Com_Printf( S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string ); } /* ================= LerpColor lerp and clamp each component of and into by the fraction ================= */ void LerpColor( vec4_t a, vec4_t b, vec4_t c, float t ) { int i; 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; } } } /* ================= Float_Parse ================= */ qboolean Float_Parse( char **p, float *f ) { char *token; token = COM_ParseExt( p, qfalse ); if ( token && token[0] != 0 ) { *f = atof( token ); return qtrue; } else { return qfalse; } } /* ================= PC_Float_Parse ================= */ qboolean PC_Float_Parse( int handle, float *f ) { pc_token_t token; int negative = qfalse; if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } if ( token.string[0] == '-' ) { if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } negative = qtrue; } if ( token.type != TT_NUMBER ) { PC_SourceError( handle, "expected float but found %s\n", token.string ); return qfalse; } if ( negative ) { *f = -token.floatvalue; } else { *f = token.floatvalue; } return qtrue; } /* ================= Color_Parse ================= */ qboolean Color_Parse( char **p, vec4_t *c ) { int i; float f; for ( i = 0; i < 4; i++ ) { if ( !Float_Parse( p, &f ) ) { return qfalse; } ( *c )[i] = f; } return qtrue; } /* ================= PC_Color_Parse ================= */ qboolean PC_Color_Parse( int handle, vec4_t *c ) { int i; float f; for ( i = 0; i < 4; i++ ) { if ( !PC_Float_Parse( handle, &f ) ) { return qfalse; } ( *c )[i] = f; } return qtrue; } /* ================= Int_Parse ================= */ qboolean Int_Parse( char **p, int *i ) { char *token; token = COM_ParseExt( p, qfalse ); if ( token && token[0] != 0 ) { *i = atoi( token ); return qtrue; } else { return qfalse; } } /* ================= PC_Int_Parse ================= */ qboolean PC_Int_Parse( int handle, int *i ) { pc_token_t token; int negative = qfalse; if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } if ( token.string[0] == '-' ) { if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } negative = qtrue; } if ( token.type != TT_NUMBER ) { PC_SourceError( handle, "expected integer but found %s\n", token.string ); return qfalse; } *i = token.intvalue; if ( negative ) { *i = -*i; } return qtrue; } /* ================= Rect_Parse ================= */ qboolean Rect_Parse( char **p, rectDef_t *r ) { if ( Float_Parse( p, &r->x ) ) { if ( Float_Parse( p, &r->y ) ) { if ( Float_Parse( p, &r->w ) ) { if ( Float_Parse( p, &r->h ) ) { return qtrue; } } } } return qfalse; } /* ================= PC_Rect_Parse ================= */ qboolean PC_Rect_Parse( int handle, rectDef_t *r ) { if ( PC_Float_Parse( handle, &r->x ) ) { if ( PC_Float_Parse( handle, &r->y ) ) { if ( PC_Float_Parse( handle, &r->w ) ) { if ( PC_Float_Parse( handle, &r->h ) ) { return qtrue; } } } } return qfalse; } /* ================= String_Parse ================= */ qboolean String_Parse( char **p, const char **out ) { char *token; token = COM_ParseExt( p, qfalse ); if ( token && token[0] != 0 ) { *( out ) = String_Alloc( token ); return qtrue; } return qfalse; } /* ================= PC_String_Parse ================= */ qboolean PC_String_Parse( int handle, const char **out ) { pc_token_t token; if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } *( out ) = String_Alloc( token.string ); return qtrue; } /* ================= PC_String_Parse_Trans NERVE - SMF - translates string ================= */ qboolean PC_String_Parse_Trans( int handle, const char **out ) { pc_token_t token; if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } *( out ) = String_Alloc( DC->translateString( token.string ) ); return qtrue; } // NERVE - SMF /* ================= PC_Char_Parse ================= */ qboolean PC_Char_Parse( int handle, char *out ) { pc_token_t token; if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } *( out ) = token.string[0]; return qtrue; } // -NERVE - SMF /* ================= PC_Script_Parse ================= */ qboolean PC_Script_Parse( int handle, const char **out ) { char script[1024]; pc_token_t token; memset( script, 0, sizeof( script ) ); // 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 if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } if ( Q_stricmp( token.string, "{" ) != 0 ) { return qfalse; } while ( 1 ) { if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } if ( Q_stricmp( token.string, "}" ) == 0 ) { *out = String_Alloc( script ); return qtrue; } if ( token.string[1] != '\0' ) { Q_strcat( script, 1024, va( "\"%s\"", token.string ) ); } else { Q_strcat( script, 1024, token.string ); } Q_strcat( script, 1024, " " ); } return qfalse; // bk001105 - LCC missing return value } // display, window, menu, item code // /* ================== Init_Display Initializes the display with a structure to all the drawing routines ================== */ void Init_Display( displayContextDef_t *dc ) { DC = dc; } // type and style painting 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_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; } 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; } } } } } } void Window_Paint( Window *w, float fadeAmount, float fadeClamp, float fadeCycle ) { //float bordersize = 0; vec4_t color; rectDef_t fillRect = w->rect; if ( 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_FORECOLORSET ) { DC->setColor( w->foreColor ); } DC->drawHandlePic( fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background ); DC->setColor( NULL ); } else if ( w->style == WINDOW_STYLE_TEAMCOLOR ) { if ( DC->getTeamColor ) { DC->getTeamColor( &color ); DC->fillRect( fillRect.x, fillRect.y, fillRect.w, fillRect.h, color ); } } else if ( w->style == WINDOW_STYLE_CINEMATIC ) { if ( w->cinematic == -1 ) { w->cinematic = DC->playCinematic( w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h ); if ( w->cinematic == -1 ) { w->cinematic = -2; } } if ( w->cinematic >= 0 ) { DC->runCinematicFrame( w->cinematic ); DC->drawCinematic( w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h ); } } 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 ); } } 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; } // 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 = 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 ); } // menus 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 ); } } 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 ); } 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; } qboolean IsVisible( int flags ) { return ( flags & WINDOW_VISIBLE && !( flags & WINDOW_FADINGOUT ) ); } qboolean Rect_ContainsPoint( rectDef_t *rect, float x, float y ) { if ( rect ) { if ( x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h ) { return qtrue; } } return qfalse; } int Menu_ItemsMatchingGroup( menuDef_t *menu, const char *name ) { int i; int count = 0; char *pdest; int wildcard = -1; // if wildcard is set, it's value is the number of characters to compare pdest = strstr( name, "*" ); // allow wildcard strings (ex. "hide nb_*" would translate to "hide nb_pg1; hide nb_extra" etc) if ( pdest ) { wildcard = pdest - name; } for ( i = 0; i < menu->itemCount; i++ ) { if ( wildcard != -1 ) { if ( Q_strncmp( menu->items[i]->window.name, name, wildcard ) == 0 || ( menu->items[i]->window.group && Q_strncmp( menu->items[i]->window.group, name, wildcard ) == 0 ) ) { count++; } } else { 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; } itemDef_t *Menu_GetMatchingItemByNumber( menuDef_t *menu, int index, const char *name ) { int i; int count = 0; char *pdest; int wildcard = -1; // if wildcard is set, it's value is the number of characters to compare pdest = strstr( name, "*" ); // allow wildcard strings (ex. "hide nb_*" would translate to "hide nb_pg1; hide nb_extra" etc) if ( pdest ) { wildcard = pdest - name; } for ( i = 0; i < menu->itemCount; i++ ) { if ( wildcard != -1 ) { if ( Q_strncmp( menu->items[i]->window.name, name, wildcard ) == 0 || ( menu->items[i]->window.group && Q_strncmp( menu->items[i]->window.group, name, wildcard ) == 0 ) ) { if ( count == index ) { return menu->items[i]; } count++; } } else { 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; } void Script_SetColor( itemDef_t *item, 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 ) ) { return; } ( *out )[i] = f; } } } } void Script_SetAsset( itemDef_t *item, 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 ) { } } } void Script_SetBackground( itemDef_t *item, char **args ) { const char *name; // expecting name to set asset to if ( String_Parse( args, &name ) ) { item->window.background = DC->registerShaderNoMip( name ); } } 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; } void Script_SetTeamColor( itemDef_t *item, char **args ) { if ( DC->getTeamColor ) { int i; vec4_t color; DC->getTeamColor( &color ); for ( i = 0; i < 4; i++ ) { item->window.backColor[i] = color[i]; } } } void Script_SetItemColor( itemDef_t *item, char **args ) { const char *itemname; const char *name; vec4_t color; int i; vec4_t *out; // expecting type of color to set and 4 args for the color if ( String_Parse( args, &itemname ) && String_Parse( args, &name ) ) { itemDef_t *item2; int j; int count = Menu_ItemsMatchingGroup( item->parent, itemname ); if ( !Color_Parse( args, &color ) ) { return; } for ( j = 0; j < count; j++ ) { item2 = Menu_GetMatchingItemByNumber( 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]; } } } } } } void Menu_ShowItemByName( menuDef_t *menu, const char *p, qboolean bShow ) { 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 ( bShow ) { item->window.flags |= WINDOW_VISIBLE; } else { item->window.flags &= ~WINDOW_VISIBLE; // stop cinematics playing in the window if ( item->window.cinematic >= 0 ) { DC->stopCinematic( item->window.cinematic ); item->window.cinematic = -1; } } } } } 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; } } } } 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; } void Menus_ShowByName( const char *p ) { menuDef_t *menu = Menus_FindByName( p ); if ( menu ) { Menus_Activate( menu ); } } void Menus_OpenByName( const char *p ) { Menus_ActivateByName( p, qtrue ); } 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 ); } } void Menus_CloseByName( const char *p ) { menuDef_t *menu = Menus_FindByName( p ); if ( menu != NULL ) { Menu_RunCloseScript( menu ); menu->window.flags &= ~( WINDOW_VISIBLE | WINDOW_HASFOCUS ); if ( menu->window.flags & WINDOW_MODAL ) { if ( modalMenuCount <= 0 ) { Com_Printf( S_COLOR_YELLOW "WARNING: tried closing a modal window with an empty modal stack!\n" ); } else { modalMenuCount--; // if modal doesn't have a parent, the stack item may be NULL .. just go back to the main menu then if ( modalMenuStack[modalMenuCount] ) { Menus_ActivateByName( modalMenuStack[modalMenuCount]->window.name, qfalse ); // don't try to push the one we are opening to the stack } } } } } void Menus_CloseAll() { int i; for ( i = 0; i < menuCount; i++ ) { Menu_RunCloseScript( &Menus[i] ); Menus[i].window.flags &= ~( WINDOW_HASFOCUS | WINDOW_VISIBLE ); } } void Script_Show( itemDef_t *item, char **args ) { const char *name; if ( String_Parse( args, &name ) ) { Menu_ShowItemByName( item->parent, name, qtrue ); } } void Script_Hide( itemDef_t *item, char **args ) { const char *name; if ( String_Parse( args, &name ) ) { Menu_ShowItemByName( item->parent, name, qfalse ); } } void Script_FadeIn( itemDef_t *item, char **args ) { const char *name; if ( String_Parse( args, &name ) ) { Menu_FadeItemByName( item->parent, name, qfalse ); } } void Script_FadeOut( itemDef_t *item, char **args ) { const char *name; if ( String_Parse( args, &name ) ) { Menu_FadeItemByName( item->parent, name, qtrue ); } } void Script_Open( itemDef_t *item, char **args ) { const char *name; if ( String_Parse( args, &name ) ) { Menus_OpenByName( name ); } } // DHM - Nerve void Script_ConditionalOpen( itemDef_t *item, char **args ) { const char *cvar; const char *name1; const char *name2; float val; if ( String_Parse( args, &cvar ) && String_Parse( args, &name1 ) && String_Parse( args, &name2 ) ) { val = DC->getCVarValue( cvar ); if ( val == 0.f ) { Menus_OpenByName( name2 ); } else { Menus_OpenByName( name1 ); } } } // DHM - Nerve void Script_Close( itemDef_t *item, char **args ) { const char *name; if ( String_Parse( args, &name ) ) { Menus_CloseByName( name ); } } /* ============== Script_Clipboard ============== */ void Script_Clipboard( itemDef_t *item, char **args ) { char curscript[64]; DC->getCVarString( "cg_clipboardName", curscript, sizeof( curscript ) ); // grab the string the client set Menu_ShowItemByName( item->parent, curscript, qtrue ); } #define NOTEBOOK_MAX_PAGES 6 // this will not be a define /* ============== Script_NotebookShowpage hide all notebook pages and show just the active one inc == 0 - show current page inc == val - turn inc pages in the notebook (negative numbers are backwards) inc == 999 - key number. +999 is jump to last page, -999 is jump to cover page ============== */ void Script_NotebookShowpage( itemDef_t *item, char **args ) { int i, inc, curpage, newpage = 0, pages; pages = DC->getCVarValue( "cg_notebookpages" ); if ( Int_Parse( args, &inc ) ) { curpage = DC->getCVarValue( "ui_notebookCurrentPage" ); if ( inc == 0 ) { // opening if ( pages && !curpage ) { // only open to cover if no pages exist inc = 1; // otherwise, go to first available page } } if ( inc == 999 ) { // jump to end // newpage = NOTEBOOK_MAX_PAGES; // = lastpage; curpage = 0; inc = -1; } else if ( inc == -999 ) { // jump to start curpage = 0; inc = 0; } else if ( inc > 500 ) { // curpage = DEBRIEFING_BASE + (inc - 500); curpage = inc; inc = 0; } if ( inc ) { int dec = 0; if ( inc > 0 ) { for ( i = 1; i < NOTEBOOK_MAX_PAGES; i++ ) { newpage = curpage + i; if ( newpage > NOTEBOOK_MAX_PAGES ) { newpage = newpage % NOTEBOOK_MAX_PAGES; } if ( newpage == 0 ) { continue; } if ( pages & ( 1 << ( newpage - 1 ) ) ) { dec++; // if(dec == inc) // break; break; } } if ( i < NOTEBOOK_MAX_PAGES ) { // a valid page was found curpage = newpage; } } else { for ( i = 1; i < NOTEBOOK_MAX_PAGES; i++ ) { newpage = curpage - i; if ( newpage <= 0 ) { newpage = newpage + NOTEBOOK_MAX_PAGES; } if ( pages & ( 1 << ( newpage - 1 ) ) ) { break; } } if ( i < NOTEBOOK_MAX_PAGES ) { // a valid page was found curpage = newpage; } } } // hide all the pages // Menu_ShowItemByName(item->parent, "page_*", qfalse); Menu_ShowItemByName( item->parent, "cover", qfalse ); for ( i = 1; i <= NOTEBOOK_MAX_PAGES; i++ ) { Menu_ShowItemByName( item->parent, va( "page%d", i ), qfalse ); } // show the visible one if ( curpage ) { Menu_ShowItemByName( item->parent, va( "page%d", curpage ), qtrue ); } else { Menu_ShowItemByName( item->parent, "cover", qtrue ); } DC->setCVar( "ui_notebookCurrentPage", va( "%d", curpage ) ); // store new current page } } void Menu_TransitionItemByName( menuDef_t *menu, const char *p, rectDef_t rectFrom, 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 ) { 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 ); } } } void Script_Transition( itemDef_t *item, char **args ) { const char *name; rectDef_t rectFrom, rectTo; int time; float amt; if ( String_Parse( args, &name ) ) { if ( Rect_Parse( args, &rectFrom ) && Rect_Parse( args, &rectTo ) && Int_Parse( args, &time ) && Float_Parse( args, &amt ) ) { Menu_TransitionItemByName( item->parent, name, rectFrom, rectTo, time, amt ); } } } 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 Script_Orbit( itemDef_t *item, 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 ) ) { Menu_OrbitItemByName( item->parent, name, x, y, cx, cy, time ); } } } void Script_SetFocus( itemDef_t *item, char **args ) { const char *name; itemDef_t *focusItem; if ( String_Parse( args, &name ) ) { focusItem = Menu_FindItemByName( item->parent, name ); if ( focusItem && !( focusItem->window.flags & WINDOW_DECORATION ) && !( focusItem->window.flags & WINDOW_HASFOCUS ) ) { Menu_ClearFocus( item->parent ); focusItem->window.flags |= WINDOW_HASFOCUS; if ( focusItem->onFocus ) { Item_RunScript( focusItem, focusItem->onFocus ); } if ( DC->Assets.itemFocusSound ) { DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND ); } } } } void Script_SetPlayerModel( itemDef_t *item, char **args ) { const char *name; if ( String_Parse( args, &name ) ) { DC->setCVar( "team_model", name ); } } void Script_SetPlayerHead( itemDef_t *item, char **args ) { const char *name; if ( String_Parse( args, &name ) ) { DC->setCVar( "team_headmodel", name ); } } // ATVI Wolfenstein Misc #304 // the parser misreads setCvar "bleh" "" // you have to use clearCvar "bleh" void Script_ClearCvar( itemDef_t *item, char **args ) { const char *cvar; if ( String_Parse( args, &cvar ) ) { DC->setCVar( cvar, "" ); } } void Script_SetCvar( itemDef_t *item, char **args ) { const char *cvar, *val; if ( String_Parse( args, &cvar ) && String_Parse( args, &val ) ) { DC->setCVar( cvar, val ); } } void Script_Exec( itemDef_t *item, char **args ) { const char *val; if ( String_Parse( args, &val ) ) { DC->executeText( EXEC_APPEND, va( "%s ; ", val ) ); } } void Script_Play( itemDef_t *item, char **args ) { const char *val; if ( String_Parse( args, &val ) ) { DC->startLocalSound( DC->registerSound( val ), CHAN_LOCAL_SOUND ); // all sounds are not 3d } } void Script_playLooped( itemDef_t *item, char **args ) { const char *val; if ( String_Parse( args, &val ) ) { DC->stopBackgroundTrack(); DC->startBackgroundTrack( val, val ); } } // NERVE - SMF void Script_AddListItem( itemDef_t *item, char **args ) { const char *itemname, *val, *name; itemDef_t *t; if ( String_Parse( args, &itemname ) && String_Parse( args, &val ) && String_Parse( args, &name ) ) { t = Menu_FindItemByName( item->parent, itemname ); if ( t && t->special ) { DC->feederAddItem( t->special, name, atoi( val ) ); } } } // -NERVE - SMF // DHM - Nerve void Script_CheckAutoUpdate( itemDef_t *item, char **args ) { DC->checkAutoUpdate(); } void Script_GetAutoUpdate( itemDef_t *item, char **args ) { DC->getAutoUpdate(); } // DHM - Nerve commandDef_t commandList[] = { {"fadein", &Script_FadeIn}, // group/name {"fadeout", &Script_FadeOut}, // group/name {"show", &Script_Show}, // group/name {"hide", &Script_Hide}, // group/name {"setcolor", &Script_SetColor}, // works on this {"open", &Script_Open}, // menu {"conditionalopen", &Script_ConditionalOpen}, // DHM - Nerve:: cvar menu menu // opens first menu if cvar is true[non-zero], second if false {"close", &Script_Close}, // menu {"clipboard", &Script_Clipboard}, // show the current clipboard group by name {"showpage", &Script_NotebookShowpage}, // {"setasset", &Script_SetAsset}, // works on this {"setbackground", &Script_SetBackground}, // works on this {"setitemcolor", &Script_SetItemColor}, // group/name {"setteamcolor", &Script_SetTeamColor}, // sets this background color to team color {"setfocus", &Script_SetFocus}, // sets this background color to team color {"setplayermodel", &Script_SetPlayerModel}, // sets this background color to team color {"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color {"transition", &Script_Transition}, // group/name {"setcvar", &Script_SetCvar}, // group/name {"clearcvar", &Script_ClearCvar}, {"exec", &Script_Exec}, // group/name {"play", &Script_Play}, // group/name {"playlooped", &Script_playLooped}, // group/name {"orbit", &Script_Orbit}, // group/name {"addlistitem", &Script_AddListItem}, // NERVE - SMF - special command to add text items to list box {"checkautoupdate", &Script_CheckAutoUpdate}, // DHM - Nerve {"getautoupdate", &Script_GetAutoUpdate} // DHM - Nerve }; int scriptCommandCount = sizeof( commandList ) / sizeof( commandDef_t ); void Item_RunScript( itemDef_t *item, const char *s ) { char script[1024], *p; int i; qboolean bRan; memset( script, 0, sizeof( script ) ); if ( item && s && s[0] ) { Q_strcat( script, 1024, s ); p = script; while ( 1 ) { const char *command; // expect command then arguments, ; ends command, NULL ends script if ( !String_Parse( &p, &command ) ) { return; } if ( command[0] == ';' && command[1] == '\0' ) { continue; } bRan = qfalse; for ( i = 0; i < scriptCommandCount; i++ ) { if ( Q_stricmp( command, commandList[i].name ) == 0 ) { ( commandList[i].handler( item, &p ) ); bRan = qtrue; break; } } // not in our auto list, pass to handler if ( !bRan ) { DC->runScript( &p ); } } } } qboolean Item_EnableShowViaCvar( itemDef_t *item, int flag ) { char script[1024], *p; memset( script, 0, sizeof( script ) ); if ( item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest ) { char buff[1024]; DC->getCVarString( item->cvarTest, buff, sizeof( buff ) ); Q_strcat( script, 1024, item->enableCvar ); p = script; while ( 1 ) { const char *val; // expect value then ; or NULL, NULL ends list if ( !String_Parse( &p, &val ) ) { 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 ) { return qtrue; } } else { // disable it if any of the values are true if ( Q_stricmp( buff, val ) == 0 ) { return qfalse; } } } return ( item->cvarFlags & flag ) ? qfalse : qtrue; } return qtrue; } // 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; menuDef_t *parent; // bk001206: = (menuDef_t*)item->parent; // 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 ) ) { return qfalse; } // bk001206 - this can be NULL. parent = (menuDef_t*)item->parent; // 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( item->parent ); if ( item->type == ITEM_TYPE_TEXT ) { rectDef_t r; r = item->textRect; r.y -= r.h; 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; } 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; } 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; } } 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 ); } } float Item_Slider_ThumbPosition( itemDef_t *item ) { float value, range, x; editFieldDef_t *editDef = item->typeData; if ( item->text ) { x = item->textRect.x + item->textRect.w + 8; } else { x = item->window.rect.x; } if ( editDef == NULL && 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; } 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; } int Item_ListBox_OverLB( itemDef_t *item, float x, float y ) { rectDef_t r; listBoxDef_t *listPtr; int thumbstart; int count; count = DC->feederCount( item->special ); listPtr = (listBoxDef_t*)item->typeData; 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; } 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; } } } } void Item_MouseEnter( itemDef_t *item, float x, float y ) { rectDef_t r; if ( item ) { r = item->textRect; r.y -= r.h; // in the text rect? // 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; } 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 ); } } } } 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 ); } } itemDef_t *Menu_HitTest( menuDef_t *menu, float x, float y ) { int i; for ( i = 0; i < menu->itemCount; i++ ) { if ( Rect_ContainsPoint( &menu->items[i]->window.rect, x, y ) ) { return menu->items[i]; } } return NULL; } void Item_SetMouseOver( itemDef_t *item, qboolean focus ) { if ( item ) { if ( focus ) { item->window.flags |= WINDOW_MOUSEOVER; } else { item->window.flags &= ~WINDOW_MOUSEOVER; } } } 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; } 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 == K_LEFTARROW || key == K_KP_LEFTARROW ) { 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 ); } else { listPtr->startPos--; if ( listPtr->startPos < 0 ) { listPtr->startPos = 0; } } return qtrue; } if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) { 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 ); } else { listPtr->startPos++; if ( listPtr->startPos >= count ) { listPtr->startPos = count - 1; } } return qtrue; } } else { viewmax = ( item->window.rect.h / listPtr->elementHeight ); if ( key == K_UPARROW || key == K_KP_UPARROW ) { 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 ); } else { listPtr->startPos--; if ( listPtr->startPos < 0 ) { listPtr->startPos = 0; } } return qtrue; } if ( key == K_DOWNARROW || key == K_KP_DOWNARROW ) { 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 ); } else { listPtr->startPos++; if ( listPtr->startPos > max ) { listPtr->startPos = max; } } return qtrue; } } // mouse hit if ( key == K_MOUSE1 || key == K_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; if ( item->cursorPos != listPtr->cursorPos ) { item->cursorPos = listPtr->cursorPos; DC->feederSelection( item->special, item->cursorPos ); } } return qtrue; } if ( key == K_HOME || key == K_KP_HOME ) { // home listPtr->startPos = 0; return qtrue; } if ( key == K_END || key == K_KP_END ) { // end listPtr->startPos = max; return qtrue; } if ( key == K_PGUP || key == K_KP_PGUP ) { // 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 ); } else { listPtr->startPos -= viewmax; if ( listPtr->startPos < 0 ) { listPtr->startPos = 0; } } return qtrue; } if ( key == K_PGDN || key == K_KP_PGDN ) { // 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 ); } else { listPtr->startPos += viewmax; if ( listPtr->startPos > max ) { listPtr->startPos = max; } } return qtrue; } } return qfalse; } 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 == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3 ) { // ATVI Wolfenstein Misc #462 // added the flag to toggle via action script only if ( !( item->cvarFlags & CVAR_NOTOGGLE ) ) { DC->setCVar( item->cvar, va( "%i", !DC->getCVarValue( item->cvar ) ) ); } return qtrue; } } return qfalse; } int Item_Multi_CountSettings( itemDef_t *item ) { multiDef_t *multiPtr = (multiDef_t*)item->typeData; if ( multiPtr == NULL ) { return 0; } return multiPtr->count; } 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; } 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 ) { 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 multiPtr->cvarList[i]; } } else { if ( multiPtr->cvarValue[i] == value ) { return multiPtr->cvarList[i]; } } } } return ""; } 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 && item->cvar ) { if ( key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3 ) { int current = Item_Multi_FindCvarByValue( item ) + 1; int max = Item_Multi_CountSettings( item ); if ( current < 0 || 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 ) ); } } return qtrue; } } } return qfalse; } 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 == K_DEL || key == K_KP_DEL ) { if ( item->cursorPos < len ) { memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos ); DC->setCVar( item->cvar, buff ); } return qtrue; } if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) { if ( editPtr->maxPaintChars && item->cursorPos >= editPtr->paintOffset + editPtr->maxPaintChars && item->cursorPos < len ) { item->cursorPos++; editPtr->paintOffset++; return qtrue; } if ( item->cursorPos < len ) { item->cursorPos++; } return qtrue; } if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) { if ( item->cursorPos > 0 ) { item->cursorPos--; } if ( item->cursorPos < editPtr->paintOffset ) { editPtr->paintOffset--; } return qtrue; } if ( key == K_HOME || key == K_KP_HOME ) { // || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) { item->cursorPos = 0; editPtr->paintOffset = 0; return qtrue; } if ( key == K_END || key == K_KP_END ) { // ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) { item->cursorPos = len; if ( item->cursorPos > editPtr->maxPaintChars ) { editPtr->paintOffset = len - editPtr->maxPaintChars; } return qtrue; } if ( key == K_INS || key == K_KP_INS ) { DC->setOverstrikeMode( !DC->getOverstrikeMode() ); return qtrue; } } if ( key == K_TAB || key == K_DOWNARROW || key == K_KP_DOWNARROW ) { newItem = Menu_SetNextCursorItem( item->parent ); if ( newItem && ( newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD ) ) { g_editItem = newItem; } } if ( key == K_UPARROW || key == K_KP_UPARROW ) { newItem = Menu_SetPrevCursorItem( item->parent ); if ( newItem && ( newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD ) ) { g_editItem = newItem; } } // NERVE - SMF if ( key == K_ENTER || key == K_KP_ENTER ) { if ( item->onAccept ) { Item_RunScript( item, item->onAccept ); } } // -NERVE - SMF if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE ) { return qfalse; } return qtrue; } return qfalse; } 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; } } } 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; } } } static void Scroll_Slider_ThumbFunc( void *p ) { float x, value, cursorx; scrollInfo_t *si = (scrollInfo_t*)p; editFieldDef_t *editDef = 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 ) ); } 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_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; } } } void Item_StopCapture( itemDef_t *item ) { } qboolean Item_Slider_HandleKey( itemDef_t *item, int key, qboolean down ) { float x, value, width, work; //DC->Print("slider handle key\n"); if ( item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint( &item->window.rect, DC->cursorx, DC->cursory ) ) { if ( key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3 ) { editFieldDef_t *editDef = 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; } qboolean Item_HandleKey( itemDef_t *item, int key, qboolean down ) { if ( itemCapture ) { Item_StopCapture( itemCapture ); itemCapture = NULL; captureFunc = NULL; captureData = NULL; } else { // bk001206 - parentheses if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_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_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; //case ITEM_TYPE_IMAGE: // Item_Image_Paint(item); // break; default: return qfalse; break; } //return qfalse; } void Item_Action( itemDef_t *item ) { if ( item ) { Item_RunScript( item, item->action ); } } 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 && !wrapped ) { wrapped = qtrue; menu->cursorItem = menu->itemCount - 1; } // NERVE - SMF if ( menu->cursorItem < 0 ) { menu->cursorItem = oldCursor; return NULL; } // -NERVE - SMF 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; } 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 ) { // (SA) had a problem 'tabbing' in dialogs with only one possible button if ( !wrapped ) { wrapped = qtrue; menu->cursorItem = 0; } else { return menu->items[oldCursor]; } } 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; } static void Window_CloseCinematic( windowDef_t *window ) { if ( window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0 ) { DC->stopCinematic( window->cinematic ); window->cinematic = -1; } } 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 ); } } } } static void Display_CloseCinematics() { int i; for ( i = 0; i < menuCount; i++ ) { Menu_CloseCinematics( &Menus[i] ); } } void Menus_Activate( menuDef_t *menu ) { menu->window.flags |= ( WINDOW_HASFOCUS | WINDOW_VISIBLE ); if ( menu->onOpen ) { itemDef_t item; item.parent = menu; Item_RunScript( &item, menu->onOpen ); } if ( menu->soundName && *menu->soundName ) { // DC->stopBackgroundTrack(); // you don't want to do this since it will reset s_rawend DC->startBackgroundTrack( menu->soundName, menu->soundName ); } Display_CloseCinematics(); } int Display_VisibleMenuCount() { int i, count; count = 0; for ( i = 0; i < menuCount; i++ ) { if ( Menus[i].window.flags & ( WINDOW_FORCED | WINDOW_VISIBLE ) ) { count++; } } return count; } 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); // NERVE - SMF - why do we close the calling menu instead of just removing the focus? // menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE); menu->window.flags &= ~( WINDOW_HASFOCUS ); 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(); } } static rectDef_t *Item_CorrectedTextRect( itemDef_t *item ) { static rectDef_t rect; memset( &rect, 0, sizeof( rectDef_t ) ); if ( item ) { rect = item->textRect; if ( rect.w ) { rect.y -= rect.h; } } return ▭ } void Menu_HandleKey( menuDef_t *menu, int key, qboolean down ) { int i; itemDef_t *item = NULL; qboolean inHandler = qfalse; Menu_HandleMouseMove( menu, DC->cursorx, DC->cursory ); // NERVE - SMF - fix for focus not resetting on unhidden buttons 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 == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) { g_editingField = qfalse; g_editItem = NULL; Display_MouseMove( NULL, DC->cursorx, DC->cursory ); } else if ( key == K_TAB || key == K_UPARROW || key == K_DOWNARROW ) { return; } } if ( menu == NULL ) { inHandler = qfalse; return; } // 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; // bk001206 - parentheses if ( !inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_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]; } } if ( item != NULL ) { if ( Item_HandleKey( item, key, down ) ) { Item_Action( item ); inHandler = qfalse; return; } } if ( !down ) { inHandler = qfalse; return; } // NERVE - SMF if ( key > 0 && key <= 255 && menu->onKey[key] ) { itemDef_t it; it.parent = menu; Item_RunScript( &it, menu->onKey[key] ); return; } // - NERVE - SMF // default handling switch ( key ) { case K_F11: if ( DC->getCVarValue( "developer" ) ) { debugMode ^= 1; } break; case K_F12: if ( DC->getCVarValue( "developer" ) ) { DC->executeText( EXEC_APPEND, "screenshot\n" ); } break; case K_KP_UPARROW: case K_UPARROW: Menu_SetPrevCursorItem( menu ); break; case K_ESCAPE: if ( !g_waitingForKey && menu->onESC ) { itemDef_t it; it.parent = menu; Item_RunScript( &it, menu->onESC ); } break; case K_TAB: case K_KP_DOWNARROW: case K_DOWNARROW: Menu_SetNextCursorItem( menu ); break; case K_MOUSE1: case K_MOUSE2: if ( item ) { if ( item->type == ITEM_TYPE_TEXT ) { if ( Rect_ContainsPoint( Item_CorrectedTextRect( item ), DC->cursorx, DC->cursory ) ) { Item_Action( item ); } } else if ( item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD ) { if ( Rect_ContainsPoint( &item->window.rect, DC->cursorx, DC->cursory ) ) { editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData; // NERVE - SMF - reset scroll offset so we can see what we're editing if ( editPtr ) { editPtr->paintOffset = 0; } item->cursorPos = 0; g_editingField = qtrue; g_editItem = item; DC->setOverstrikeMode( qtrue ); } } else { if ( Rect_ContainsPoint( &item->window.rect, DC->cursorx, DC->cursory ) ) { Item_Action( item ); } } } break; case K_JOY1: case K_JOY2: case K_JOY3: case K_JOY4: case K_AUX1: case K_AUX2: case K_AUX3: case K_AUX4: case K_AUX5: case K_AUX6: case K_AUX7: case K_AUX8: case K_AUX9: case K_AUX10: case K_AUX11: case K_AUX12: case K_AUX13: case K_AUX14: case K_AUX15: case K_AUX16: break; case K_KP_ENTER: case K_ENTER: case K_MOUSE3: 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; } 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; } void Rect_ToWindowCoords( rectDef_t *rect, windowDef_t *window ) { ToWindowCoords( &rect->x, &rect->y, window ); } 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 ) || item->textalignment == ITEM_ALIGN_CENTER2 ) { int originalWidth = DC->textWidth( item->text, item->textscale, 0 ); 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, 0 ); } else if ( item->textalignment == ITEM_ALIGN_CENTER2 ) { // NERVE - SMF - default centering case originalWidth += DC->textWidth( text, item->textscale, 0 ); } *width = DC->textWidth( textPtr, item->textscale, 0 ); *height = DC->textHeight( textPtr, item->textscale, 0 ); 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->textalignment == ITEM_ALIGN_CENTER2 ) { // NERVE - SMF - default centering case item->textRect.x = item->textalignx - originalWidth / 2; } ToWindowCoords( &item->textRect.x, &item->textRect.y, &item->window ); } } void Item_TextColor( itemDef_t *item, vec4_t *newColor ) { vec4_t lowLight; 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->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( 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 ) ); // 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 ) ); } } } void Item_Text_AutoWrapped_Paint( itemDef_t *item ) { char text[1024]; const char *p, *textPtr, *newLinePtr; char buff[1024]; int width, 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 == '\0' ) { return; } Item_TextColor( item, &color ); Item_SetTextExtents( item, &width, &height, textPtr ); y = item->textaligny; len = 0; buff[0] = '\0'; newLine = 0; newLineWidth = 0; p = textPtr; while ( p ) { 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 ) || *p == '\n' || *p == '\0' ) { 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'; DC->drawText( item->textRect.x, item->textRect.y, item->textscale, color, buff, 0, 0, item->textStyle ); } if ( *p == '\0' ) { break; } // y += height + 5; p = newLinePtr; len = 0; newLine = 0; newLineWidth = 0; continue; } buff[len++] = *p++; if ( buff[len - 1] == 13 ) { buff[len - 1] = ' '; } buff[len] = '\0'; } } 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 == '\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, 0, item->textStyle ); y += height + 5; start += p - start + 1; p = strchr( p + 1, '\r' ); } DC->drawText( x, y, item->textscale, color, start, 0, 0, item->textStyle ); } 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 ) ); if ( item->window.flags & CG_SHOW_TEXTASINT ) { COM_StripExtension( text, text ); } textPtr = text; } } else { textPtr = item->text; } // 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 ); //FIXME: this is a fucking mess /* adjust = 0; if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) { adjust = 0.5; } if (item->textStyle == ITEM_TEXTSTYLE_SHADOWED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) { Fade(&item->window.flags, &DC->Assets.shadowColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse); DC->drawText(item->textRect.x + DC->Assets.shadowX, item->textRect.y + DC->Assets.shadowY, item->textscale, DC->Assets.shadowColor, textPtr, adjust); } */ // if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) { // Fade(&item->window.flags, &item->window.outlineColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse); // /* // Text_Paint(item->textRect.x-1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust); // Text_Paint(item->textRect.x, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust); // Text_Paint(item->textRect.x+1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust); // Text_Paint(item->textRect.x-1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust); // Text_Paint(item->textRect.x+1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust); // Text_Paint(item->textRect.x-1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust); // Text_Paint(item->textRect.x, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust); // Text_Paint(item->textRect.x+1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust); // */ // DC->drawText(item->textRect.x - 1, item->textRect.y + 1, item->textscale * 1.02, item->window.outlineColor, textPtr, adjust); // } DC->drawText( item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, 0, item->textStyle ); } void Item_TextField_Paint( itemDef_t *item ) { char buff[1024]; vec4_t newColor, lowLight; int offset; int text_len = 0; // screen length of the editfield text that will be printed int field_offset; // character offset in the editfield string int screen_offset; // offset on screen for precise placement 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 ) ); } 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( DC->realTime / PULSE_DIVISOR ) ); } else { memcpy( &newColor, &item->window.foreColor, sizeof( vec4_t ) ); } // NOTE: offset from the editfield prefix (like "Say: " in limbo menu) offset = ( item->text && *item->text ) ? 8 : 0; // TTimo // text length control // if the edit field goes beyond the available width, drop some characters at the beginning of the string and apply some offseting // FIXME: we could cache the text length and offseting, but given the low count of edit fields, I abstained for now // FIXME: this won't handle going back into the line of the editfield to the hidden area // start of text painting: item->textRect.x + item->textRect.w + offset // our window limit: item->window.rect.x + item->window.rect.w field_offset = -1; do { field_offset++; if ( buff + editPtr->paintOffset + field_offset == '\0' ) { break; // keep it safe } text_len = DC->textWidth( buff + editPtr->paintOffset + field_offset, item->textscale, 0 ); } while ( text_len + item->textRect.x + item->textRect.w + offset > item->window.rect.x + item->window.rect.w ); if ( field_offset ) { // we had to take out some chars to make it fit in, there is an additional screen offset to compute screen_offset = item->window.rect.x + item->window.rect.w - ( text_len + item->textRect.x + item->textRect.w + offset ); } else { screen_offset = 0; } if ( item->window.flags & WINDOW_HASFOCUS && g_editingField ) { char cursor = DC->getOverstrikeMode() ? '_' : '|'; DC->drawTextWithCursor( item->textRect.x + item->textRect.w + offset + screen_offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset + field_offset, item->cursorPos - editPtr->paintOffset - field_offset, cursor, editPtr->maxPaintChars, item->textStyle ); } else { DC->drawText( item->textRect.x + item->textRect.w + offset + screen_offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset + field_offset, 0, editPtr->maxPaintChars, item->textStyle ); } } void Item_YesNo_Paint( itemDef_t *item ) { vec4_t newColor, lowLight; float value; menuDef_t *parent = (menuDef_t*)item->parent; value = ( item->cvar ) ? DC->getCVarValue( item->cvar ) : 0; 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( DC->realTime / PULSE_DIVISOR ) ); } else { memcpy( &newColor, &item->window.foreColor, sizeof( vec4_t ) ); } if ( item->text ) { Item_Text_Paint( item ); DC->drawText( item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, ( value != 0 ) ? DC->translateString( "Yes" ) : DC->translateString( "No" ), 0, 0, item->textStyle ); } else { DC->drawText( item->textRect.x, item->textRect.y, item->textscale, newColor, ( value != 0 ) ? "Yes" : "No", 0, 0, item->textStyle ); } } void Item_Multi_Paint( itemDef_t *item ) { vec4_t newColor, lowLight; const char *text = ""; 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( DC->realTime / PULSE_DIVISOR ) ); } else { memcpy( &newColor, &item->window.foreColor, sizeof( vec4_t ) ); } text = Item_Multi_Setting( item ); if ( item->text ) { Item_Text_Paint( item ); DC->drawText( item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle ); } else { DC->drawText( item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle ); } } typedef struct { char *command; int id; int defaultbind1; int defaultbind2; int bind1; int bind2; } bind_t; typedef struct { char* name; float defaultvalue; float value; } configcvar_t; static bind_t g_bindings[] = { {"+scores", -1, -1, -1, -1}, {"+speed", K_SHIFT, -1, -1, -1}, {"+forward", K_UPARROW, -1, -1, -1}, {"+back", K_DOWNARROW, -1, -1, -1}, {"+moveleft", ',', -1, -1, -1}, {"+moveright", '.', -1, -1, -1}, {"+moveup", K_SPACE, -1, -1, -1}, {"+movedown", 'c', -1, -1, -1}, {"+left", K_LEFTARROW, -1, -1, -1}, {"+right", K_RIGHTARROW, -1, -1, -1}, {"+strafe", K_ALT, -1, -1, -1}, {"+lookup", K_PGDN, -1, -1, -1}, {"+lookdown", K_DEL, -1, -1, -1}, {"+mlook", '/', -1, -1, -1}, {"centerview", K_END, -1, -1, -1}, {"+zoom", 'z', -1, -1, -1}, {"weaponbank 1", '1', -1, -1, -1}, {"weaponbank 2", '2', -1, -1, -1}, {"weaponbank 3", '3', -1, -1, -1}, {"weaponbank 4", '4', -1, -1, -1}, {"weaponbank 5", '5', -1, -1, -1}, {"weaponbank 6", '6', -1, -1, -1}, {"weaponbank 7", '7', -1, -1, -1}, {"weaponbank 8", '8', -1, -1, -1}, {"weaponbank 9", '9', -1, -1, -1}, {"weaponbank 10", '0', -1, -1, -1}, {"+attack", K_CTRL, -1, -1, -1}, {"weapprev", K_MWHEELDOWN, -1, -1, -1}, {"weapnext", K_MWHEELUP, -1, -1, -1}, {"weapalt", -1, -1, -1, -1}, {"weaplastused", -1, -1, -1, -1}, //----(SA) added {"weapnextinbank", -1, -1, -1, -1}, //----(SA) added {"weapprevinbank", -1, -1, -1, -1}, //----(SA) added {"+useitem", K_ENTER, -1, -1, -1}, {"itemprev", '[', -1, -1, -1}, {"itemnext", ']', -1, -1, -1}, {"+button3", K_MOUSE3, -1, -1, -1}, /* {"prevTeamMember", -1, -1, -1, -1}, {"nextTeamMember", -1, -1, -1, -1}, {"nextOrder", -1, -1, -1, -1}, {"confirmOrder", -1, -1, -1, -1}, {"denyOrder", -1, -1, -1, -1}, {"taskOffense", -1, -1, -1, -1}, {"taskDefense", -1, -1, -1, -1}, {"taskPatrol", -1, -1, -1, -1}, {"taskCamp", -1, -1, -1, -1}, {"taskFollow", -1, -1, -1, -1}, {"taskRetrieve", -1, -1, -1, -1}, {"taskEscort", -1, -1, -1, -1}, {"taskOwnFlag", -1, -1, -1, -1}, {"taskSuicide", -1, -1, -1, -1}, {"tauntKillInsult", -1, -1, -1, -1}, {"tauntPraise", -1, -1, -1, -1}, {"tauntTaunt", -1, -1, -1, -1}, {"tauntDeathInsult",-1, -1, -1, -1}, {"tauntGauntlet", -1, -1, -1, -1}, */ {"scoresUp", -1, -1, -1, -1}, {"scoresDown", -1, -1, -1, -1}, {"messagemode", -1, -1, -1, -1}, {"messagemode2", -1, -1, -1, -1}, {"messagemode3", -1, -1, -1, -1}, {"messagemode4", -1, -1, -1, -1}, {"+activate", -1, -1, -1, -1}, {"zoomin", -1, -1, -1, -1}, {"zoomout", -1, -1, -1, -1}, {"+kick", -1, -1, -1, -1}, {"+reload", -1, -1, -1, -1}, {"+sprint", -1, -1, -1, -1}, {"notebook", K_TAB, -1, -1, -1}, {"help", K_F1, -1, -1, -1}, {"+leanleft", -1, -1, -1, -1}, {"+leanright", -1, -1, -1, -1}, // DHM - Nerve {"vote yes", -1, -1, -1, -1}, {"vote no", -1, -1, -1, -1}, // dhm // NERVE - SMF {"OpenLimboMenu", -1, -1, -1, -1}, {"mp_QuickMessage", -1, -1, -1, -1}, {"+dropweapon", -1, -1, -1, -1}, // -NERVE - SMF {"weapon 1", -1, -1, -1, -1}, {"weapon 2", -1, -1, -1, -1}, {"weapon 3", -1, -1, -1, -1}, {"weapon 4", -1, -1, -1, -1}, {"weapon 5", -1, -1, -1, -1}, {"weapon 6", -1, -1, -1, -1}, {"weapon 7", -1, -1, -1, -1}, {"weapon 8", -1, -1, -1, -1}, {"weapon 9", -1, -1, -1, -1}, {"weapon 10", -1, -1, -1, -1}, {"weapon 11", -1, -1, -1, -1}, {"weapon 12", -1, -1, -1, -1}, {"weapon 13", -1, -1, -1, -1}, {"weapon 14", -1, -1, -1, -1}, {"weapon 15", -1, -1, -1, -1}, {"weapon 16", -1, -1, -1, -1}, {"weapon 17", -1, -1, -1, -1}, {"weapon 18", -1, -1, -1, -1}, {"weapon 19", -1, -1, -1, -1}, {"weapon 20", -1, -1, -1, -1}, {"weapon 21", -1, -1, -1, -1}, {"weapon 22", -1, -1, -1, -1}, {"weapon 23", -1, -1, -1, -1}, {"weapon 24", -1, -1, -1, -1}, {"weapon 25", -1, -1, -1, -1}, {"weapon 26", -1, -1, -1, -1}, {"weapon 27", -1, -1, -1, -1}, {"weapon 28", -1, -1, -1, -1}, {"weapon 29", -1, -1, -1, -1}, {"weapon 30", -1, -1, -1, -1}, {"weapon 31", -1, -1, -1, -1}, {"weapon 32", -1, -1, -1, -1} }; static const int g_bindCount = sizeof( g_bindings ) / sizeof( bind_t ); /* // TTimo unused static configcvar_t g_configcvars[] = { {"cl_run", 0, 0}, {"m_pitch", 0, 0}, {"cg_autoswitch", 0, 0}, {"sensitivity", 0, 0}, {"in_joystick", 0, 0}, {"joy_threshold", 0, 0}, {"m_filter", 0, 0}, {"cl_freelook", 0, 0}, {"cg_quickMessageAlt", 0, 0}, // NERVE - SMF {NULL, 0, 0} }; */ /* ================= Controls_GetKeyAssignment ================= */ void Controls_GetKeyAssignment( char *command, int *twokeys ) { int count; int j; char b[256]; twokeys[0] = twokeys[1] = -1; count = 0; for ( j = 0; j < 256; j++ ) { DC->getBindingBuf( j, b, 256 ); if ( *b == 0 ) { continue; } if ( !Q_stricmp( b, command ) ) { twokeys[count] = j; count++; if ( count == 2 ) { break; } } } } /* ================= Controls_GetConfig ================= */ void Controls_GetConfig( void ) { int i; int twokeys[2]; // iterate each command, get its numeric binding for ( i = 0; i < g_bindCount; i++ ) { Controls_GetKeyAssignment( g_bindings[i].command, twokeys ); g_bindings[i].bind1 = twokeys[0]; g_bindings[i].bind2 = twokeys[1]; } //s_controls.invertmouse.curvalue = DC->getCVarValue( "m_pitch" ) < 0; //s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) ); //s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) ); //s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) ); //s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) ); //s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) ); //s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05, 0.75, Controls_GetCvarValue( "joy_threshold" ) ); //s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) ); } /* ================= Controls_SetConfig ================= */ void Controls_SetConfig( qboolean restart ) { int i; // iterate each command, get its numeric binding for ( i = 0; i < g_bindCount; i++ ) { if ( g_bindings[i].bind1 != -1 ) { DC->setBinding( g_bindings[i].bind1, g_bindings[i].command ); if ( g_bindings[i].bind2 != -1 ) { DC->setBinding( g_bindings[i].bind2, g_bindings[i].command ); } } } //if ( s_controls.invertmouse.curvalue ) // DC->setCVar("m_pitch", va("%f),-fabs( DC->getCVarValue( "m_pitch" ) ) ); //else // trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) ); //trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue ); //trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue ); //trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue ); //trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue ); //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue ); //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue ); //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue ); #if !defined( __MACOS__ ) DC->executeText( EXEC_APPEND, "in_restart\n" ); #endif //trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" ); } /* ================= Controls_SetDefaults ================= */ void Controls_SetDefaults( void ) { int i; // iterate each command, set its default binding for ( i = 0; i < g_bindCount; i++ ) { g_bindings[i].bind1 = g_bindings[i].defaultbind1; g_bindings[i].bind2 = g_bindings[i].defaultbind2; } //s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0; //s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" ); //s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" ); //s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" ); //s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" ); //s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" ); //s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" ); //s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" ); } int BindingIDFromName( const char *name ) { int i; for ( i = 0; i < g_bindCount; i++ ) { if ( Q_stricmp( name, g_bindings[i].command ) == 0 ) { return i; } } return -1; } char g_nameBind1[32]; char g_nameBind2[32]; char* BindingFromName( const char *cvar ) { int i, b1, b2; // iterate each command, set its default binding for ( i = 0; i < g_bindCount; i++ ) { if ( Q_stricmp( cvar, g_bindings[i].command ) == 0 ) { b1 = g_bindings[i].bind1; if ( b1 == -1 ) { break; } DC->keynumToStringBuf( b1, g_nameBind1, 32 ); Q_strupr( g_nameBind1 ); b2 = g_bindings[i].bind2; if ( b2 != -1 ) { DC->keynumToStringBuf( b2, g_nameBind2, 32 ); Q_strupr( g_nameBind2 ); strcat( g_nameBind1, DC->translateString( " or " ) ); strcat( g_nameBind1, g_nameBind2 ); } return g_nameBind1; // NERVE - SMF } } strcpy( g_nameBind1, "???" ); return g_nameBind1; // NERVE - SMF } void Item_Slider_Paint( itemDef_t *item ) { vec4_t newColor, lowLight; float x, y, value; menuDef_t *parent = (menuDef_t*)item->parent; value = ( item->cvar ) ? DC->getCVarValue( item->cvar ) : 0; 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( 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, 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 ); } void Item_Bind_Paint( itemDef_t *item ) { vec4_t newColor, lowLight; float value; int maxChars = 0; 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( DC->realTime / PULSE_DIVISOR ) ); } else { memcpy( &newColor, &item->window.foreColor, sizeof( vec4_t ) ); } if ( item->text ) { Item_Text_Paint( item ); BindingFromName( item->cvar ); DC->drawText( item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, 0, maxChars, item->textStyle ); } else { DC->drawText( item->textRect.x, item->textRect.y, item->textscale, newColor, ( value != 0 ) ? "FIXME" : "FIXME", 0, maxChars, item->textStyle ); } } qboolean Display_KeyBindPending() { return g_waitingForKey; } qboolean Item_Bind_HandleKey( itemDef_t *item, int key, qboolean down ) { int id; int i; if ( Rect_ContainsPoint( &item->window.rect, DC->cursorx, DC->cursory ) && !g_waitingForKey ) { if ( down && ( key == K_MOUSE1 || key == K_ENTER ) ) { g_waitingForKey = qtrue; g_bindItem = item; } return qtrue; } else { if ( !g_waitingForKey || g_bindItem == NULL ) { return qtrue; } if ( key & K_CHAR_FLAG ) { return qtrue; } switch ( key ) { case K_ESCAPE: g_waitingForKey = qfalse; return qtrue; case K_BACKSPACE: id = BindingIDFromName( item->cvar ); if ( id != -1 ) { g_bindings[id].bind1 = -1; g_bindings[id].bind2 = -1; } Controls_SetConfig( qtrue ); g_waitingForKey = qfalse; g_bindItem = NULL; return qtrue; case '`': return qtrue; } } if ( key != -1 ) { for ( i = 0; i < g_bindCount; i++ ) { if ( g_bindings[i].bind2 == key ) { g_bindings[i].bind2 = -1; } if ( g_bindings[i].bind1 == key ) { g_bindings[i].bind1 = g_bindings[i].bind2; g_bindings[i].bind2 = -1; } } } id = BindingIDFromName( item->cvar ); if ( id != -1 ) { if ( key == -1 ) { if ( g_bindings[id].bind1 != -1 ) { DC->setBinding( g_bindings[id].bind1, "" ); g_bindings[id].bind1 = -1; } if ( g_bindings[id].bind2 != -1 ) { DC->setBinding( g_bindings[id].bind2, "" ); g_bindings[id].bind2 = -1; } } else if ( g_bindings[id].bind1 == -1 ) { g_bindings[id].bind1 = key; } else if ( g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1 ) { g_bindings[id].bind2 = key; } else { DC->setBinding( g_bindings[id].bind1, "" ); DC->setBinding( g_bindings[id].bind2, "" ); g_bindings[id].bind1 = key; g_bindings[id].bind2 = -1; } } Controls_SetConfig( qtrue ); g_waitingForKey = qfalse; return qtrue; } void AdjustFrom640( float *x, float *y, float *w, float *h ) { //*x = *x * DC->scale + DC->bias; *x *= DC->xscale; *y *= DC->yscale; *w *= DC->xscale; *h *= DC->yscale; } void Item_Model_Paint( itemDef_t *item ) { float x, y, w, h; //,xx; refdef_t refdef; qhandle_t hModel; refEntity_t ent; vec3_t mins, maxs, origin; vec3_t angles; modelDef_t *modelPtr = (modelDef_t*)item->typeData; int backLerpWhole; if ( modelPtr == NULL ) { return; } if ( !item->asset ) { return; } hModel = item->asset; // 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; AdjustFrom640( &x, &y, &w, &h ); refdef.x = x; refdef.y = y; refdef.width = w; refdef.height = h; DC->modelBounds( hModel, 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; } #define NEWWAY #ifdef NEWWAY refdef.fov_x = ( modelPtr->fov_x ) ? modelPtr->fov_x : w; refdef.fov_y = ( modelPtr->fov_y ) ? modelPtr->fov_y : h; #else 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 ); #endif 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 ); AnglesToAxis( angles, ent.axis ); ent.hModel = hModel; if ( modelPtr->frameTime ) { // don't advance on the first frame modelPtr->backlerp += ( ( ( DC->realTime - modelPtr->frameTime ) / 1000.0f ) * (float)modelPtr->fps ); } if ( modelPtr->backlerp > 1 ) { backLerpWhole = floor( modelPtr->backlerp ); modelPtr->frame += ( backLerpWhole ); if ( ( modelPtr->frame - modelPtr->startframe ) > modelPtr->numframes ) { modelPtr->frame = modelPtr->startframe + modelPtr->frame % modelPtr->numframes; // todo: ignoring loopframes } modelPtr->oldframe += ( backLerpWhole ); if ( ( modelPtr->oldframe - modelPtr->startframe ) > modelPtr->numframes ) { modelPtr->oldframe = modelPtr->startframe + modelPtr->oldframe % modelPtr->numframes; // todo: ignoring loopframes } modelPtr->backlerp = modelPtr->backlerp - backLerpWhole; } modelPtr->frameTime = DC->realTime; ent.frame = modelPtr->frame; ent.oldframe = modelPtr->oldframe; ent.backlerp = 1.0f - modelPtr->backlerp; VectorCopy( origin, ent.origin ); VectorCopy( origin, ent.lightingOrigin ); ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW; VectorCopy( ent.origin, ent.oldorigin ); DC->addRefEntityToScene( &ent ); DC->renderScene( &refdef ); } void Item_Image_Paint( itemDef_t *item ) { if ( item == NULL ) { return; } DC->drawHandlePic( item->window.rect.x + 1, item->window.rect.y + 1, item->window.rect.w - 2, item->window.rect.h - 2, item->asset ); } void Item_ListBox_Paint( itemDef_t *item ) { float x, y, size, 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 ); // default is vertical if horizontal flag is not here if ( item->window.flags & WINDOW_HORIZONTAL ) { // draw scrollbar in bottom of the window // bar 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 ); // 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 ) { 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 { // 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 ); // 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->elementWidth; 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; for ( i = listPtr->startPos; 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 ( 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 ) { DC->drawText( x + 4 + listPtr->columnInfo[j].pos + item->textalignx, y + listPtr->elementHeight + item->textaligny, item->textscale, item->window.foreColor, text, 0, listPtr->columnInfo[j].maxChars, item->textStyle ); } } } 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, 0, item->textStyle ); } } if ( i == item->cursorPos ) { DC->fillRect( x, y, item->window.rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight - 1, item->window.outlineColor ); } size -= listPtr->elementHeight; if ( size < listPtr->elementHeight ) { listPtr->drawPadding = listPtr->elementHeight - size; break; } listPtr->endPos++; y += listPtr->elementHeight; // fit++; } } } } 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; 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 ); 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, item->colorRangeType ); 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; } } } // take hudalpha into account unless explicitly ignoring if ( !( item->window.flags & WINDOW_IGNORE_HUDALPHA ) ) { color[3] *= DC->getCVarValue( "cg_hudAlpha" );; } 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( 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( DC->realTime / PULSE_DIVISOR ) ); } 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 ); if ( item->text[0] ) { // +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 ); } else { DC->ownerDrawItem( item->textRect.x + item->textRect.w, 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 ); } } 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 ); } } } void Item_Paint( itemDef_t *item ) { vec4_t red; menuDef_t *parent = (menuDef_t*)item->parent; red[0] = red[3] = 1; red[1] = red[2] = 0; if ( item == NULL ) { return; } // NERVE - SMF if ( DC->textFont ) { DC->textFont( item->font ); } 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 = 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; } } } 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->cvarFlags & ( CVAR_SHOW | CVAR_HIDE ) ) { if ( !Item_EnableShowViaCvar( item, CVAR_SHOW ) ) { return; } } if ( item->window.flags & WINDOW_TIMEDVISIBLE ) { } if ( !( item->window.flags & WINDOW_VISIBLE ) ) { return; } // paint the rect first.. Window_Paint( &item->window, parent->fadeAmount, parent->fadeClamp, parent->fadeCycle ); if ( debugMode ) { vec4_t color; rectDef_t *r = Item_CorrectedTextRect( item ); color[1] = color[3] = 1; color[0] = color[2] = 0; DC->drawRect( r->x, r->y, r->w, r->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_IMAGE: // Item_Image_Paint(item); // break; case ITEM_TYPE_MENUMODEL: Item_Model_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; } } void Menu_Init( menuDef_t *menu ) { memset( menu, 0, sizeof( menuDef_t ) ); menu->cursorItem = -1; menu->fadeAmount = DC->Assets.fadeAmount; menu->fadeClamp = DC->Assets.fadeClamp; menu->fadeCycle = DC->Assets.fadeCycle; Window_Init( &menu->window ); } itemDef_t *Menu_GetFocusedItem( menuDef_t *menu ) { int i; if ( menu ) { for ( i = 0; i < menu->itemCount; i++ ) { if ( menu->items[i]->window.flags & WINDOW_HASFOCUS ) { return menu->items[i]; } } } return NULL; } menuDef_t *Menu_GetFocused() { 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; } void Menu_ScrollFeeder( menuDef_t *menu, int feeder, qboolean down ) { if ( menu ) { int i; for ( i = 0; i < menu->itemCount; i++ ) { if ( menu->items[i]->special == feeder ) { Item_ListBox_HandleKey( menu->items[i], ( down ) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue ); return; } } } } void Menu_SetFeederSelection( menuDef_t *menu, int feeder, int index, const char *name ) { if ( menu == NULL ) { if ( name == NULL ) { menu = Menu_GetFocused(); } else { menu = Menus_FindByName( name ); } } if ( menu ) { int i; for ( i = 0; i < menu->itemCount; i++ ) { if ( menu->items[i]->special == feeder ) { if ( index == 0 ) { listBoxDef_t *listPtr = (listBoxDef_t*)menu->items[i]->typeData; listPtr->cursorPos = 0; listPtr->startPos = 0; } menu->items[i]->cursorPos = index; DC->feederSelection( menu->items[i]->special, menu->items[i]->cursorPos ); return; } } } } qboolean Menus_AnyFullScreenVisible() { int i; for ( i = 0; i < menuCount; i++ ) { if ( Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen ) { return qtrue; } } return qfalse; } menuDef_t *Menus_ActivateByName( const char *p, qboolean modalStack ) { int i; menuDef_t *m = NULL; menuDef_t *focus = Menu_GetFocused(); for ( i = 0; i < menuCount; i++ ) { if ( Q_stricmp( Menus[i].window.name, p ) == 0 ) { m = &Menus[i]; Menus_Activate( m ); if ( modalStack && m->window.flags & WINDOW_MODAL ) { if ( modalMenuCount >= MAX_MODAL_MENUS ) { Com_Error( ERR_DROP, "MAX_MODAL_MENUS exceeded\n" ); } modalMenuStack[modalMenuCount++] = focus; } } else { Menus[i].window.flags &= ~WINDOW_HASFOCUS; } } Display_CloseCinematics(); return m; } void Item_Init( itemDef_t *item ) { memset( item, 0, sizeof( itemDef_t ) ); item->textscale = 0.55f; Window_Init( &item->window ); } 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 ) { if ( itemCapture->type == ITEM_TYPE_LISTBOX ) { // NERVE - SMF - lose capture if out of client rect if ( !Rect_ContainsPoint( &itemCapture->window.rect, x, y ) ) { Item_StopCapture( itemCapture ); itemCapture = NULL; captureFunc = NULL; captureData = NULL; } } //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; } // 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( Item_CorrectedTextRect( overItem ), 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 ); } } } } void Menu_Paint( menuDef_t *menu, qboolean forcePaint ) { int i; if ( menu == NULL ) { return; } 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 ) { // implies a background shader // FIXME: make sure we have a default shader if fullscreen is set with no background 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 ); for ( i = 0; i < menu->itemCount; i++ ) { Item_Paint( menu->items[i] ); } if ( 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_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 ) ); } else if ( item->type == ITEM_TYPE_MENUMODEL ) { item->typeData = UI_Alloc( sizeof( modelDef_t ) ); } } /* =============== Keyword Hash =============== */ #define KEYWORDHASH_SIZE 512 typedef struct keywordHash_s { char *keyword; qboolean ( *func )( itemDef_t *item, int handle ); struct keywordHash_s *next; } keywordHash_t; int KeywordHash_Key( char *keyword ) { int register 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; } void KeywordHash_Add( keywordHash_t *table[], keywordHash_t *key ) { int hash; hash = KeywordHash_Key( key->keyword ); /* if (table[hash]) { int collision = qtrue; } */ key->next = table[hash]; table[hash] = key; } keywordHash_t *KeywordHash_Find( keywordHash_t *table[], 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; } /* =============== Item Keyword Parse functions =============== */ // name qboolean ItemParse_name( itemDef_t *item, int handle ) { if ( !PC_String_Parse( handle, &item->window.name ) ) { return qfalse; } return qtrue; } // name qboolean ItemParse_focusSound( itemDef_t *item, int handle ) { const char *temp; if ( !PC_String_Parse( handle, &temp ) ) { return qfalse; } item->focusSound = DC->registerSound( temp ); return qtrue; } // text qboolean ItemParse_text( itemDef_t *item, int handle ) { if ( !PC_String_Parse( handle, &item->text ) ) { return qfalse; } return qtrue; } //----(SA) added // textfile // read an external textfile into item->text qboolean ItemParse_textfile( itemDef_t *item, int handle ) { const char *newtext; pc_token_t token; if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } newtext = DC->fileText( token.string ); item->text = String_Alloc( newtext ); return qtrue; } //----(SA) // group qboolean ItemParse_group( itemDef_t *item, int handle ) { if ( !PC_String_Parse( handle, &item->window.group ) ) { return qfalse; } return qtrue; } // asset_model qboolean ItemParse_asset_model( itemDef_t *item, int handle ) { const char *temp; modelDef_t *modelPtr; Item_ValidateTypeData( item ); modelPtr = (modelDef_t*)item->typeData; if ( !PC_String_Parse( handle, &temp ) ) { return qfalse; } if ( !( item->asset ) ) { item->asset = DC->registerModel( temp ); // modelPtr->angle = rand() % 360; } return qtrue; } // asset_shader qboolean ItemParse_asset_shader( itemDef_t *item, int handle ) { const char *temp; if ( !PC_String_Parse( handle, &temp ) ) { return qfalse; } item->asset = DC->registerShaderNoMip( temp ); return qtrue; } // model_origin qboolean ItemParse_model_origin( itemDef_t *item, int handle ) { modelDef_t *modelPtr; Item_ValidateTypeData( item ); modelPtr = (modelDef_t*)item->typeData; if ( PC_Float_Parse( handle, &modelPtr->origin[0] ) ) { if ( PC_Float_Parse( handle, &modelPtr->origin[1] ) ) { if ( PC_Float_Parse( handle, &modelPtr->origin[2] ) ) { return qtrue; } } } return qfalse; } // model_fovx qboolean ItemParse_model_fovx( itemDef_t *item, int handle ) { modelDef_t *modelPtr; Item_ValidateTypeData( item ); modelPtr = (modelDef_t*)item->typeData; if ( !PC_Float_Parse( handle, &modelPtr->fov_x ) ) { return qfalse; } return qtrue; } // model_fovy qboolean ItemParse_model_fovy( itemDef_t *item, int handle ) { modelDef_t *modelPtr; Item_ValidateTypeData( item ); modelPtr = (modelDef_t*)item->typeData; if ( !PC_Float_Parse( handle, &modelPtr->fov_y ) ) { return qfalse; } return qtrue; } // model_rotation qboolean ItemParse_model_rotation( itemDef_t *item, int handle ) { modelDef_t *modelPtr; Item_ValidateTypeData( item ); modelPtr = (modelDef_t*)item->typeData; if ( !PC_Int_Parse( handle, &modelPtr->rotationSpeed ) ) { return qfalse; } return qtrue; } // model_angle qboolean ItemParse_model_angle( itemDef_t *item, int handle ) { modelDef_t *modelPtr; Item_ValidateTypeData( item ); modelPtr = (modelDef_t*)item->typeData; if ( !PC_Int_Parse( handle, &modelPtr->angle ) ) { return qfalse; } return qtrue; } // model_animplay qboolean ItemParse_model_animplay( itemDef_t *item, int handle ) { modelDef_t *modelPtr; Item_ValidateTypeData( item ); modelPtr = (modelDef_t*)item->typeData; modelPtr->animated = 1; if ( !PC_Int_Parse( handle, &modelPtr->startframe ) ) { return qfalse; } if ( !PC_Int_Parse( handle, &modelPtr->numframes ) ) { return qfalse; } if ( !PC_Int_Parse( handle, &modelPtr->loopframes ) ) { return qfalse; } if ( !PC_Int_Parse( handle, &modelPtr->fps ) ) { return qfalse; } modelPtr->frame = modelPtr->startframe + 1; modelPtr->oldframe = modelPtr->startframe; modelPtr->backlerp = 0.0f; modelPtr->frameTime = DC->realTime; return qtrue; } // rect qboolean ItemParse_rect( itemDef_t *item, int handle ) { if ( !PC_Rect_Parse( handle, &item->window.rectClient ) ) { return qfalse; } return qtrue; } // NERVE - SMF // origin qboolean ItemParse_origin( itemDef_t *item, int handle ) { int x, y; if ( !PC_Int_Parse( handle, &x ) ) { return qfalse; } if ( !PC_Int_Parse( handle, &y ) ) { return qfalse; } item->window.rectClient.x += x; item->window.rectClient.y += y; return qtrue; } // -NERVE - SMF // style qboolean ItemParse_style( itemDef_t *item, int handle ) { if ( !PC_Int_Parse( handle, &item->window.style ) ) { return qfalse; } return qtrue; } // decoration qboolean ItemParse_decoration( itemDef_t *item, int handle ) { item->window.flags |= WINDOW_DECORATION; return qtrue; } // notselectable qboolean ItemParse_notselectable( itemDef_t *item, int handle ) { listBoxDef_t *listPtr; Item_ValidateTypeData( item ); listPtr = (listBoxDef_t*)item->typeData; if ( item->type == ITEM_TYPE_LISTBOX && listPtr ) { listPtr->notselectable = qtrue; } return qtrue; } // manually wrapped qboolean ItemParse_wrapped( itemDef_t *item, int handle ) { item->window.flags |= WINDOW_WRAPPED; return qtrue; } // auto wrapped qboolean ItemParse_autowrapped( itemDef_t *item, int handle ) { item->window.flags |= WINDOW_AUTOWRAPPED; return qtrue; } // horizontalscroll qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) { item->window.flags |= WINDOW_HORIZONTAL; return qtrue; } // type qboolean ItemParse_type( itemDef_t *item, int handle ) { if ( !PC_Int_Parse( handle, &item->type ) ) { return qfalse; } Item_ValidateTypeData( item ); return qtrue; } // elementwidth, used for listbox image elements // uses textalignx for storage qboolean ItemParse_elementwidth( itemDef_t *item, int handle ) { listBoxDef_t *listPtr; Item_ValidateTypeData( item ); listPtr = (listBoxDef_t*)item->typeData; if ( !PC_Float_Parse( handle, &listPtr->elementWidth ) ) { return qfalse; } return qtrue; } // elementheight, used for listbox image elements // uses textaligny for storage qboolean ItemParse_elementheight( itemDef_t *item, int handle ) { listBoxDef_t *listPtr; Item_ValidateTypeData( item ); listPtr = (listBoxDef_t*)item->typeData; if ( !PC_Float_Parse( handle, &listPtr->elementHeight ) ) { return qfalse; } return qtrue; } // feeder qboolean ItemParse_feeder( itemDef_t *item, int handle ) { if ( !PC_Float_Parse( handle, &item->special ) ) { return qfalse; } return qtrue; } // elementtype, used to specify what type of elements a listbox contains // uses textstyle for storage qboolean ItemParse_elementtype( itemDef_t *item, int handle ) { listBoxDef_t *listPtr; Item_ValidateTypeData( item ); if ( !item->typeData ) { return qfalse; } listPtr = (listBoxDef_t*)item->typeData; if ( !PC_Int_Parse( handle, &listPtr->elementStyle ) ) { return qfalse; } return qtrue; } // columns sets a number of columns and an x pos and width per.. qboolean ItemParse_columns( itemDef_t *item, int handle ) { int num, i; listBoxDef_t *listPtr; Item_ValidateTypeData( item ); if ( !item->typeData ) { return qfalse; } listPtr = (listBoxDef_t*)item->typeData; if ( PC_Int_Parse( handle, &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_Int_Parse( handle, &pos ) && PC_Int_Parse( handle, &width ) && PC_Int_Parse( handle, &maxChars ) ) { listPtr->columnInfo[i].pos = pos; listPtr->columnInfo[i].width = width; listPtr->columnInfo[i].maxChars = maxChars; } else { return qfalse; } } } else { return qfalse; } return qtrue; } qboolean ItemParse_border( itemDef_t *item, int handle ) { if ( !PC_Int_Parse( handle, &item->window.border ) ) { return qfalse; } return qtrue; } qboolean ItemParse_bordersize( itemDef_t *item, int handle ) { if ( !PC_Float_Parse( handle, &item->window.borderSize ) ) { return qfalse; } return qtrue; } qboolean ItemParse_visible( itemDef_t *item, int handle ) { int i; if ( !PC_Int_Parse( handle, &i ) ) { return qfalse; } if ( i ) { item->window.flags |= WINDOW_VISIBLE; } return qtrue; } qboolean ItemParse_ownerdraw( itemDef_t *item, int handle ) { if ( !PC_Int_Parse( handle, &item->window.ownerDraw ) ) { return qfalse; } item->type = ITEM_TYPE_OWNERDRAW; return qtrue; } qboolean ItemParse_align( itemDef_t *item, int handle ) { if ( !PC_Int_Parse( handle, &item->alignment ) ) { return qfalse; } return qtrue; } qboolean ItemParse_textalign( itemDef_t *item, int handle ) { if ( !PC_Int_Parse( handle, &item->textalignment ) ) { return qfalse; } return qtrue; } qboolean ItemParse_textalignx( itemDef_t *item, int handle ) { if ( !PC_Float_Parse( handle, &item->textalignx ) ) { return qfalse; } return qtrue; } qboolean ItemParse_textaligny( itemDef_t *item, int handle ) { if ( !PC_Float_Parse( handle, &item->textaligny ) ) { return qfalse; } return qtrue; } qboolean ItemParse_textscale( itemDef_t *item, int handle ) { if ( !PC_Float_Parse( handle, &item->textscale ) ) { return qfalse; } return qtrue; } qboolean ItemParse_textstyle( itemDef_t *item, int handle ) { if ( !PC_Int_Parse( handle, &item->textStyle ) ) { return qfalse; } return qtrue; } //----(SA) added for forcing a font for a given item qboolean ItemParse_textfont( itemDef_t *item, int handle ) { if ( !PC_Int_Parse( handle, &item->font ) ) { return qfalse; } return qtrue; } //----(SA) end qboolean ItemParse_backcolor( itemDef_t *item, int handle ) { int i; float f; for ( i = 0; i < 4; i++ ) { if ( !PC_Float_Parse( handle, &f ) ) { return qfalse; } item->window.backColor[i] = f; } return qtrue; } qboolean ItemParse_forecolor( itemDef_t *item, int handle ) { int i; float f; for ( i = 0; i < 4; i++ ) { if ( !PC_Float_Parse( handle, &f ) ) { return qfalse; } item->window.foreColor[i] = f; item->window.flags |= WINDOW_FORECOLORSET; } return qtrue; } qboolean ItemParse_bordercolor( itemDef_t *item, int handle ) { int i; float f; for ( i = 0; i < 4; i++ ) { if ( !PC_Float_Parse( handle, &f ) ) { return qfalse; } item->window.borderColor[i] = f; } return qtrue; } qboolean ItemParse_outlinecolor( itemDef_t *item, int handle ) { if ( !PC_Color_Parse( handle, &item->window.outlineColor ) ) { return qfalse; } return qtrue; } qboolean ItemParse_background( itemDef_t *item, int handle ) { const char *temp; if ( !PC_String_Parse( handle, &temp ) ) { return qfalse; } item->window.background = DC->registerShaderNoMip( temp ); return qtrue; } qboolean ItemParse_cinematic( itemDef_t *item, int handle ) { if ( !PC_String_Parse( handle, &item->window.cinematicName ) ) { return qfalse; } return qtrue; } qboolean ItemParse_doubleClick( itemDef_t *item, int handle ) { listBoxDef_t *listPtr; Item_ValidateTypeData( item ); if ( !item->typeData ) { return qfalse; } listPtr = (listBoxDef_t*)item->typeData; if ( !PC_Script_Parse( handle, &listPtr->doubleClick ) ) { return qfalse; } return qtrue; } qboolean ItemParse_onFocus( itemDef_t *item, int handle ) { if ( !PC_Script_Parse( handle, &item->onFocus ) ) { return qfalse; } return qtrue; } qboolean ItemParse_leaveFocus( itemDef_t *item, int handle ) { if ( !PC_Script_Parse( handle, &item->leaveFocus ) ) { return qfalse; } return qtrue; } qboolean ItemParse_mouseEnter( itemDef_t *item, int handle ) { if ( !PC_Script_Parse( handle, &item->mouseEnter ) ) { return qfalse; } return qtrue; } qboolean ItemParse_mouseExit( itemDef_t *item, int handle ) { if ( !PC_Script_Parse( handle, &item->mouseExit ) ) { return qfalse; } return qtrue; } qboolean ItemParse_mouseEnterText( itemDef_t *item, int handle ) { if ( !PC_Script_Parse( handle, &item->mouseEnterText ) ) { return qfalse; } return qtrue; } qboolean ItemParse_mouseExitText( itemDef_t *item, int handle ) { if ( !PC_Script_Parse( handle, &item->mouseExitText ) ) { return qfalse; } return qtrue; } qboolean ItemParse_action( itemDef_t *item, int handle ) { if ( !PC_Script_Parse( handle, &item->action ) ) { return qfalse; } return qtrue; } // NERVE - SMF qboolean ItemParse_accept( itemDef_t *item, int handle ) { if ( !PC_Script_Parse( handle, &item->onAccept ) ) { return qfalse; } return qtrue; } // -NERVE - SMF qboolean ItemParse_special( itemDef_t *item, int handle ) { if ( !PC_Float_Parse( handle, &item->special ) ) { return qfalse; } return qtrue; } qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) { if ( !PC_String_Parse( handle, &item->cvarTest ) ) { return qfalse; } return qtrue; } qboolean ItemParse_cvar( itemDef_t *item, int handle ) { editFieldDef_t *editPtr; Item_ValidateTypeData( item ); if ( !PC_String_Parse( handle, &item->cvar ) ) { return qfalse; } if ( item->typeData ) { editPtr = (editFieldDef_t*)item->typeData; editPtr->minVal = -1; editPtr->maxVal = -1; editPtr->defVal = -1; } return qtrue; } qboolean ItemParse_maxChars( itemDef_t *item, int handle ) { editFieldDef_t *editPtr; int maxChars; Item_ValidateTypeData( item ); if ( !item->typeData ) { return qfalse; } if ( !PC_Int_Parse( handle, &maxChars ) ) { return qfalse; } editPtr = (editFieldDef_t*)item->typeData; editPtr->maxChars = maxChars; return qtrue; } qboolean ItemParse_maxPaintChars( itemDef_t *item, int handle ) { editFieldDef_t *editPtr; int maxChars; Item_ValidateTypeData( item ); if ( !item->typeData ) { return qfalse; } if ( !PC_Int_Parse( handle, &maxChars ) ) { return qfalse; } editPtr = (editFieldDef_t*)item->typeData; editPtr->maxPaintChars = maxChars; return qtrue; } qboolean ItemParse_cvarFloat( itemDef_t *item, int handle ) { editFieldDef_t *editPtr; Item_ValidateTypeData( item ); if ( !item->typeData ) { return qfalse; } editPtr = (editFieldDef_t*)item->typeData; if ( PC_String_Parse( handle, &item->cvar ) && PC_Float_Parse( handle, &editPtr->defVal ) && PC_Float_Parse( handle, &editPtr->minVal ) && PC_Float_Parse( handle, &editPtr->maxVal ) ) { return qtrue; } return qfalse; } qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) { pc_token_t 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 ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } if ( *token.string != '{' ) { return qfalse; } pass = 0; while ( 1 ) { if ( !trap_PC_ReadToken( handle, &token ) ) { PC_SourceError( handle, "end of file inside menu item\n" ); return qfalse; } if ( *token.string == '}' ) { return qtrue; } if ( *token.string == ',' || *token.string == ';' ) { continue; } if ( pass == 0 ) { multiPtr->cvarList[multiPtr->count] = String_Alloc( token.string ); pass = 1; } else { multiPtr->cvarStr[multiPtr->count] = String_Alloc( token.string ); pass = 0; multiPtr->count++; if ( multiPtr->count >= MAX_MULTI_CVARS ) { return qfalse; } } } return qfalse; // bk001205 - LCC missing return value } qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) { pc_token_t token; multiDef_t *multiPtr; Item_ValidateTypeData( item ); if ( !item->typeData ) { return qfalse; } multiPtr = (multiDef_t*)item->typeData; multiPtr->count = 0; multiPtr->strDef = qfalse; if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } if ( *token.string != '{' ) { return qfalse; } while ( 1 ) { if ( !trap_PC_ReadToken( handle, &token ) ) { PC_SourceError( handle, "end of file inside menu item\n" ); return qfalse; } if ( *token.string == '}' ) { return qtrue; } if ( *token.string == ',' || *token.string == ';' ) { continue; } multiPtr->cvarList[multiPtr->count] = String_Alloc( token.string ); if ( !PC_Float_Parse( handle, &multiPtr->cvarValue[multiPtr->count] ) ) { return qfalse; } multiPtr->count++; if ( multiPtr->count >= MAX_MULTI_CVARS ) { return qfalse; } } return qfalse; // bk001205 - LCC missing return value } qboolean ParseColorRange( itemDef_t *item, int handle, int type ) { colorRangeDef_t color; if ( item->numColors && type != item->colorRangeType ) { PC_SourceError( handle, "both addColorRange and addColorRangeRel - set within same itemdef\n" ); return qfalse; } item->colorRangeType = type; if ( PC_Float_Parse( handle, &color.low ) && PC_Float_Parse( handle, &color.high ) && PC_Color_Parse( handle, &color.color ) ) { if ( item->numColors < MAX_COLOR_RANGES ) { memcpy( &item->colorRanges[item->numColors], &color, sizeof( color ) ); item->numColors++; } return qtrue; } return qfalse; } qboolean ItemParse_addColorRangeRel( itemDef_t *item, int handle ) { return ParseColorRange( item, handle, RANGETYPE_RELATIVE ); } qboolean ItemParse_addColorRange( itemDef_t *item, int handle ) { return ParseColorRange( item, handle, RANGETYPE_ABSOLUTE ); } qboolean ItemParse_ownerdrawFlag( itemDef_t *item, int handle ) { int i; if ( !PC_Int_Parse( handle, &i ) ) { return qfalse; } item->window.ownerDrawFlags |= i; return qtrue; } qboolean ItemParse_enableCvar( itemDef_t *item, int handle ) { if ( PC_Script_Parse( handle, &item->enableCvar ) ) { item->cvarFlags = CVAR_ENABLE; return qtrue; } return qfalse; } qboolean ItemParse_disableCvar( itemDef_t *item, int handle ) { if ( PC_Script_Parse( handle, &item->enableCvar ) ) { item->cvarFlags = CVAR_DISABLE; return qtrue; } return qfalse; } qboolean ItemParse_noToggle( itemDef_t *item, int handle ) { item->cvarFlags |= CVAR_NOTOGGLE; return qtrue; } qboolean ItemParse_showCvar( itemDef_t *item, int handle ) { if ( PC_Script_Parse( handle, &item->enableCvar ) ) { item->cvarFlags = CVAR_SHOW; return qtrue; } return qfalse; } qboolean ItemParse_hideCvar( itemDef_t *item, int handle ) { if ( PC_Script_Parse( handle, &item->enableCvar ) ) { item->cvarFlags = CVAR_HIDE; return qtrue; } return qfalse; } keywordHash_t itemParseKeywords[] = { {"name", ItemParse_name, NULL}, {"text", ItemParse_text, NULL}, {"textfile", ItemParse_textfile, NULL}, //----(SA) added {"group", ItemParse_group, NULL}, {"asset_model", ItemParse_asset_model, NULL}, {"asset_shader", ItemParse_asset_shader, NULL}, {"model_origin", ItemParse_model_origin, NULL}, {"model_fovx", ItemParse_model_fovx, NULL}, {"model_fovy", ItemParse_model_fovy, NULL}, {"model_rotation", ItemParse_model_rotation, NULL}, {"model_angle", ItemParse_model_angle, NULL}, {"model_animplay", ItemParse_model_animplay, NULL}, {"rect", ItemParse_rect, NULL}, {"origin", ItemParse_origin, NULL}, // NERVE - SMF {"style", ItemParse_style, NULL}, {"decoration", ItemParse_decoration, NULL}, {"notselectable", ItemParse_notselectable, NULL}, {"wrapped", ItemParse_wrapped, NULL}, {"autowrapped", ItemParse_autowrapped, NULL}, {"horizontalscroll", ItemParse_horizontalscroll, NULL}, {"type", ItemParse_type, NULL}, {"elementwidth", ItemParse_elementwidth, NULL}, {"elementheight", ItemParse_elementheight, NULL}, {"feeder", ItemParse_feeder, NULL}, {"elementtype", ItemParse_elementtype, NULL}, {"columns", ItemParse_columns, NULL}, {"border", ItemParse_border, NULL}, {"bordersize", ItemParse_bordersize, NULL}, {"visible", ItemParse_visible, NULL}, {"ownerdraw", ItemParse_ownerdraw, NULL}, {"align", ItemParse_align, NULL}, {"textalign", ItemParse_textalign, NULL}, {"textalignx", ItemParse_textalignx, NULL}, {"textaligny", ItemParse_textaligny, NULL}, {"textscale", ItemParse_textscale, NULL}, {"textstyle", ItemParse_textstyle, NULL}, {"textfont", ItemParse_textfont, NULL}, // (SA) {"backcolor", ItemParse_backcolor, NULL}, {"forecolor", ItemParse_forecolor, NULL}, {"bordercolor", ItemParse_bordercolor, NULL}, {"outlinecolor", ItemParse_outlinecolor, NULL}, {"background", ItemParse_background, NULL}, {"onFocus", ItemParse_onFocus, NULL}, {"leaveFocus", ItemParse_leaveFocus, NULL}, {"mouseEnter", ItemParse_mouseEnter, NULL}, {"mouseExit", ItemParse_mouseExit, NULL}, {"mouseEnterText", ItemParse_mouseEnterText, NULL}, {"mouseExitText", ItemParse_mouseExitText, NULL}, {"action", ItemParse_action, NULL}, {"accept", ItemParse_accept, NULL}, // NERVE - SMF {"special", ItemParse_special, NULL}, {"cvar", ItemParse_cvar, NULL}, {"maxChars", ItemParse_maxChars, NULL}, {"maxPaintChars", ItemParse_maxPaintChars, NULL}, {"focusSound", ItemParse_focusSound, NULL}, {"cvarFloat", ItemParse_cvarFloat, NULL}, {"cvarStrList", ItemParse_cvarStrList, NULL}, {"cvarFloatList", ItemParse_cvarFloatList, NULL}, {"addColorRange", ItemParse_addColorRange, NULL}, {"addColorRangeRel", ItemParse_addColorRangeRel, NULL}, {"ownerdrawFlag", ItemParse_ownerdrawFlag, NULL}, {"enableCvar", ItemParse_enableCvar, NULL}, {"cvarTest", ItemParse_cvarTest, NULL}, {"disableCvar", ItemParse_disableCvar, NULL}, {"showCvar", ItemParse_showCvar, NULL}, {"hideCvar", ItemParse_hideCvar, NULL}, {"cinematic", ItemParse_cinematic, NULL}, {"doubleclick", ItemParse_doubleClick, NULL}, {"noToggle", ItemParse_noToggle, NULL}, // TTimo: use with ITEM_TYPE_YESNO and an action script (see sv_punkbuster) {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( int handle, itemDef_t *item ) { pc_token_t token; keywordHash_t *key; if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } if ( *token.string != '{' ) { return qfalse; } while ( 1 ) { if ( !trap_PC_ReadToken( handle, &token ) ) { PC_SourceError( handle, "end of file inside menu item\n" ); return qfalse; } if ( *token.string == '}' ) { return qtrue; } key = KeywordHash_Find( itemParseKeywordHash, token.string ); if ( !key ) { PC_SourceError( handle, "unknown menu item keyword %s", token.string ); continue; } if ( !key->func( item, handle ) ) { PC_SourceError( handle, "couldn't parse menu item keyword %s", token.string ); return qfalse; } } return qfalse; // bk001205 - LCC missing return value } // 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; } } } /* =============== Menu Keyword Parse functions =============== */ qboolean MenuParse_font( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_String_Parse( handle, &menu->font ) ) { return qfalse; } if ( !DC->Assets.fontRegistered ) { DC->registerFont( menu->font, 48, &DC->Assets.textFont ); DC->Assets.fontRegistered = qtrue; } return qtrue; } qboolean MenuParse_name( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_String_Parse( handle, &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; } qboolean MenuParse_fullscreen( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Int_Parse( handle, (int*)&menu->fullScreen ) ) { return qfalse; } return qtrue; } qboolean MenuParse_rect( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Rect_Parse( handle, &menu->window.rect ) ) { return qfalse; } return qtrue; } qboolean MenuParse_style( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Int_Parse( handle, &menu->window.style ) ) { return qfalse; } return qtrue; } qboolean MenuParse_visible( itemDef_t *item, int handle ) { int i; menuDef_t *menu = (menuDef_t*)item; if ( !PC_Int_Parse( handle, &i ) ) { return qfalse; } if ( i ) { menu->window.flags |= WINDOW_VISIBLE; } return qtrue; } qboolean MenuParse_onOpen( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Script_Parse( handle, &menu->onOpen ) ) { return qfalse; } return qtrue; } qboolean MenuParse_onClose( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Script_Parse( handle, &menu->onClose ) ) { return qfalse; } return qtrue; } qboolean MenuParse_onESC( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Script_Parse( handle, &menu->onESC ) ) { return qfalse; } return qtrue; } qboolean MenuParse_border( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Int_Parse( handle, &menu->window.border ) ) { return qfalse; } return qtrue; } qboolean MenuParse_borderSize( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Float_Parse( handle, &menu->window.borderSize ) ) { return qfalse; } return qtrue; } qboolean MenuParse_backcolor( itemDef_t *item, int handle ) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for ( i = 0; i < 4; i++ ) { if ( !PC_Float_Parse( handle, &f ) ) { return qfalse; } menu->window.backColor[i] = f; } return qtrue; } qboolean MenuParse_forecolor( itemDef_t *item, int handle ) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for ( i = 0; i < 4; i++ ) { if ( !PC_Float_Parse( handle, &f ) ) { return qfalse; } menu->window.foreColor[i] = f; menu->window.flags |= WINDOW_FORECOLORSET; } return qtrue; } qboolean MenuParse_bordercolor( itemDef_t *item, int handle ) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for ( i = 0; i < 4; i++ ) { if ( !PC_Float_Parse( handle, &f ) ) { return qfalse; } menu->window.borderColor[i] = f; } return qtrue; } qboolean MenuParse_focuscolor( itemDef_t *item, int handle ) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for ( i = 0; i < 4; i++ ) { if ( !PC_Float_Parse( handle, &f ) ) { return qfalse; } menu->focusColor[i] = f; } return qtrue; } qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) { int i; float f; menuDef_t *menu = (menuDef_t*)item; for ( i = 0; i < 4; i++ ) { if ( !PC_Float_Parse( handle, &f ) ) { return qfalse; } menu->disableColor[i] = f; } return qtrue; } qboolean MenuParse_outlinecolor( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Color_Parse( handle, &menu->window.outlineColor ) ) { return qfalse; } return qtrue; } qboolean MenuParse_background( itemDef_t *item, int handle ) { const char *buff; menuDef_t *menu = (menuDef_t*)item; if ( !PC_String_Parse( handle, &buff ) ) { return qfalse; } menu->window.background = DC->registerShaderNoMip( buff ); return qtrue; } qboolean MenuParse_cinematic( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_String_Parse( handle, &menu->window.cinematicName ) ) { return qfalse; } return qtrue; } qboolean MenuParse_ownerdrawFlag( itemDef_t *item, int handle ) { int i; menuDef_t *menu = (menuDef_t*)item; if ( !PC_Int_Parse( handle, &i ) ) { return qfalse; } menu->window.ownerDrawFlags |= i; return qtrue; } qboolean MenuParse_ownerdraw( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Int_Parse( handle, &menu->window.ownerDraw ) ) { return qfalse; } return qtrue; } // decoration qboolean MenuParse_popup( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; menu->window.flags |= WINDOW_POPUP; return qtrue; } qboolean MenuParse_outOfBounds( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; menu->window.flags |= WINDOW_OOB_CLICK; return qtrue; } qboolean MenuParse_soundLoop( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_String_Parse( handle, &menu->soundName ) ) { return qfalse; } return qtrue; } qboolean MenuParse_fadeClamp( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Float_Parse( handle, &menu->fadeClamp ) ) { return qfalse; } return qtrue; } qboolean MenuParse_fadeAmount( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Float_Parse( handle, &menu->fadeAmount ) ) { return qfalse; } return qtrue; } qboolean MenuParse_fadeCycle( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( !PC_Int_Parse( handle, &menu->fadeCycle ) ) { return qfalse; } return qtrue; } qboolean MenuParse_itemDef( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; if ( menu->itemCount < MAX_MENUITEMS ) { menu->items[menu->itemCount] = UI_Alloc( sizeof( itemDef_t ) ); Item_Init( menu->items[menu->itemCount] ); if ( !Item_Parse( handle, menu->items[menu->itemCount] ) ) { return qfalse; } Item_InitControls( menu->items[menu->itemCount] ); menu->items[menu->itemCount++]->parent = menu; } return qtrue; } // NERVE - SMF qboolean MenuParse_execKey( itemDef_t *item, int handle ) { menuDef_t *menu = ( menuDef_t* )item; char keyname; short int keyindex; if ( !PC_Char_Parse( handle, &keyname ) ) { return qfalse; } keyindex = keyname; if ( !PC_Script_Parse( handle, &menu->onKey[keyindex] ) ) { return qfalse; } return qtrue; } qboolean MenuParse_execKeyInt( itemDef_t *item, int handle ) { menuDef_t *menu = ( menuDef_t* )item; int keyname; if ( !PC_Int_Parse( handle, &keyname ) ) { return qfalse; } if ( !PC_Script_Parse( handle, &menu->onKey[keyname] ) ) { return qfalse; } return qtrue; } // -NERVE - SMF // TTimo qboolean MenuParse_modal( itemDef_t *item, int handle ) { menuDef_t *menu = (menuDef_t*)item; menu->window.flags |= WINDOW_MODAL; return qtrue; } keywordHash_t menuParseKeywords[] = { {"font", MenuParse_font, NULL}, {"name", MenuParse_name, NULL}, {"fullscreen", MenuParse_fullscreen, NULL}, {"rect", MenuParse_rect, NULL}, {"style", MenuParse_style, NULL}, {"visible", MenuParse_visible, NULL}, {"onOpen", MenuParse_onOpen, NULL}, {"onClose", MenuParse_onClose, NULL}, {"onESC", MenuParse_onESC, NULL}, {"border", MenuParse_border, NULL}, {"borderSize", MenuParse_borderSize, NULL}, {"backcolor", MenuParse_backcolor, NULL}, {"forecolor", MenuParse_forecolor, NULL}, {"bordercolor", MenuParse_bordercolor, NULL}, {"focuscolor", MenuParse_focuscolor, NULL}, {"disablecolor", MenuParse_disablecolor, NULL}, {"outlinecolor", MenuParse_outlinecolor, NULL}, {"background", MenuParse_background, NULL}, {"ownerdraw", MenuParse_ownerdraw, NULL}, {"ownerdrawFlag", MenuParse_ownerdrawFlag, NULL}, {"outOfBoundsClick", MenuParse_outOfBounds, NULL}, {"soundLoop", MenuParse_soundLoop, NULL}, {"itemDef", MenuParse_itemDef, NULL}, {"cinematic", MenuParse_cinematic, NULL}, {"popup", MenuParse_popup, NULL}, {"fadeClamp", MenuParse_fadeClamp, NULL}, {"fadeCycle", MenuParse_fadeCycle, NULL}, {"fadeAmount", MenuParse_fadeAmount, NULL}, {"execKey", MenuParse_execKey, NULL}, // NERVE - SMF {"execKeyInt", MenuParse_execKeyInt, NULL}, // NERVE - SMF {"modal", MenuParse_modal, NULL }, {NULL, NULL, NULL} }; keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE]; /* =============== 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] ); } } /* =============== Menu_Parse =============== */ qboolean Menu_Parse( int handle, menuDef_t *menu ) { pc_token_t token; keywordHash_t *key; if ( !trap_PC_ReadToken( handle, &token ) ) { return qfalse; } if ( *token.string != '{' ) { return qfalse; } while ( 1 ) { memset( &token, 0, sizeof( pc_token_t ) ); if ( !trap_PC_ReadToken( handle, &token ) ) { PC_SourceError( handle, "end of file inside menu\n" ); return qfalse; } if ( *token.string == '}' ) { return qtrue; } key = KeywordHash_Find( menuParseKeywordHash, token.string ); if ( !key ) { PC_SourceError( handle, "unknown menu keyword %s", token.string ); continue; } if ( !key->func( (itemDef_t*)menu, handle ) ) { PC_SourceError( handle, "couldn't parse menu keyword %s", token.string ); return qfalse; } } return qfalse; // bk001205 - LCC missing return value } /* =============== Menu_New =============== */ void Menu_New( int handle ) { menuDef_t *menu = &Menus[menuCount]; if ( menuCount < MAX_MENUS ) { Menu_Init( menu ); if ( Menu_Parse( handle, menu ) ) { Menu_PostParse( menu ); menuCount++; } } } int Menu_Count() { return menuCount; } void Menu_PaintAll() { int i; if ( captureFunc ) { captureFunc( captureData ); } for ( i = 0; i < Menu_Count(); i++ ) { Menu_Paint( &Menus[i], qfalse ); } if ( debugMode ) { vec4_t v = {1, 1, 1, 1}; DC->drawText( 5, 25, .5, v, va( "fps: %f", DC->FPS ), 0, 0, 0 ); } } void Menu_Reset() { menuCount = 0; } displayContextDef_t *Display_GetContext() { return DC; } //static float captureX; // TTimo: unused //static float captureY; // TTimo: unused void *Display_CaptureItem( int x, int y ) { int i; for ( i = 0; i < menuCount; i++ ) { // turn off focus each item // menu->items[i].window.flags &= ~WINDOW_HASFOCUS; if ( Rect_ContainsPoint( &Menus[i].window.rect, x, y ) ) { return &Menus[i]; } } return NULL; } // FIXME: qboolean Display_MouseMove( void *p, int x, int y ) { int i; menuDef_t *menu = 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; } int Display_CursorType( int x, int y ) { int i; for ( i = 0; i < menuCount; i++ ) { rectDef_t r2; r2.x = Menus[i].window.rect.x - 3; r2.y = Menus[i].window.rect.y - 3; r2.w = r2.h = 7; if ( Rect_ContainsPoint( &r2, x, y ) ) { return CURSOR_SIZER; } } return CURSOR_ARROW; } void Display_HandleKey( int key, qboolean down, int x, int y ) { menuDef_t *menu = Display_CaptureItem( x, y ); if ( menu == NULL ) { menu = Menu_GetFocused(); } if ( menu ) { Menu_HandleKey( menu, key, down ); } } static void Window_CacheContents( windowDef_t *window ) { if ( window ) { if ( window->cinematicName ) { int cin = DC->playCinematic( window->cinematicName, 0, 0, 0, 0 ); DC->stopCinematic( cin ); } } } static void Item_CacheContents( itemDef_t *item ) { if ( item ) { Window_CacheContents( &item->window ); } } static void Menu_CacheContents( menuDef_t *menu ) { if ( menu ) { int i; Window_CacheContents( &menu->window ); for ( i = 0; i < menu->itemCount; i++ ) { Item_CacheContents( menu->items[i] ); } if ( menu->soundName && *menu->soundName ) { DC->registerSound( menu->soundName ); } } } void Display_CacheAll() { int i; for ( i = 0; i < menuCount; i++ ) { Menu_CacheContents( &Menus[i] ); } } 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( Item_CorrectedTextRect( overItem ), x, y ) ) { return qtrue; } else { continue; } } else { return qtrue; } } } } } return qfalse; }