/*
===========================================================================
Wolfenstein: Enemy Territory GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Wolfenstein: Enemy Territory GPL Source Code (Wolf ET Source Code).
Wolf ET 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.
Wolf ET 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 Wolf ET Source Code. If not, see .
In addition, the Wolf: ET 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 Wolf ET 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"
#include "ui_local.h" // For CS settings/retrieval
#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;
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_MouseLeave( itemDef_t *item );
void Item_SetMouseOver( itemDef_t *item, qboolean focus );
void Item_Paint( itemDef_t *item );
void Item_RunScript( itemDef_t *item, qboolean *bAbort, 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 1536 * 1024 // Arnout: was 1024
#endif
static char memoryPool[MEM_POOL_SIZE];
static int allocPoint, outOfMemory;
void Tooltip_Initialize( itemDef_t *item ) {
item->text = NULL;
item->font = UI_FONT_COURBD_21;
item->textalignx = 3;
item->textaligny = 10;
item->textscale = .2f;
item->window.border = WINDOW_BORDER_FULL;
item->window.borderSize = 1.f;
item->window.flags &= ~WINDOW_VISIBLE;
item->window.flags |= ( WINDOW_DRAWALWAYSONTOP | WINDOW_AUTOWRAPPED );
Vector4Set( item->window.backColor, .9f, .9f, .75f, 1.f );
Vector4Set( item->window.borderColor, 0.f, 0.f, 0.f, 1.f );
Vector4Set( item->window.foreColor, 0.f, 0.f, 0.f, 1.f );
}
void Tooltip_ComputePosition( itemDef_t *item ) {
Rectangle *itemRect = &item->window.rectClient;
Rectangle *tipRect = &item->toolTipData->window.rectClient;
DC->textFont( item->toolTipData->font );
// Set positioning based on item location
tipRect->x = itemRect->x + ( itemRect->w / 3 );
tipRect->y = itemRect->y + itemRect->h + 8;
//tipRect->h = 14.0f;
//tipRect->w = DC->textWidth( item->toolTipData->text, item->toolTipData->textscale, 0 ) + 6.0f;
tipRect->h = DC->multiLineTextHeight( item->toolTipData->text, item->toolTipData->textscale, 0 ) + 9.f;
tipRect->w = DC->multiLineTextWidth( item->toolTipData->text, item->toolTipData->textscale, 0 ) + 6.f;
if ( ( tipRect->w + tipRect->x ) > 635.0f ) {
tipRect->x -= ( tipRect->w + tipRect->x ) - 635.0f;
}
item->toolTipData->parent = item->parent;
item->toolTipData->type = ITEM_TYPE_TEXT;
item->toolTipData->window.style = WINDOW_STYLE_FILLED;
item->toolTipData->window.flags |= WINDOW_VISIBLE;
}
/*
===============
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 ) {
str = str->next;
last = str;
}
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();
}
}
/*
=================
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;
}
}
/*
=================
Color_Parse
=================
*/
qboolean Color_Parse( char **p, vec4_t *c ) {
int i;
float f = 0.0f;
for ( i = 0; i < 4; i++ ) {
if ( !Float_Parse( p, &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;
}
}
/*
=================
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;
}
/*
=================
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;
}
// 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[4096];
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, 4096, va( "\"%s\"", token.string ) );
} else {
Q_strcat( script, 4096, token.string );
}
Q_strcat( script, 4096, " " );
}
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;
}
// FIXME: do right thing for right border type
if ( w->border != 0 ) {
fillRect.x += w->borderSize;
fillRect.y += w->borderSize;
fillRect.w -= 2 * w->borderSize;
fillRect.h -= 2 * w->borderSize;
}
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;
}
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;
// FIXME: do the proper thing for the right borders here?
/*if( item->window.border != 0 ) {
item->window.rect.x += item->window.borderSize;
item->window.rect.y += item->window.borderSize;
item->window.rect.w -= 2 * item->window.borderSize;
item->window.rect.h -= 2 * item->window.borderSize;
}*/
// Don't let tooltips draw off the screen.
if ( item->toolTipData ) {
Item_SetScreenCoords( item->toolTipData, x, y );
{
float val = ( item->toolTipData->window.rect.x + item->toolTipData->window.rect.w ) - 635.0f;
if ( val > 0.0f ) {
item->toolTipData->window.rectClient.x -= val;
item->toolTipData->window.rect.x -= val;
}
}
}
// 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]->window.flags & WINDOW_MOUSEOVER ) {
Item_MouseLeave( menu->items[i] );
Item_SetMouseOver( menu->items[i], qfalse );
}
if ( menu->items[i]->leaveFocus ) {
Item_RunScript( menu->items[i], NULL, 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, qboolean *bAbort, char **args ) {
const char *name = NULL;
int i;
float f = 0.0f;
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, qboolean *bAbort, 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, qboolean *bAbort, char **args ) {
const char *name = NULL;
// 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, qboolean *bAbort, 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, qboolean *bAbort, char **args ) {
const char *itemname = NULL;
const char *name = NULL;
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 Script_SetMenuItemColor( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *menuname = NULL;
const char *itemname = NULL;
const char *name = NULL;
vec4_t color;
int i;
vec4_t *out;
// expecting type of color to set and 4 args for the color
if ( String_Parse( args, &menuname ) && String_Parse( args, &itemname ) && String_Parse( args, &name ) ) {
menuDef_t *menu = Menus_FindByName( menuname );
itemDef_t *item2;
int j;
int count;
if ( !menu ) {
return;
}
count = Menu_ItemsMatchingGroup( menu, itemname );
if ( !Color_Parse( args, &color ) ) {
return;
}
for ( j = 0; j < count; j++ ) {
item2 = Menu_GetMatchingItemByNumber( menu, 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 {
if ( item->window.flags & WINDOW_MOUSEOVER ) {
Item_MouseLeave( item );
Item_SetMouseOver( item, qfalse );
}
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, NULL, menu->onClose );
}
}
void Menus_CloseByName( const char *p ) {
menuDef_t *menu = Menus_FindByName( p );
if ( menu != NULL ) {
int i;
// Gordon: make sure no edit fields are left hanging
for ( i = 0; i < menu->itemCount; i++ ) {
if ( g_editItem == menu->items[ i ] ) {
g_editingField = qfalse;
g_editItem = NULL;
}
}
menu->cursorItem = -1;
Menu_ClearFocus( menu );
Menu_RunCloseScript( menu );
menu->window.flags &= ~( WINDOW_VISIBLE | WINDOW_HASFOCUS | WINDOW_MOUSEOVER );
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 | WINDOW_MOUSEOVER );
}
}
void Script_Show( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
if ( String_Parse( args, &name ) ) {
Menu_ShowItemByName( item->parent, name, qtrue );
}
}
void Script_Hide( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
if ( String_Parse( args, &name ) ) {
Menu_ShowItemByName( item->parent, name, qfalse );
}
}
void Script_FadeIn( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
if ( String_Parse( args, &name ) ) {
Menu_FadeItemByName( item->parent, name, qfalse );
}
}
void Script_FadeOut( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
if ( String_Parse( args, &name ) ) {
Menu_FadeItemByName( item->parent, name, qtrue );
}
}
void Script_Open( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
if ( String_Parse( args, &name ) ) {
Menus_OpenByName( name );
}
}
void Menu_FadeMenuByName( const char *p, qboolean *bAbort, qboolean fadeOut ) {
itemDef_t *item;
int i;
menuDef_t *menu = Menus_FindByName( p );
if ( menu ) {
for ( i = 0; i < menu->itemCount; i++ ) {
item = menu->items[i];
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;
}
}
}
}
void Script_FadeInMenu( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
if ( String_Parse( args, &name ) ) {
Menu_FadeMenuByName( name, bAbort, qfalse );
}
}
void Script_FadeOutMenu( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
if ( String_Parse( args, &name ) ) {
Menu_FadeMenuByName( name, bAbort, qtrue );
}
}
// DHM - Nerve
void Script_ConditionalOpen( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *cvar = NULL;
const char *name1 = NULL;
const char *name2 = NULL;
float val;
char buff[1024];
int testtype; // 0: check val not 0
// 1: check cvar not empty
if ( String_Parse( args, &cvar ) && Int_Parse( args, &testtype ) && String_Parse( args, &name1 ) && String_Parse( args, &name2 ) ) {
switch ( testtype ) {
default:
case 0:
val = DC->getCVarValue( cvar );
if ( val == 0.f ) {
Menus_OpenByName( name2 );
} else {
Menus_OpenByName( name1 );
}
break;
case 1:
DC->getCVarString( cvar, buff, sizeof( buff ) );
if ( !buff[0] ) {
Menus_OpenByName( name2 );
} else {
Menus_OpenByName( name1 );
}
break;
}
}
}
void Script_ConditionalScript( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *cvar;
const char *script1;
const char *script2;
const char *token;
float val;
char buff[1024];
int testtype; // 0: check val not 0
// 1: check cvar not empty
int testval;
if ( String_Parse( args, &cvar ) &&
Int_Parse( args, &testtype ) &&
String_Parse( args, &token ) && ( token && *token == '(' ) &&
String_Parse( args, &script1 ) &&
String_Parse( args, &token ) && ( token && *token == ')' ) &&
String_Parse( args, &token ) && ( token && *token == '(' ) &&
String_Parse( args, &script2 ) &&
String_Parse( args, &token ) && ( token && *token == ')' ) ) {
switch ( testtype ) {
default:
case 0:
val = DC->getCVarValue( cvar );
if ( val == 0.f ) {
Item_RunScript( item, bAbort, script2 );
} else {
Item_RunScript( item, bAbort, script1 );
}
break;
case 1:
DC->getCVarString( cvar, buff, sizeof( buff ) );
if ( !buff[0] ) {
Item_RunScript( item, bAbort, script2 );
} else {
Item_RunScript( item, bAbort, script1 );
}
break;
case 3:
if ( Int_Parse( args, &testval ) ) {
val = DC->getCVarValue( cvar );
if ( val != testval ) {
Item_RunScript( item, bAbort, script2 );
} else {
Item_RunScript( item, bAbort, script1 );
}
}
break;
case 2:
// special tests
if ( !Q_stricmp( cvar, "UIProfileIsActiveProfile" ) ) {
char ui_profileStr[256];
char cl_profileStr[256];
DC->getCVarString( "ui_profile", ui_profileStr, sizeof( ui_profileStr ) );
Q_CleanStr( ui_profileStr );
Q_CleanDirName( ui_profileStr );
DC->getCVarString( "cl_profile", cl_profileStr, sizeof( cl_profileStr ) );
if ( !Q_stricmp( ui_profileStr, cl_profileStr ) ) {
Item_RunScript( item, bAbort, script1 );
} else {
Item_RunScript( item, bAbort, script2 );
}
} else if ( !Q_stricmp( cvar, "UIProfileValidName" ) ) {
char ui_profileStr[256];
char ui_profileCleanedStr[256];
DC->getCVarString( "ui_profile", ui_profileStr, sizeof( ui_profileStr ) );
Q_strncpyz( ui_profileCleanedStr, ui_profileStr, sizeof( ui_profileCleanedStr ) );
Q_CleanStr( ui_profileCleanedStr );
Q_CleanDirName( ui_profileCleanedStr );
if ( *ui_profileStr && *ui_profileCleanedStr ) {
Item_RunScript( item, bAbort, script1 );
} else {
Item_RunScript( item, bAbort, script2 );
}
} else if ( !Q_stricmp( cvar, "UIProfileAlreadyExists" ) ) {
char ui_profileCleanedStr[256];
qboolean alreadyExists = qfalse;
fileHandle_t f;
DC->getCVarString( "ui_profile", ui_profileCleanedStr, sizeof( ui_profileCleanedStr ) );
Q_CleanStr( ui_profileCleanedStr );
Q_CleanDirName( ui_profileCleanedStr );
if ( trap_FS_FOpenFile( va( "profiles/%s/profile.dat", ui_profileCleanedStr ), &f, FS_READ ) >= 0 ) {
alreadyExists = qtrue;
trap_FS_FCloseFile( f );
}
if ( alreadyExists ) {
Item_RunScript( item, bAbort, script1 );
} else {
Item_RunScript( item, bAbort, script2 );
}
} else if ( !Q_stricmp( cvar, "UIProfileAlreadyExists_Rename" ) ) {
char ui_profileCleanedStr[256];
qboolean alreadyExists = qfalse;
fileHandle_t f;
DC->getCVarString( "ui_profile_renameto", ui_profileCleanedStr, sizeof( ui_profileCleanedStr ) );
Q_CleanStr( ui_profileCleanedStr );
Q_CleanDirName( ui_profileCleanedStr );
if ( trap_FS_FOpenFile( va( "profiles/%s/profile.dat", ui_profileCleanedStr ), &f, FS_READ ) >= 0 ) {
alreadyExists = qtrue;
trap_FS_FCloseFile( f );
}
if ( alreadyExists ) {
Item_RunScript( item, bAbort, script1 );
} else {
Item_RunScript( item, bAbort, script2 );
}
} else if ( !Q_stricmp( cvar, "ReadyToCreateProfile" ) ) {
char ui_profileStr[256], ui_profileCleanedStr[256];
int ui_rate;
qboolean alreadyExists = qfalse;
fileHandle_t f;
DC->getCVarString( "ui_profile", ui_profileStr, sizeof( ui_profileStr ) );
Q_strncpyz( ui_profileCleanedStr, ui_profileStr, sizeof( ui_profileCleanedStr ) );
Q_CleanStr( ui_profileCleanedStr );
Q_CleanDirName( ui_profileCleanedStr );
if ( trap_FS_FOpenFile( va( "profiles/%s/profile.dat", ui_profileCleanedStr ), &f, FS_READ ) >= 0 ) {
alreadyExists = qtrue;
trap_FS_FCloseFile( f );
}
ui_rate = (int)DC->getCVarValue( "ui_rate" );
if ( !alreadyExists && *ui_profileStr && ui_rate > 0 ) {
Item_RunScript( item, bAbort, script1 );
} else {
Item_RunScript( item, bAbort, script2 );
}
} else if ( !Q_stricmp( cvar, "vidrestartIsRequired" ) ) {
int ui_r_mode = DC->getCVarValue( "ui_r_mode" );
int ui_r_colorbits = DC->getCVarValue( "ui_r_colorbits" );
int ui_r_fullscreen = DC->getCVarValue( "ui_r_fullscreen" );
int ui_r_texturebits = DC->getCVarValue( "ui_r_texturebits" );
int ui_r_depthbits = DC->getCVarValue( "ui_r_depthbits" );
int ui_r_ext_compressed_textures = DC->getCVarValue( "ui_r_ext_compressed_textures" );
int ui_r_allowextensions = DC->getCVarValue( "ui_r_allowextensions" );
int ui_s_khz = DC->getCVarValue( "ui_s_khz" );
int ui_r_detailtextures = DC->getCVarValue( "ui_r_detailtextures" );
int ui_r_subdivisions = DC->getCVarValue( "ui_r_subdivisions" );
char ui_r_texturemode[MAX_CVAR_VALUE_STRING];
int r_mode = DC->getCVarValue( "r_mode" );
int r_colorbits = DC->getCVarValue( "r_colorbits" );
int r_fullscreen = DC->getCVarValue( "r_fullscreen" );
int r_texturebits = DC->getCVarValue( "r_texturebits" );
int r_depthbits = DC->getCVarValue( "r_depthbits" );
int r_ext_compressed_textures = DC->getCVarValue( "r_ext_compressed_textures" );
int r_allowextensions = DC->getCVarValue( "r_allowextensions" );
int s_khz = DC->getCVarValue( "s_khz" );
int r_detailtextures = DC->getCVarValue( "r_detailtextures" );
int r_subdivisions = DC->getCVarValue( "r_subdivisions" );
char r_texturemode[MAX_CVAR_VALUE_STRING];
trap_Cvar_VariableStringBuffer( "ui_r_texturemode", ui_r_texturemode, sizeof( ui_r_texturemode ) );
trap_Cvar_VariableStringBuffer( "r_texturemode", r_texturemode, sizeof( r_texturemode ) );
if ( ui_r_subdivisions != r_subdivisions ||
ui_r_mode != r_mode ||
ui_r_colorbits != r_colorbits ||
ui_r_fullscreen != r_fullscreen ||
ui_r_texturebits != r_texturebits ||
ui_r_depthbits != r_depthbits ||
ui_r_ext_compressed_textures != r_ext_compressed_textures ||
ui_r_allowextensions != r_allowextensions ||
ui_s_khz != s_khz ||
ui_r_detailtextures != r_detailtextures ||
Q_stricmp( r_texturemode, ui_r_texturemode ) ) {
Item_RunScript( item, bAbort, script1 );
} else {
Item_RunScript( item, bAbort, script2 );
}
/*} else if( !Q_stricmpn( cvar, "voteflags", 9 ) ) {
char info[MAX_INFO_STRING];
int voteflags = atoi(cvar + 9);
trap_Cvar_VariableStringBuffer( "cg_ui_voteFlags", info, sizeof(info) );
if( (atoi(info) & item->voteFlag) != item->voteFlag ) {
Item_RunScript( item, bAbort, script1 );
} else {
Item_RunScript( item, bAbort, script2 );
}*/
#ifndef CGAMEDLL
} else if ( !Q_stricmpn( cvar, "serversort_", 11 ) ) {
int sorttype = atoi( cvar + 11 );
if ( sorttype != uiInfo.serverStatus.sortKey ) {
Item_RunScript( item, bAbort, script2 );
} else {
Item_RunScript( item, bAbort, script1 );
}
} else if ( !Q_stricmp( cvar, "ValidReplaySelected" ) ) {
if ( uiInfo.demoIndex >= 0 && uiInfo.demoIndex < uiInfo.demoCount ) {
Item_RunScript( item, bAbort, script1 );
} else {
Item_RunScript( item, bAbort, script2 );
}
#endif // !CGAMEDLL
} else if ( !Q_stricmp( cvar, "ROldModeCheck" ) ) {
char r_oldModeStr[256];
int r_oldMode;
int r_mode = DC->getCVarValue( "r_mode" );
DC->getCVarString( "r_oldMode", r_oldModeStr, sizeof( r_oldModeStr ) );
r_oldMode = atoi( r_oldModeStr );
if ( *r_oldModeStr && r_oldMode != r_mode ) {
Item_RunScript( item, bAbort, script1 );
} else {
if ( r_oldMode == r_mode ) {
trap_Cvar_Set( "r_oldMode", "" ); // clear it
}
Item_RunScript( item, bAbort, script2 );
}
}
break;
}
}
}
// DHM - Nerve
void Script_Close( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
if ( String_Parse( args, &name ) ) {
Menus_CloseByName( name );
}
}
void Script_CloseAll( itemDef_t *item, qboolean *bAbort, char **args ) {
Menus_CloseAll();
}
void Script_CloseAllOtherMenus( itemDef_t *item, qboolean *bAbort, char **args ) {
int i;
for ( i = 0; i < menuCount; i++ ) {
if ( &Menus[i] == item->parent ) {
continue;
}
Menu_RunCloseScript( &Menus[i] );
Menus[i].window.flags &= ~( WINDOW_HASFOCUS | WINDOW_VISIBLE | WINDOW_MOUSEOVER );
}
}
/*
==============
Script_Clipboard
==============
*/
void Script_Clipboard( itemDef_t *item, qboolean *bAbort, char **args ) {
}
/*
==============
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, qboolean *bAbort, char **args ) {
}
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, qboolean *bAbort, char **args ) {
const char *name = NULL;
rectDef_t rectFrom, rectTo;
int time = 0;
float amt = 0.0f;
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, qboolean *bAbort, char **args ) {
const char *name = NULL;
float cx = 0.0f, cy = 0.0f, x = 0.0f, y = 0.0f;
int time = 0;
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, qboolean *bAbort, char **args ) {
const char *name = NULL;
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, NULL, focusItem->onFocus );
}
if ( DC->Assets.itemFocusSound ) {
DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
}
}
}
}
void Script_ClearFocus( itemDef_t *item, qboolean *bAbort, char **args ) {
Menu_ClearFocus( item->parent );
}
void Script_SetPlayerModel( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
if ( String_Parse( args, &name ) ) {
DC->setCVar( "team_model", name );
}
}
void Script_SetPlayerHead( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
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, qboolean *bAbort, char **args ) {
const char *cvar;
if ( String_Parse( args, &cvar ) ) {
DC->setCVar( cvar, "" );
}
}
void Script_SetCvar( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *cvar = NULL, *val = NULL;
if ( String_Parse( args, &cvar ) && String_Parse( args, &val ) ) {
DC->setCVar( cvar, val );
}
}
void Script_CopyCvar( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *cvar_src = NULL, *cvar_dst = NULL;
if ( String_Parse( args, &cvar_src ) && String_Parse( args, &cvar_dst ) ) {
char buff[256];
DC->getCVarString( cvar_src, buff, 256 );
DC->setCVar( cvar_dst, buff );
}
}
void Script_Exec( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *val = NULL;
if ( String_Parse( args, &val ) ) {
DC->executeText( EXEC_APPEND, va( "%s ; ", val ) );
}
}
void Script_ExecNOW( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *val = NULL;
if ( String_Parse( args, &val ) ) {
DC->executeText( EXEC_NOW, va( "%s ; ", val ) );
}
}
void Script_Play( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *val = NULL;
if ( String_Parse( args, &val ) ) {
DC->startLocalSound( DC->registerSound( val, qfalse ), CHAN_LOCAL_SOUND ); // all sounds are not 3d
}
}
void Script_playLooped( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *val = NULL;
if ( String_Parse( args, &val ) ) {
DC->stopBackgroundTrack();
DC->startBackgroundTrack( val, val, 0 );
}
}
// NERVE - SMF
void Script_AddListItem( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *itemname = NULL, *val = NULL, *name = NULL;
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, qboolean *bAbort, char **args ) {
DC->checkAutoUpdate();
}
void Script_GetAutoUpdate( itemDef_t *item, qboolean *bAbort, char **args ) {
DC->getAutoUpdate();
}
// DHM - Nerve
void Script_SetMenuFocus( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name;
if ( String_Parse( args, &name ) ) {
menuDef_t *focusMenu = Menus_FindByName( name );
if ( focusMenu && !( focusMenu->window.flags & WINDOW_HASFOCUS ) ) {
Menu_ClearFocus( item->parent );
focusMenu->window.flags |= WINDOW_HASFOCUS;
}
}
}
qboolean FileExists( char *filename ) {
fileHandle_t f;
if ( trap_FS_FOpenFile( filename, &f, FS_READ ) < 0 ) {
trap_FS_FCloseFile( f );
return qfalse;
} else {
trap_FS_FCloseFile( f );
return qtrue;
}
}
qboolean Script_CheckProfile( char *profile_path ) {
fileHandle_t f;
char f_data[32];
int f_pid;
char com_pid[256];
int pid;
if ( trap_FS_FOpenFile( profile_path, &f, FS_READ ) < 0 ) {
//no profile found, we're ok
return qtrue;
}
trap_FS_Read( &f_data, sizeof( f_data ) - 1, f );
DC->getCVarString( "com_pid", com_pid, sizeof( com_pid ) );
pid = atoi( com_pid );
f_pid = atoi( f_data );
if ( f_pid != pid ) {
//pid doesn't match
trap_FS_FCloseFile( f );
return qfalse;
}
//we're all ok
trap_FS_FCloseFile( f );
return qtrue;
}
qboolean Script_WriteProfile( char *profile_path ) {
fileHandle_t f;
char com_pid[256];
if ( FileExists( profile_path ) ) {
trap_FS_Delete( profile_path );
}
if ( trap_FS_FOpenFile( profile_path, &f, FS_WRITE ) < 0 ) {
Com_Printf( "Script_WriteProfile: Can't write %s.\n", profile_path );
return qfalse;
}
if ( f < 0 ) {
Com_Printf( "Script_WriteProfile: Can't write %s.\n", profile_path );
return qfalse;
}
DC->getCVarString( "com_pid", com_pid, sizeof( com_pid ) );
trap_FS_Write( com_pid, strlen( com_pid ), f );
trap_FS_FCloseFile( f );
return qtrue;
}
void Script_ExecWolfConfig( itemDef_t *item, qboolean *bAbort, char **args ) {
char cl_profileStr[256];
int useprofile = 1;
if ( Int_Parse( args, &useprofile ) ) {
DC->getCVarString( "cl_profile", cl_profileStr, sizeof( cl_profileStr ) );
if ( useprofile && cl_profileStr[0] ) {
if ( !Script_CheckProfile( va( "profiles/%s/profile.pid", cl_profileStr ) ) ) {
#ifndef _DEBUG
Com_Printf( "^3WARNING: profile.pid found for profile '%s' - not executing %s\n", cl_profileStr, CONFIG_NAME );
#else
DC->executeText( EXEC_NOW, va( "exec profiles/%s/%s\n", cl_profileStr, CONFIG_NAME ) );
#endif // _DEBUG
} else {
DC->executeText( EXEC_NOW, va( "exec profiles/%s/%s\n", cl_profileStr, CONFIG_NAME ) );
if ( !Script_WriteProfile( va( "profiles/%s/profile.pid", cl_profileStr ) ) ) {
Com_Printf( "^3WARNING: couldn't write profiles/%s/profile.pid\n", cl_profileStr );
}
}
} else {
DC->executeText( EXEC_NOW, va( "exec %s\n", CONFIG_NAME ) );
}
}
}
void Script_SetEditFocus( itemDef_t *item, qboolean *bAbort, char **args ) {
const char *name = NULL;
itemDef_t *editItem;
if ( String_Parse( args, &name ) ) {
editItem = Menu_FindItemByName( item->parent, name );
if ( editItem && ( editItem->type == ITEM_TYPE_EDITFIELD || editItem->type == ITEM_TYPE_NUMERICFIELD ) ) {
editFieldDef_t *editPtr = (editFieldDef_t*)editItem->typeData;
Menu_ClearFocus( item->parent );
editItem->window.flags |= WINDOW_HASFOCUS;
if ( editItem->onFocus ) {
Item_RunScript( editItem, NULL, editItem->onFocus );
}
if ( DC->Assets.itemFocusSound ) {
DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
}
// NERVE - SMF - reset scroll offset so we can see what we're editing
if ( editPtr ) {
editPtr->paintOffset = 0;
}
editItem->cursorPos = 0;
g_editingField = qtrue;
g_editItem = editItem;
// the stupidest idea ever, let's just override the console, every ui element, user choice, etc
// nuking this
//% DC->setOverstrikeMode(qtrue);
}
}
}
void Script_Abort( itemDef_t *item, qboolean *bAbort, char **args ) {
*bAbort = qtrue;
}
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
{"fadeinmenu", &Script_FadeInMenu}, // menu
{"fadeoutmenu", &Script_FadeOutMenu}, // menu
{"conditionalopen", &Script_ConditionalOpen}, // DHM - Nerve:: cvar menu menu
// opens first menu if cvar is true[non-zero], second if false
{"conditionalscript", &Script_ConditionalScript}, // as conditonalopen, but then executes scripts
{"close", &Script_Close}, // menu
{"closeall", &Script_CloseAll},
{"closeallothermenus", &Script_CloseAllOtherMenus},
{"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
{"setmenuitemcolor", &Script_SetMenuItemColor}, // group/name
{"setteamcolor", &Script_SetTeamColor}, // sets this background color to team color
{"setfocus", &Script_SetFocus}, // sets this background color to team color
{"clearfocus", &Script_ClearFocus},
{"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},
{"copycvar", &Script_CopyCvar},
{"exec", &Script_Exec}, // group/name
{"execnow", &Script_ExecNOW}, // 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
{"setmenufocus", &Script_SetMenuFocus}, // focus menu
{"execwolfconfig", &Script_ExecWolfConfig}, // executes etconfig.cfg
{"setEditFocus", &Script_SetEditFocus },
{"abort", &Script_Abort },
};
int scriptCommandCount = sizeof( commandList ) / sizeof( commandDef_t );
void Item_RunScript( itemDef_t *item, qboolean *bAbort, const char *s ) {
char script[4096], *p;
int i;
qboolean bRan;
qboolean b_localAbort = qfalse;
memset( script, 0, sizeof( script ) );
if ( item && s && s[0] ) {
Q_strcat( script, 4096, s );
p = script;
while ( 1 ) {
const char *command = NULL;
// 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, &b_localAbort, &p ) );
bRan = qtrue;
if ( b_localAbort ) {
if ( bAbort ) {
*bAbort = b_localAbort;
}
return;
}
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 = NULL;
// 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;
}
// OSP - display if we poll on a server toggle setting
// We want *current* settings, so this is a bit of a perf hit,
// but this is only during UI display
qboolean Item_SettingShow( itemDef_t *item, qboolean fVoteTest ) {
char info[MAX_INFO_STRING];
if ( fVoteTest ) {
trap_Cvar_VariableStringBuffer( "cg_ui_voteFlags", info, sizeof( info ) );
return( ( atoi( info ) & item->voteFlag ) != item->voteFlag );
}
DC->getConfigString( CS_SERVERTOGGLES, info, sizeof( info ) );
if ( item->settingFlags & SVS_ENABLED_SHOW ) {
return( atoi( info ) & item->settingTest );
}
if ( item->settingFlags & SVS_DISABLED_SHOW ) {
return( !( atoi( info ) & item->settingTest ) );
}
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;
}
// OSP
if ( ( item->settingFlags & ( SVS_ENABLED_SHOW | SVS_DISABLED_SHOW ) ) && !Item_SettingShow( item, qfalse ) ) {
return( qfalse );
}
if ( item->voteFlag != 0 && !Item_SettingShow( item, qtrue ) ) {
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, NULL, oldFocus->onFocus );
}
}
}
} else {
item->window.flags |= WINDOW_HASFOCUS;
if ( item->onFocus ) {
Item_RunScript( item, NULL, 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 - (int)( item->window.rect.w / listPtr->elementWidth );
} else {
max = count - (int)( item->window.rect.h / listPtr->elementHeight );
}
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.y = item->window.rect.y;
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);
thumbstart = Item_ListBox_ThumbDrawPosition( 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;
}
// hack hack
r.x = item->window.rect.x;
r.w = item->window.rect.w;
if ( Rect_ContainsPoint( &r, x, y ) ) {
return WINDOW_LB_SOMEWHERE;
}
} 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);
thumbstart = Item_ListBox_ThumbDrawPosition( 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;
}
// hack hack
r.y = item->window.rect.y;
r.h = item->window.rect.h;
if ( Rect_ContainsPoint( &r, x, y ) ) {
return WINDOW_LB_SOMEWHERE;
}
}
return 0;
}
void Item_ListBox_MouseEnter( itemDef_t *item, float x, float y, qboolean click ) {
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 | WINDOW_LB_SOMEWHERE );
item->window.flags |= Item_ListBox_OverLB( item, x, y );
if ( click ) {
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 | WINDOW_LB_SOMEWHERE ) ) ) {
// 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 | WINDOW_LB_SOMEWHERE ) ) ) {
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;
}
// OSP - server settings too .. (mostly for callvote)
if ( ( item->settingFlags & ( SVS_ENABLED_SHOW | SVS_DISABLED_SHOW ) ) && !Item_SettingShow( item, qfalse ) ) {
return;
}
if ( item->voteFlag != 0 && !Item_SettingShow( item, qtrue ) ) {
return;
}
if ( Rect_ContainsPoint( &r, x, y ) ) {
if ( !( item->window.flags & WINDOW_MOUSEOVERTEXT ) ) {
Item_RunScript( item, NULL, item->mouseEnterText );
item->window.flags |= WINDOW_MOUSEOVERTEXT;
}
if ( !( item->window.flags & WINDOW_MOUSEOVER ) ) {
Item_RunScript( item, NULL, 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, NULL, item->mouseExitText );
item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
}
if ( !( item->window.flags & WINDOW_MOUSEOVER ) ) {
Item_RunScript( item, NULL, item->mouseEnter );
item->window.flags |= WINDOW_MOUSEOVER;
}
if ( item->type == ITEM_TYPE_LISTBOX ) {
Item_ListBox_MouseEnter( item, x, y, qfalse );
}
}
}
}
void Item_MouseLeave( itemDef_t *item ) {
if ( item ) {
if ( item->window.flags & WINDOW_MOUSEOVERTEXT ) {
Item_RunScript( item, NULL, item->mouseExitText );
item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
}
Item_RunScript( item, NULL, 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 || key == K_MWHEELUP ) {
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 || key == K_MWHEELDOWN ) {
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 ) {
Item_ListBox_MouseEnter( item, DC->cursorx, DC->cursory, qtrue );
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 if ( item->window.flags & WINDOW_LB_SOMEWHERE ) {
// do nowt
} else {
// select an item
// Arnout: can't select something that doesn't exist
if ( listPtr->cursorPos >= count ) {
listPtr->cursorPos = count - 1;
}
if ( item->cursorPos == listPtr->cursorPos &&
DC->realTime < lastListBoxClickTime && listPtr->doubleClick ) {
Item_RunScript( item, NULL, listPtr->doubleClick );
}
lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
if ( item->cursorPos != listPtr->cursorPos ) {
item->cursorPos = listPtr->cursorPos;
DC->feederSelection( item->special, item->cursorPos );
}
if ( key == K_MOUSE1 ) {
DC->feederSelectionClick( item );
}
if ( key == K_MOUSE2 && listPtr->contextMenu ) {
menuDef_t* menu = Menus_FindByName( listPtr->contextMenu );
if ( menu ) {
menu->window.rect.x = DC->cursorx;
menu->window.rect.y = DC->cursory;
Menu_UpdatePosition( menu );
Menus_ActivateByName( listPtr->contextMenu, qtrue );
}
}
}
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_CheckBox_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 ) ) {
if ( item->type == ITEM_TYPE_TRICHECKBOX ) {
int curvalue = DC->getCVarValue( item->cvar ) + 1;
if ( curvalue > 2 ) {
curvalue = 0;
}
DC->setCVar( item->cvar, va( "%i", curvalue ) );
} else {
DC->setCVar( item->cvar, va( "%i", !DC->getCVarValue( item->cvar ) ) );
}
}
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];
}
}
}
}
if ( multiPtr->undefinedStr ) {
return multiPtr->undefinedStr;
} else {
return( ( multiPtr->count == 0 ) ? "None Defined" : "Custom" );
}
}
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 );
int max = Item_Multi_CountSettings( item );
if ( key == K_MOUSE2 ) {
current--;
} else {
current++;
}
if ( current < 0 ) {
current = max - 1;
} else if ( current >= max ) {
current = 0;
}
if ( multiPtr->strDef ) {
DC->setCVar( item->cvar, multiPtr->cvarStr[current] );
} else {
float value = multiPtr->cvarValue[current];
if ( ( (float)( (int) value ) ) == value ) {
DC->setCVar( item->cvar, va( "%i", (int) value ) );
} else {
DC->setCVar( item->cvar, va( "%f", value ) );
}
}
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;
}
// Gordon: make sure our cursorpos doesn't go oob, windows doesn't like negative memory copy operations :)
if ( item->cursorPos < 0 || item->cursorPos > len ) {
item->cursorPos = 0;
}
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--;
}
buff[len] = '\0';
}
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' ) && key != '.' ) {
return qfalse;
}
}
if ( DC->getOverstrikeMode && !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 );
buff[len] = '\0';
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, NULL, 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
// Arnout: clear doubleclicktime though!
lastListBoxClickTime = 0;
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 ) {
int realKey;
realKey = key;
if ( realKey & K_CHAR_FLAG ) {
realKey &= ~K_CHAR_FLAG;
}
if ( itemCapture ) {
Item_StopCapture( itemCapture );
itemCapture = NULL;
captureFunc = NULL;
captureData = NULL;
} else {
// bk001206 - parentheses
if ( down && ( realKey == K_MOUSE1 || realKey == K_MOUSE2 || realKey == K_MOUSE3 ) ) {
Item_StartCapture( item, key );
}
}
if ( !down ) {
return qfalse;
}
if ( realKey == K_ESCAPE && item->onEsc ) {
Item_RunScript( item, NULL, item->onEsc );
return qtrue;
}
if ( realKey == K_ENTER && item->onEnter ) {
Item_RunScript( item, NULL, item->onEnter );
return qtrue;
}
switch ( item->type ) {
case ITEM_TYPE_BUTTON:
return qfalse;
break;
case ITEM_TYPE_RADIOBUTTON:
return qfalse;
break;
case ITEM_TYPE_CHECKBOX:
case ITEM_TYPE_TRICHECKBOX:
return Item_CheckBox_HandleKey( item, key );
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, NULL, 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;
if ( !menu ) {
return NULL;
}
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, NULL, 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();
}*/
void Menus_Activate( menuDef_t *menu ) {
int i;
for ( i = 0; i < menuCount; i++ ) {
Menus[i].window.flags &= ~( WINDOW_HASFOCUS | WINDOW_MOUSEOVER );
}
menu->window.flags |= ( WINDOW_HASFOCUS | WINDOW_VISIBLE );
if ( menu->onOpen ) {
itemDef_t item;
item.parent = menu;
Item_RunScript( &item, NULL, menu->onOpen );
}
// ydnar: set open time (note dc time may be 0, in which case refresh code sets this)
menu->openTime = DC->realTime;
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, 0 );
}
Display_CloseCinematics();
}
qboolean Menus_CaptureFuncActive( void ) {
if ( captureFunc ) {
return qtrue;
} else {
return qfalse;
}
}
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 | WINDOW_MOUSEOVER );
}
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 | WINDOW_MOUSEOVER);
menu->window.flags &= ~( WINDOW_HASFOCUS | WINDOW_MOUSEOVER );
Menus[i].window.flags |= ( WINDOW_HASFOCUS | WINDOW_VISIBLE );
// Menus_Activate(&Menus[i]);
Menu_HandleMouseMove( &Menus[i], DC->cursorx, DC->cursory );
Menu_HandleKey( &Menus[i], key, down );
}
}
if ( Display_VisibleMenuCount() == 0 ) {
if ( DC->Pause ) {
DC->Pause( qfalse );
}
}
Display_CloseCinematics();
}
}
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;
}
// ydnar: enter key handling for the window supercedes item enter handling
if ( down && ( ( key == K_ENTER || key == K_KP_ENTER ) && menu->onEnter ) ) {
itemDef_t it;
it.parent = menu;
Item_RunScript( &it, NULL, menu->onEnter );
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;
}
// START - TAT 9/16/2002
// we need to check and see if we're supposed to loop through the items to find the key press func
if ( !menu->itemHotkeyMode ) {
// END - TAT 9/16/2002
if ( key > 0 && key <= 255 && menu->onKey[key] ) {
itemDef_t it;
it.parent = menu;
Item_RunScript( &it, NULL, menu->onKey[key] );
return;
}
// START - TAT 9/16/2002
} else if ( key > 0 && key <= 255 ) {
itemDef_t* it;
// we're using the item hotkey mode, so we want to loop through all the items in this menu
for ( i = 0; i < menu->itemCount; i++ )
{
it = menu->items[i];
// is the hotkey for this the same as what was pressed?
if ( it->hotkey == key
// and is this item visible?
&& Item_EnableShowViaCvar( it, CVAR_SHOW ) ) {
Item_RunScript( it, NULL, it->onKey );
return;
}
}
}
// END - TAT 9/16/2002
// 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, NULL, menu->onESC );
}
break;
case K_ENTER:
case K_KP_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;
} else {
Item_Action( item );
}
}
break;
case K_TAB:
if ( DC->keyIsDown( K_SHIFT ) ) {
Menu_SetPrevCursorItem( menu );
} else {
Menu_SetNextCursorItem( menu );
}
break;
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;
// ydnar: fixme, make it set the insertion point correctly
// 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;
// see elsewhere for venomous comment about this particular piece of "functionality"
//% 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;
}
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 ||
item->type == ITEM_TYPE_TIMEOUT_COUNTER ) { // ydnar
//% int originalWidth = DC->textWidth(item->text, item->textscale, 0);
int originalWidth = DC->textWidth( textPtr, 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 && item->window.flags & WINDOW_FOCUSPULSE ) {
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;
qboolean hasWhitespace;
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;
hasWhitespace = qfalse;
p = textPtr;
while ( p ) {
textWidth = DC->textWidth( buff, item->textscale, 0 );
if ( *p == ' ' || *p == '\t' || *p == '\n' || *p == '\0' ) {
newLine = len;
newLinePtr = p + 1;
newLineWidth = textWidth;
hasWhitespace = qtrue;
} else if ( !hasWhitespace && textWidth > item->window.rect.w ) {
newLine = len;
newLinePtr = p;
newLineWidth = textWidth;
}
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;
hasWhitespace = qfalse;
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;
int seconds;
menuDef_t *menu = (menuDef_t*) item->parent;
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 & WINDOW_TEXTASINT ) {
COM_StripExtension( text, text );
item->textRect.w = 0; // force recalculation
} else if ( item->window.flags & WINDOW_TEXTASFLOAT ) {
char *s = va( "%.2f", atof( text ) );
Q_strncpyz( text, s, sizeof( text ) );
item->textRect.w = 0; // force recalculation
}
textPtr = text;
}
} else {
textPtr = item->text;
}
// ydnar: handle counters
if ( item->type == ITEM_TYPE_TIMEOUT_COUNTER && menu != NULL && menu->openTime > 0 ) {
// calc seconds remaining
seconds = ( menu->openTime + menu->timeout - DC->realTime + 999 ) / 1000;
// build string
if ( seconds <= 2 ) {
//Com_sprintf( text, 255, "^1%d", seconds );
Com_sprintf( text, 255, item->text, va( "^1%d^*", seconds ) );
} else {
//Com_sprintf( text, 255, "%d", seconds );
Com_sprintf( text, 255, item->text, va( "%d", seconds ) );
}
// set ptr
textPtr = 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 && item->window.flags & WINDOW_FOCUSPULSE ) {
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_CheckBox_Paint( itemDef_t *item ) {
vec4_t newColor, lowLight;
float value;
menuDef_t *parent = (menuDef_t*)item->parent;
qboolean hasMultiText = qfalse;
multiDef_t *multiPtr = (multiDef_t*)item->typeData;
value = ( item->cvar ) ? DC->getCVarValue( item->cvar ) : 0;
if ( item->window.flags & WINDOW_HASFOCUS && item->window.flags & WINDOW_FOCUSPULSE ) {
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 ( multiPtr && multiPtr->count ) {
hasMultiText = qtrue;
}
if ( item->text ) {
Item_Text_Paint( item );
if ( item->type == ITEM_TYPE_TRICHECKBOX && value == 2 ) {
DC->drawHandlePic( item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.h, item->window.rect.h, DC->Assets.checkboxCheckNo );
} else if ( value ) {
DC->drawHandlePic( item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.h, item->window.rect.h, DC->Assets.checkboxCheck );
} else {
DC->drawHandlePic( item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.h, item->window.rect.h, DC->Assets.checkboxCheckNot );
}
if ( hasMultiText ) {
vec4_t colour;
Item_TextColor( item, &colour );
DC->drawText( item->textRect.x + item->textRect.w + 8 + item->window.rect.h + 4, item->textRect.y, item->textscale,
colour, Item_Multi_Setting( item ), 0, 0, item->textStyle );
}
} else {
if ( item->type == ITEM_TYPE_TRICHECKBOX && value == 2 ) {
DC->drawHandlePic( item->window.rect.x, item->window.rect.y, item->window.rect.h, item->window.rect.h, DC->Assets.checkboxCheckNo );
} else if ( value ) {
DC->drawHandlePic( item->window.rect.x, item->window.rect.y, item->window.rect.h, item->window.rect.h, DC->Assets.checkboxCheck );
} else {
DC->drawHandlePic( item->window.rect.x, item->window.rect.y, item->window.rect.h, item->window.rect.h, DC->Assets.checkboxCheckNot );
}
if ( hasMultiText ) {
vec4_t colour;
Item_TextColor( item, &colour );
DC->drawText( item->window.rect.x + item->window.rect.h + 4, item->window.rect.y + item->textaligny, item->textscale,
colour, Item_Multi_Setting( item ), 0, 0, 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 && item->window.flags & WINDOW_FOCUSPULSE ) {
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 && item->window.flags & WINDOW_FOCUSPULSE ) {
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_right;
int defaultbind2_right;
int defaultbind1_left;
int defaultbind2_left;
int bind1;
int bind2;
} bind_t;
typedef struct
{
char* name;
float defaultvalue;
float value;
} configcvar_t;
// Gordon: These MUST be all lowercase now
static bind_t g_bindings[] = {
{ "+forward", 'w', -1, K_UPARROW, -1, -1, -1 },
{ "+back", 's', -1, K_DOWNARROW, -1, -1, -1 },
{ "+moveleft", 'a', -1, K_LEFTARROW, -1, -1, -1 },
{ "+moveright", 'd', -1, K_RIGHTARROW, -1, -1, -1 },
{ "+moveup", K_SPACE, -1, K_KP_INS, -1, -1, -1 },
{ "+movedown", 'c', -1, K_CTRL, -1, -1, -1 },
{ "+leanright", 'e', -1, K_PGDN, -1, -1, -1 },
{ "+leanleft", 'q', -1, K_DEL, -1, -1, -1 },
{ "+prone", 'x', -1, K_SHIFT, -1, -1, -1 },
{ "+attack", K_MOUSE1, -1, K_MOUSE1, -1, -1, -1 },
{ "weapalt", K_MOUSE2, -1, K_MOUSE2, -1, -1, -1 },
{ "weapprev", K_MWHEELDOWN, -1, K_MWHEELDOWN, -1, -1, -1 },
{ "weapnext", K_MWHEELUP, -1, K_MWHEELUP, -1, -1, -1 },
{ "weaponbank 10", '0', -1, '0', -1, -1, -1 },
{ "weaponbank 1", '1', -1, '1', -1, -1, -1 },
{ "weaponbank 2", '2', -1, '2', -1, -1, -1 },
{ "weaponbank 3", '3', -1, '3', -1, -1, -1 },
{ "weaponbank 4", '4', -1, '4', -1, -1, -1 },
{ "weaponbank 5", '5', -1, '5', -1, -1, -1 },
{ "weaponbank 6", '6', -1, '6', -1, -1, -1 },
{ "weaponbank 7", '7', -1, '7', -1, -1, -1 },
{ "weaponbank 8", '8', -1, '8', -1, -1, -1 },
{ "weaponbank 9", '9', -1, '9', -1, -1, -1 },
{ "+sprint", K_SHIFT, -1, K_MOUSE3, -1, -1, -1 },
{ "+speed", K_CAPSLOCK, -1, K_CAPSLOCK, -1, -1, -1 },
{ "+activate", 'f', -1, K_ENTER, -1, -1, -1 },
{ "+zoom", 'b', -1, 'b', -1, -1, -1 },
{ "+mapexpand", 'g', -1, '#', -1, -1, -1 },
{ "+reload", 'r', -1, K_END, -1, -1, -1 },
{ "+scores", K_TAB, -1, K_TAB, -1, -1, -1 },
{ "+stats", K_ALT, -1, K_F9, -1, -1, -1 },
{ "+topshots", K_CTRL, -1, K_F10, -1, -1, -1 },
{ "toggleconsole", '`', '~', '`', '~', -1, -1 },
{ "togglemenu", K_ESCAPE, -1, K_ESCAPE, -1, -1, -1 },
{ "openlimbomenu", 'l', -1, 'l', -1, -1, -1 },
{ "mvactivate", 'm', -1, 'm', -1, -1, -1 },
{ "mapzoomout", ',', -1, '[', -1, -1, -1 },
{ "mapzoomin", '.', -1, ']', -1, -1, -1 },
{ "zoomin", '=', -1, '-', -1, -1, -1 },
{ "zoomout", '-', -1, '=', -1, -1, -1 },
{ "messagemode", 't', -1, 't', -1, -1, -1 },
{ "messagemode2", 'y', -1, 'y', -1, -1, -1 },
{ "messagemode3", 'u', -1, 'u', -1, -1, -1 },
{ "mp_quickmessage",'v', -1, 'v', -1, -1, -1 },
{ "mp_fireteammsg", 'z', -1, 'c', -1, -1, -1 },
{ "vote yes", K_F1, -1, K_F1, -1, -1, -1 },
{ "vote no", K_F2, -1, K_F2, -1, -1, -1 },
{ "ready", K_F3, -1, K_F3, -1, -1, -1 },
{ "notready", K_F4, -1, K_F4, -1, -1, -1 },
{ "autoscreenshot", K_F11, -1, K_F11, -1, -1, -1 },
{ "autoRecord", K_F12, -1, K_F12, -1, -1, -1 },
{ "mp_fireteamadmin", K_KP_ENTER, -1, K_KP_ENTER, -1, -1, -1 },
{ "selectbuddy -1", K_KP_DEL, -1, K_KP_PLUS, -1, -1, -1 },
{ "selectbuddy 0", K_KP_END, -1, K_KP_END, -1, -1, -1 },
{ "selectbuddy 1", K_KP_DOWNARROW, -1, K_KP_DOWNARROW, -1, -1, -1 },
{ "selectbuddy 2", K_KP_PGDN, -1, K_KP_PGDN, -1, -1, -1 },
{ "selectbuddy 3", K_KP_LEFTARROW, -1, K_KP_LEFTARROW, -1, -1, -1 },
{ "selectbuddy 4", K_KP_5, -1, K_KP_5, -1, -1, -1 },
{ "selectbuddy 5", K_KP_RIGHTARROW,-1, K_KP_RIGHTARROW,-1, -1, -1 },
{ "selectbuddy -2", K_KP_INS, -1, K_KP_MINUS, -1, -1, -1 },
/* {"+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}, // this is an exploit nowadays
{"+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},
{"+button3", K_MOUSE3, -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},
{"+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},
{"vote yes", -1, -1, -1, -1},
{"vote no", -1, -1, -1, -1},
{"openlimbomenu", -1, -1, -1, -1},
{"mp_quickmessage", -1, -1, -1, -1},
{"mp_fireteammsg", -1, -1, -1, -1},
{"mp_fireteamadmin",-1, -1, -1, -1},
// OSP
{"+stats", -1, -1, -1, -1},
{"+topshots", -1, -1, -1, -1},
{"+wstats", -1, -1, -1, -1},
{"autoScreenshot", -1, -1, -1, -1},
{"autoRecord", -1, -1, -1, -1},
{"currenttime", -1, -1, -1, -1},
{"statsdump", -1, -1, -1, -1},
{"mvallies", -1, -1, -1, -1},
{"mvaxis", -1, -1, -1, -1},
{"mvdel", -1, -1, -1, -1},
{"mvhide", -1, -1, -1, -1},
{"mvnone", -1, -1, -1, -1},
{"mvshow", -1, -1, -1, -1},
{"mvswap", -1, -1, -1, -1},
{"mvtoggle", -1, -1, -1, -1},
{"mvactivate", -1, -1, -1, -1},
// -OSP
{"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},
{"commandmap", -1, -1, -1, -1},
{"buddy", -1, -1, -1, -1},
{"stats", -1, -1, -1, -1},
{"selectbuddy -1", -1, -1, -1, -1},
{"selectbuddy -2", -1, -1, -1, -1},
{"selectbuddy 0", -1, -1, -1, -1},
{"selectbuddy 1", -1, -1, -1, -1},
{"selectbuddy 2", -1, -1, -1, -1},
{"selectbuddy 3", -1, -1, -1, -1},
{"selectbuddy 4", -1, -1, -1, -1},
{"selectbuddy 5", -1, -1, -1, -1},
{"gotowaypoint", -1, -1, -1, -1},
{"mapzoomin", -1, -1, -1, -1},
{"mapzoomout", -1, -1, -1, -1},
{"+mapexpand", -1, -1, -1, -1},
{"+prone", -1, -1, -1, -1},*/
};
static const int g_bindCount = sizeof( g_bindings ) / sizeof( bind_t );
/*
=================
Controls_GetConfig
=================
*/
void Controls_GetConfig( void ) {
int i;
// iterate each command, get its numeric binding
for ( i = 0; i < g_bindCount; i++ ) {
DC->getKeysForBinding( g_bindings[i].command, &g_bindings[i].bind1, &g_bindings[i].bind2 );
}
}
/*
=================
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 !defined( __MACOS__ )
if ( restart ) {
DC->executeText( EXEC_APPEND, "in_restart\n" );
}
#endif
//trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
}
/*
=================
Controls_SetDefaults
=================
*/
void Controls_SetDefaults( qboolean lefthanded ) {
int i;
// iterate each command, set its default binding
for ( i = 0; i < g_bindCount; i++ ) {
g_bindings[i].bind1 = lefthanded ? g_bindings[i].defaultbind1_left : g_bindings[i].defaultbind1_right;
g_bindings[i].bind2 = lefthanded ? g_bindings[i].defaultbind2_left : g_bindings[i].defaultbind2_right;
}
}
int BindingIDFromName( const char *name ) {
int i;
for ( i = 0; i < g_bindCount; i++ ) {
if ( !Q_stricmp( name, g_bindings[i].command ) ) {
return i;
}
}
return -1;
}
char g_nameBind1[32];
char g_nameBind2[32];
char* BindingFromName( const char *cvar ) {
int b1, b2;
DC->getKeysForBinding( cvar, &b1, &b2 );
if ( b1 != -1 ) {
DC->keynumToStringBuf( b1, g_nameBind1, 32 );
Q_strupr( g_nameBind1 );
if ( b2 != -1 ) {
DC->keynumToStringBuf( b2, g_nameBind2, 32 );
Q_strupr( g_nameBind2 );
Q_strcat( g_nameBind1, 32, DC->translateString( " or " ) );
Q_strcat( g_nameBind1, 32, g_nameBind2 );
}
} else {
Q_strncpyz( g_nameBind1, "(?" "?" "?)", 32 );
}
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 && item->window.flags & WINDOW_FOCUSPULSE ) {
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 );
DC->drawHandlePic( x, y + 1, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar );
x = Item_Slider_ThumbPosition( item );
//DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y - 2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb );
DC->drawHandlePic( x - ( SLIDER_THUMB_WIDTH / 2 ), y, 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 && item->window.flags & WINDOW_FOCUSPULSE ) {
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 {
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;
LerpColor( item->window.foreColor, lowLight, newColor, 0.5 + 0.5 * sin( DC->realTime / PULSE_DIVISOR ) );
} else {
memcpy( &newColor, &item->window.foreColor, sizeof( vec4_t ) );
}
}
if ( item->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 {
return qfalse;
}
} else
{
if ( !g_waitingForKey || g_bindItem == NULL ) {
return qfalse;
}
if ( key & K_CHAR_FLAG ) {
return qtrue;
}
switch ( key )
{
case K_ESCAPE:
g_waitingForKey = qfalse;
g_bindItem = NULL;
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;
g_bindItem = NULL;
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 optionalImages[8];
int numOptionalImages;
listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
rectDef_t fillRect = item->window.rect;
/*if( item->window.borderSize ) {
fillRect.x += item->window.borderSize;
fillRect.y += item->window.borderSize;
fillRect.w -= 2 * item->window.borderSize;
fillRect.h -= 2 * item->window.borderSize;
}*/
// 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 = fillRect.x + 1;
y = fillRect.y + fillRect.h - SCROLLBAR_SIZE - 1;
DC->drawHandlePic( x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft );
x += SCROLLBAR_SIZE - 1;
size = fillRect.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 = fillRect.w - 2;
// items
// size contains max available space
if ( listPtr->elementStyle == LISTBOX_IMAGE ) {
// fit = 0;
x = fillRect.x + 1;
y = fillRect.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 = fillRect.x + fillRect.w - SCROLLBAR_SIZE - 1;
y = fillRect.y + 1;
DC->drawHandlePic( x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp );
y += SCROLLBAR_SIZE - 1;
listPtr->endPos = listPtr->startPos;
size = fillRect.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 = fillRect.h /* - 2*/;
if ( listPtr->elementStyle == LISTBOX_IMAGE ) {
// fit = 0;
x = fillRect.x + 1;
y = fillRect.y + 1;
for ( i = listPtr->startPos; i < count; i++ ) {
if ( i == item->cursorPos ) {
DC->fillRect( x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.outlineColor );
}
// always draw at least one
// which may overdraw the box if it is too small for the element
image = DC->feederItemImage( item->special, i );
if ( image ) {
DC->drawHandlePic( x + 1, y + 1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image );
}
if ( i == item->cursorPos ) {
DC->drawRect( x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.borderColor );
}
listPtr->endPos++;
size -= listPtr->elementHeight;
if ( size < listPtr->elementHeight ) {
listPtr->drawPadding = size; //listPtr->elementHeight - size;
break;
}
y += listPtr->elementHeight;
// fit++;
}
} else {
x = fillRect.x /*+ 1*/;
y = fillRect.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, k;
for ( j = 0; j < listPtr->numColumns; j++ ) {
text = DC->feederItemText( item->special, i, j, optionalImages, &numOptionalImages );
if ( numOptionalImages > 0 ) {
for ( k = 0; k < numOptionalImages; k++ ) {
if ( optionalImages[k] >= 0 ) {
DC->drawHandlePic( x + listPtr->columnInfo[j].pos + k * listPtr->elementHeight + 1,
y + 1, listPtr->elementHeight - 2, listPtr->elementHeight - 2, optionalImages[k] );
}
}
//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, optionalImages, &numOptionalImages );
if ( numOptionalImages >= 0 ) {
//DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
} else if ( text ) {
DC->drawText( x + 4 + item->textalignx, y + listPtr->elementHeight + item->textaligny, item->textscale, item->window.foreColor, text, 0, 0, item->textStyle );
}
}
if ( i == item->cursorPos ) {
DC->fillRect( x, y, fillRect.w - SCROLLBAR_SIZE - 2, listPtr->elementHeight /* - 1*/, item->window.outlineColor );
}
size -= listPtr->elementHeight;
if ( size < listPtr->elementHeight ) {
listPtr->drawPadding = size; //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;
}
}
}
if ( item->window.flags & WINDOW_HASFOCUS && item->window.flags & WINDOW_FOCUSPULSE ) {
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 ) );
}
// gah wtf indentation!
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;
}
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 | WINDOW_MOUSEOVER );
} else {
item->window.flags |= WINDOW_VISIBLE;
}
}
if ( item->cvarFlags & ( CVAR_SHOW | CVAR_HIDE ) ) {
if ( !Item_EnableShowViaCvar( item, CVAR_SHOW ) ) {
return;
}
}
// OSP
if ( ( item->settingFlags & ( SVS_ENABLED_SHOW | SVS_DISABLED_SHOW ) ) && !Item_SettingShow( item, qfalse ) ) {
return;
}
if ( item->voteFlag != 0 && !Item_SettingShow( item, qtrue ) ) {
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:
case ITEM_TYPE_TIMEOUT_COUNTER:
Item_Text_Paint( item );
break;
case ITEM_TYPE_RADIOBUTTON:
break;
case ITEM_TYPE_CHECKBOX:
case ITEM_TYPE_TRICHECKBOX:
Item_CheckBox_Paint( item );
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;
// START - TAT 9/16/2002
// by default, do NOT use item hotkey mode
menu->itemHotkeyMode = qfalse;
// END - TAT 9/16/2002
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;
}
break; // Arnout: found it, don't continue searching as we might unfocus the menu we just activated again.
} else {
Menus[i].window.flags &= ~( WINDOW_HASFOCUS | WINDOW_MOUSEOVER );
}
}
Display_CloseCinematics();
return m;
}
void Item_Init( itemDef_t *item ) {
memset( item, 0, sizeof( itemDef_t ) );
item->textscale = 0.55f;
// default hotkey to -1
item->hotkey = -1;
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;
}
// OSP - server settings too
if ( ( menu->items[i]->settingFlags & ( SVS_ENABLED_SHOW | SVS_DISABLED_SHOW ) ) && !Item_SettingShow( menu->items[i], qfalse ) ) {
continue;
}
if ( menu->items[i]->voteFlag != 0 && !Item_SettingShow( menu->items[i], qtrue ) ) {
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;
itemDef_t *item = NULL;
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 ( menu->items[i]->window.flags & WINDOW_MOUSEOVER ) {
item = menu->items[i];
}
}
// OSP draw tooltip data if we have it
if ( DC->getCVarValue( "ui_showtooltips" ) &&
item != NULL &&
item->toolTipData != NULL &&
item->toolTipData->text != NULL &&
*item->toolTipData->text ) {
Item_Paint( item->toolTipData );
}
// ydnar: handle timeout here
if ( menu->openTime == 0 ) {
menu->openTime = DC->realTime;
} else if ( menu->window.flags & WINDOW_VISIBLE &&
menu->timeout > 0 && menu->onTimeout != NULL &&
menu->openTime + menu->timeout <= DC->realTime ) {
itemDef_t it;
it.parent = menu;
Item_RunScript( &it, NULL, menu->onTimeout );
}
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->type == ITEM_TYPE_CHECKBOX || item->type == ITEM_TYPE_TRICHECKBOX ) {
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 ) );
}
}
/*
========================
Item_ValidateTooltipData
========================
*/
qboolean Item_ValidateTooltipData( itemDef_t *item ) {
if ( item->toolTipData != NULL ) {
return( qtrue );
}
item->toolTipData = UI_Alloc( sizeof( itemDef_t ) );
if ( item->toolTipData == NULL ) {
return( qfalse );
}
Item_Init( item->toolTipData );
Tooltip_Initialize( item->toolTipData );
return( qtrue );
}
/*
===============
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 = NULL;
if ( !PC_String_Parse( handle, &temp ) ) {
return qfalse;
}
item->focusSound = DC->registerSound( temp, qtrue );
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 = NULL;
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 = NULL;
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 ) {
return( PC_Rect_Parse( handle, &item->window.rectClient ) );
}
// NERVE - SMF
// origin
qboolean ItemParse_origin( itemDef_t *item, int handle ) {
int x = 0, y = 0;
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;
}
// textasint
qboolean ItemParse_textasint( itemDef_t *item, int handle ) {
item->window.flags |= WINDOW_TEXTASINT;
return qtrue;
}
// textasfloat
qboolean ItemParse_textasfloat( itemDef_t *item, int handle ) {
item->window.flags |= WINDOW_TEXTASFLOAT;
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 = 0, 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 = 0, width = 0, maxChars = 0;
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 = 0;
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 = 0.0f;
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 = 0.0f;
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 = 0.0f;
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 = NULL;
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_onEsc( itemDef_t *item, int handle ) {
if ( !PC_Script_Parse( handle, &item->onEsc ) ) {
return qfalse;
}
return qtrue;
}
qboolean ItemParse_onEnter( itemDef_t *item, int handle ) {
if ( !PC_Script_Parse( handle, &item->onEnter ) ) {
return qfalse;
}
return qtrue;
}
qboolean ItemParse_contextMenu( itemDef_t *item, int handle ) {
listBoxDef_t *listPtr;
Item_ValidateTypeData( item );
if ( !item->typeData ) {
return qfalse;
}
listPtr = (listBoxDef_t*)item->typeData;
if ( !PC_String_Parse( handle, &listPtr->contextMenu ) ) {
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;
}
Q_strlwr( (char *)item->cvar );
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 = 0;
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 = 0;
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 ItemParse_cvarListUndefined( 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->undefinedStr = NULL;
if ( !trap_PC_ReadToken( handle, &token ) ) {
return qfalse;
}
multiPtr->undefinedStr = String_Alloc( token.string );
return qtrue;
}
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 = 0;
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;
}
// START - TAT 9/16/2002
qboolean ItemParse_execKey( itemDef_t *item, int handle ) {
char keyname;
// read in the hotkey
if ( !PC_Char_Parse( handle, &keyname ) ) {
return qfalse;
}
// store it in the hotkey field
item->hotkey = keyname;
// read in the command to execute
if ( !PC_Script_Parse( handle, &item->onKey ) ) {
return qfalse;
}
return qtrue;
}
// END - TAT 9/16/2002
// OSP - server setting tags
qboolean ItemParse_settingDisabled( itemDef_t *item, int handle ) {
qboolean fResult = PC_Int_Parse( handle, &item->settingTest );
if ( fResult ) {
item->settingFlags = SVS_DISABLED_SHOW;
}
return( fResult );
}
qboolean ItemParse_settingEnabled( itemDef_t *item, int handle ) {
qboolean fResult = PC_Int_Parse( handle, &item->settingTest );
if ( fResult ) {
item->settingFlags = SVS_ENABLED_SHOW;
}
return( fResult );
}
qboolean ItemParse_tooltip( itemDef_t *item, int handle ) {
return( Item_ValidateTooltipData( item ) && PC_String_Parse( handle, &item->toolTipData->text ) );
}
qboolean ItemParse_tooltipalignx( itemDef_t *item, int handle ) {
return( Item_ValidateTooltipData( item ) && PC_Float_Parse( handle, &item->toolTipData->textalignx ) );
}
qboolean ItemParse_tooltipaligny( itemDef_t *item, int handle ) {
return( Item_ValidateTooltipData( item ) && PC_Float_Parse( handle, &item->toolTipData->textaligny ) );
}
qboolean ItemParse_voteFlag( itemDef_t *item, int handle ) {
return( PC_Int_Parse( handle, &item->voteFlag ) );
}
keywordHash_t itemParseKeywords[] =
{
{ "accept", ItemParse_accept, NULL }, // NERVE - SMF
{ "action", ItemParse_action, NULL },
{ "addColorRange", ItemParse_addColorRange, NULL },
{ "addColorRangeRel", ItemParse_addColorRangeRel, NULL },
{ "align", ItemParse_align, NULL },
{ "asset_model", ItemParse_asset_model, NULL },
{ "asset_shader", ItemParse_asset_shader, NULL },
{ "autowrapped", ItemParse_autowrapped, NULL },
{ "backcolor", ItemParse_backcolor, NULL },
{ "background", ItemParse_background, NULL },
{ "border", ItemParse_border, NULL },
{ "bordercolor", ItemParse_bordercolor, NULL },
{ "bordersize", ItemParse_bordersize, NULL },
{ "cinematic", ItemParse_cinematic, NULL },
{ "columns", ItemParse_columns, NULL },
{ "contextmenu", ItemParse_contextMenu, NULL },
{ "cvar", ItemParse_cvar, NULL },
{ "cvarFloat", ItemParse_cvarFloat, NULL },
{ "cvarFloatList", ItemParse_cvarFloatList, NULL },
{ "cvarStrList", ItemParse_cvarStrList, NULL },
{ "cvarListUndefined", ItemParse_cvarListUndefined,NULL },
{ "cvarTest", ItemParse_cvarTest, NULL },
{ "decoration", ItemParse_decoration, NULL },
{ "textasint", ItemParse_textasint, NULL },
{ "textasfloat", ItemParse_textasfloat, NULL },
{ "disableCvar", ItemParse_disableCvar, NULL },
{ "doubleclick", ItemParse_doubleClick, NULL },
{ "onEsc", ItemParse_onEsc, NULL },
{ "onEnter", ItemParse_onEnter, NULL },
{ "elementheight", ItemParse_elementheight, NULL },
{ "elementtype", ItemParse_elementtype, NULL },
{ "elementwidth", ItemParse_elementwidth, NULL },
{ "enableCvar", ItemParse_enableCvar, NULL },
{ "execKey", ItemParse_execKey, NULL },
{ "feeder", ItemParse_feeder, NULL },
{ "focusSound", ItemParse_focusSound, NULL },
{ "forecolor", ItemParse_forecolor, NULL },
{ "group", ItemParse_group, NULL },
{ "hideCvar", ItemParse_hideCvar, NULL },
{ "horizontalscroll", ItemParse_horizontalscroll, NULL },
{ "leaveFocus", ItemParse_leaveFocus, NULL },
{ "maxChars", ItemParse_maxChars, NULL },
{ "maxPaintChars", ItemParse_maxPaintChars, NULL },
{ "model_angle", ItemParse_model_angle, NULL },
{ "model_animplay", ItemParse_model_animplay, NULL },
{ "model_fovx", ItemParse_model_fovx, NULL },
{ "model_fovy", ItemParse_model_fovy, NULL },
{ "model_origin", ItemParse_model_origin, NULL },
{ "model_rotation", ItemParse_model_rotation, NULL },
{ "mouseEnter", ItemParse_mouseEnter, NULL },
{ "mouseEnterText", ItemParse_mouseEnterText, NULL },
{ "mouseExit", ItemParse_mouseExit, NULL },
{ "mouseExitText", ItemParse_mouseExitText, NULL },
{ "name", ItemParse_name, NULL },
{ "noToggle", ItemParse_noToggle, NULL }, // TTimo: use with ITEM_TYPE_YESNO and an action script (see sv_punkbuster)
{ "notselectable", ItemParse_notselectable, NULL },
{ "onFocus", ItemParse_onFocus, NULL },
{ "origin", ItemParse_origin, NULL }, // NERVE - SMF
{ "outlinecolor", ItemParse_outlinecolor, NULL },
{ "ownerdraw", ItemParse_ownerdraw, NULL },
{ "ownerdrawFlag", ItemParse_ownerdrawFlag, NULL },
{ "rect", ItemParse_rect, NULL },
{ "settingDisabled", ItemParse_settingDisabled, NULL }, // OSP
{ "settingEnabled", ItemParse_settingEnabled, NULL }, // OSP
{ "showCvar", ItemParse_showCvar, NULL },
{ "special", ItemParse_special, NULL },
{ "style", ItemParse_style, NULL },
{ "text", ItemParse_text, NULL },
{ "textalign", ItemParse_textalign, NULL },
{ "textalignx", ItemParse_textalignx, NULL },
{ "textaligny", ItemParse_textaligny, NULL },
{ "textfile", ItemParse_textfile, NULL }, //----(SA) added
{ "textfont", ItemParse_textfont, NULL }, // (SA)
{ "textscale", ItemParse_textscale, NULL },
{ "textstyle", ItemParse_textstyle, NULL },
{ "tooltip", ItemParse_tooltip, NULL },
{ "tooltipalignx", ItemParse_tooltipalignx, NULL },
{ "tooltipaligny", ItemParse_tooltipaligny, NULL },
{ "type", ItemParse_type, NULL },
{ "visible", ItemParse_visible, NULL },
{ "voteFlag", ItemParse_voteFlag, NULL }, // OSP - vote check
{ "wrapped", ItemParse_wrapped, NULL },
{ 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;
}
}
if ( item->toolTipData != NULL ) {
Tooltip_ComputePosition( item );
}
}
/*
===============
Menu Keyword Parse functions
===============
*/
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;
return( PC_Rect_Parse( handle, &menu->window.rect ) );
}
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 = 0;
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_onEnter( itemDef_t *item, int handle ) {
menuDef_t *menu = (menuDef_t*)item;
if ( !PC_Script_Parse( handle, &menu->onEnter ) ) {
return qfalse;
}
return qtrue;
}
// ydnar: menu timeout function
qboolean MenuParse_onTimeout( itemDef_t *item, int handle ) {
menuDef_t *menu = (menuDef_t*) item;
if ( !PC_Int_Parse( handle, &menu->timeout ) ) {
return qfalse;
}
if ( !PC_Script_Parse( handle, &menu->onTimeout ) ) {
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 = 0.0f;
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 = 0.0f;
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 = 0.0f;
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 = 0.0f;
menuDef_t *menu = (menuDef_t*)item;
for ( i = 0; i < 4; i++ ) {
if ( !PC_Float_Parse( handle, &f ) ) {
return qfalse;
}
menu->focusColor[i] = f;
}
item->window.flags |= WINDOW_FOCUSPULSE;
return qtrue;
}
qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) {
int i;
float f = 0.0f;
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 = NULL;
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 = 0;
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;
}
menu->items[menu->itemCount]->parent = menu;
Item_InitControls( menu->items[menu->itemCount++] );
// START - TAT 9/16/2002
// If we are storing the hotkeys in the items, we have a little problem, in that
// people check with the menu to see if we have a hotkey (see UI_CheckExecKey)
// So we sort of need to stuff the hotkey back into the menu for that to work
// only do this at all if we're using the item hotkey mode
// NOTE: we couldn't do this earlier because the menu wasn't set, and I don't know
// what would happen if we tried to set the menu before the parse had succeeded...
if ( menu->itemHotkeyMode && menu->items[menu->itemCount - 1]->hotkey >= 0 ) {
menu->onKey[menu->items[menu->itemCount - 1]->hotkey] = String_Alloc( menu->items[menu->itemCount - 1]->onKey );
}
// END - TAT 9/16/2002
}
return qtrue;
}
// NERVE - SMF
qboolean MenuParse_execKey( itemDef_t *item, int handle ) {
menuDef_t *menu = ( menuDef_t* )item;
char keyname = 0;
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 = 0;
if ( !PC_Int_Parse( handle, &keyname ) ) {
return qfalse;
}
if ( !PC_Script_Parse( handle, &menu->onKey[keyname] ) ) {
return qfalse;
}
return qtrue;
}
// -NERVE - SMF
qboolean MenuParse_drawAlwaysOnTop( itemDef_t *item, int handle ) {
menuDef_t *menu = (menuDef_t*)item;
menu->window.flags |= WINDOW_DRAWALWAYSONTOP;
return qtrue;
}
// START - TAT 9/16/2002
// parse the command to set if we're looping through all items to find the current hotkey
qboolean MenuParse_itemHotkeyMode( itemDef_t *item, int handle ) {
// like MenuParse_fullscreen - reading an int
menuDef_t *menu = (menuDef_t*)item;
if ( !PC_Int_Parse( handle, (int*)&menu->itemHotkeyMode ) ) {
return qfalse;
}
return qtrue;
}
// END - TAT 9/16/2002
// 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[] = {
{"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},
{"onTimeout", MenuParse_onTimeout, NULL }, // ydnar: menu timeout function
{"onESC", MenuParse_onESC, NULL},
{"onEnter", MenuParse_onEnter, 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
{"alwaysontop", MenuParse_drawAlwaysOnTop, NULL},
{"modal", MenuParse_modal, NULL },
// START - TAT 9/16/2002
// parse the command to set if we're looping through all items to find the current hotkey
{"itemHotkeyMode", MenuParse_itemHotkeyMode, NULL},
// END - TAT 9/16/2002
{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;
}
menuDef_t *Menu_Get( int handle ) {
if ( handle >= 0 && handle < menuCount ) {
return &Menus[handle];
} else {
return NULL;
}
}
void Menu_PaintAll() {
int i;
if ( captureFunc ) {
captureFunc( captureData );
}
for ( i = 0; i < menuCount; i++ ) {
if ( Menus[i].window.flags & WINDOW_DRAWALWAYSONTOP ) {
continue;
}
Menu_Paint( &Menus[i], qfalse );
}
for ( i = 0; i < menuCount; i++ ) {
if ( Menus[i].window.flags & WINDOW_DRAWALWAYSONTOP ) {
Menu_Paint( &Menus[i], qfalse );
}
}
if ( debugMode ) {
vec4_t v = {1, 1, 1, 1};
DC->textFont( UI_FONT_COURBD_21 );
DC->drawText( 5, 10, .2, v, va( "fps: %.2f", DC->FPS ), 0, 0, 0 );
DC->drawText( 5, 20, .2, v, va( "mouse: %i %i", DC->cursorx, DC->cursory ), 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;
// menu = Menu_GetFocused();
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, qtrue );
}
}
}
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;
}
/*
=================
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;
}
/*
=================
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;
}
// digibob
// Panel Handling
// ======================================================
panel_button_t* bg_focusButton;
qboolean BG_RectContainsPoint( float x, float y, float w, float h, float px, float py ) {
if ( px > x && px < x + w && py > y && py < y + h ) {
return qtrue;
}
return qfalse;
}
qboolean BG_CursorInRect( rectDef_t* rect ) {
return BG_RectContainsPoint( rect->x, rect->y, rect->w, rect->h, DC->cursorx, DC->cursory );
}
void BG_PanelButton_RenderEdit( panel_button_t* button ) {
qboolean useCvar = button->data[0] ? qfalse : qtrue;
int offset = -1;
if ( useCvar ) {
char buffer[256 + 1];
trap_Cvar_VariableStringBuffer( button->text, buffer, sizeof( buffer ) );
if ( BG_PanelButtons_GetFocusButton() == button && ( ( DC->realTime / 1000 ) % 2 ) ) {
if ( trap_Key_GetOverstrikeMode() ) {
Q_strcat( buffer, sizeof( buffer ), "^0|" );
} else {
Q_strcat( buffer, sizeof( buffer ), "^0_" );
}
} else {
Q_strcat( buffer, sizeof( buffer ), " " );
}
do {
offset++;
if ( buffer + offset == '\0' ) {
break;
}
} while ( DC->textWidthExt( buffer + offset, button->font->scalex, 0, button->font->font ) > button->rect.w );
DC->drawTextExt( button->rect.x, button->rect.y + button->rect.h, button->font->scalex, button->font->scaley, button->font->colour, va( "^7%s", buffer + offset ), 0, 0, button->font->style, button->font->font );
} else {
char *s;
if ( BG_PanelButtons_GetFocusButton() == button && ( ( DC->realTime / 1000 ) % 2 ) ) {
if ( DC->getOverstrikeMode() ) {
s = va( "^7%s^0|", button->text );
} else {
s = va( "^7%s^0_", button->text );
}
} else {
s = va( "^7%s ", button->text ); // space hack to make the text not blink
}
do {
offset++;
if ( s + offset == '\0' ) {
break;
}
} while ( DC->textWidthExt( s + offset, button->font->scalex, 0, button->font->font ) > button->rect.w );
DC->drawTextExt( button->rect.x, button->rect.y + button->rect.h, button->font->scalex, button->font->scaley, button->font->colour, s + offset, 0, 0, button->font->style, button->font->font );
}
}
qboolean BG_PanelButton_EditClick( panel_button_t* button, int key ) {
if ( key == K_MOUSE1 ) {
if ( !BG_CursorInRect( &button->rect ) && BG_PanelButtons_GetFocusButton() == button ) {
BG_PanelButtons_SetFocusButton( NULL );
if ( button->onFinish ) {
button->onFinish( button );
}
return qfalse;
} else {
BG_PanelButtons_SetFocusButton( button );
return qtrue;
}
} else if ( BG_PanelButtons_GetFocusButton() != button ) {
return qfalse;
} else {
char buffer[256];
char *s = NULL;
int len, maxlen;
qboolean useCvar = button->data[0] ? qfalse : qtrue;
if ( useCvar ) {
maxlen = sizeof( buffer );
DC->getCVarString( button->text, buffer, sizeof( buffer ) );
len = strlen( buffer );
} else {
maxlen = button->data[0];
s = (char *)button->text;
len = strlen( s );
}
if ( key & K_CHAR_FLAG ) {
key &= ~K_CHAR_FLAG;
if ( key == 'h' - 'a' + 1 ) { // ctrl-h is backspace
if ( len ) {
if ( useCvar ) {
buffer[len - 1] = '\0';
DC->setCVar( button->text, buffer );
} else {
s[len - 1] = '\0';
}
}
return qtrue;
}
if ( key < 32 ) {
return qtrue;
}
if ( button->data[1] ) {
if ( key < '0' || key > '9' ) {
if ( button->data[1] == 2 ) {
return qtrue;
} else if ( !( len == 0 && key == '-' ) ) {
return qtrue;
}
}
}
if ( len >= maxlen - 1 ) {
return qtrue;
}
if ( useCvar ) {
buffer[len] = key;
buffer[len + 1] = '\0';
trap_Cvar_Set( button->text, buffer );
} else {
s[len] = key;
s[len + 1] = '\0';
}
return qtrue;
} else {
// Gordon: FIXME: have this work with all our stuff (use data[x] to store cursorpos etc)
/* 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_ENTER || key == K_KP_ENTER ) {
if ( button->onFinish ) {
button->onFinish( button );
}
BG_PanelButtons_SetFocusButton( NULL );
return qfalse;
}
}
}
return qtrue;
}
qboolean BG_PanelButtonsKeyEvent( int key, qboolean down, panel_button_t** buttons ) {
panel_button_t* button;
if ( BG_PanelButtons_GetFocusButton() ) {
for ( ; *buttons; buttons++ ) {
button = ( *buttons );
if ( button == BG_PanelButtons_GetFocusButton() ) {
if ( button->onKeyDown && down ) {
if ( !button->onKeyDown( button, key ) ) {
if ( BG_PanelButtons_GetFocusButton() ) {
return qfalse;
}
} else {
return qtrue;
}
}
if ( button->onKeyUp && !down ) {
if ( !button->onKeyUp( button, key ) ) {
if ( BG_PanelButtons_GetFocusButton() ) {
return qfalse;
}
} else {
return qtrue;
}
}
}
}
}
if ( down ) {
for ( ; *buttons; buttons++ ) {
button = ( *buttons );
if ( button->onKeyDown ) {
if ( BG_CursorInRect( &button->rect ) ) {
if ( button->onKeyDown( button, key ) ) {
return qtrue;
}
}
}
}
} else {
for ( ; *buttons; buttons++ ) {
button = ( *buttons );
if ( button->onKeyUp && BG_CursorInRect( &button->rect ) ) {
if ( button->onKeyUp( button, key ) ) {
return qtrue;
}
}
}
}
return qfalse;
}
void BG_PanelButtonsSetup( panel_button_t** buttons ) {
panel_button_t* button;
for ( ; *buttons; buttons++ ) {
button = ( *buttons );
if ( button->shaderNormal ) {
button->hShaderNormal = trap_R_RegisterShaderNoMip( button->shaderNormal );
}
}
}
panel_button_t* BG_PanelButtonsGetHighlightButton( panel_button_t** buttons ) {
panel_button_t* button;
for ( ; *buttons; buttons++ ) {
button = ( *buttons );
if ( button->onKeyDown && BG_CursorInRect( &button->rect ) ) {
return button;
}
}
return NULL;
}
void BG_PanelButtonsRender( panel_button_t** buttons ) {
panel_button_t* button;
for ( ; *buttons; buttons++ ) {
button = ( *buttons );
if ( button->onDraw ) {
button->onDraw( button );
}
}
}
void BG_PanelButtonsRender_TextExt( panel_button_t* button, const char* text ) {
float x = button->rect.x;
float w = button->rect.w;
if ( !button->font ) {
return;
}
if ( button->font->align == ITEM_ALIGN_CENTER ) {
w = DC->textWidthExt( text, button->font->scalex, 0, button->font->font );
x += ( ( button->rect.w - w ) * 0.5f );
} else if ( button->font->align == ITEM_ALIGN_RIGHT ) {
x += button->rect.w - DC->textWidthExt( text, button->font->scalex, 0, button->font->font );
}
if ( button->data[1] ) {
vec4_t clrBdr = { 0.5f, 0.5f, 0.5f, 1.f };
vec4_t clrBck = { 0.f, 0.f, 0.f, 0.8f };
DC->fillRect( button->rect.x, button->rect.y, button->rect.w, button->rect.h, clrBck );
DC->drawRect( button->rect.x, button->rect.y, button->rect.w, button->rect.h, 1, clrBdr );
}
DC->drawTextExt( x, button->rect.y + button->data[0], button->font->scalex, button->font->scaley, button->font->colour, text, 0, 0, button->font->style, button->font->font );
}
void BG_PanelButtonsRender_Text( panel_button_t* button ) {
BG_PanelButtonsRender_TextExt( button, button->text );
}
void BG_PanelButtonsRender_Img( panel_button_t* button ) {
vec4_t clr = { 1.f, 1.f, 1.f, 1.f };
if ( button->data[0] ) {
clr[0] = button->data[1] / 255.f;
clr[1] = button->data[2] / 255.f;
clr[2] = button->data[3] / 255.f;
clr[3] = button->data[4] / 255.f;
trap_R_SetColor( clr );
}
if ( button->data[5] ) {
DC->drawRect( button->rect.x, button->rect.y, button->rect.w, button->rect.h, 1, clr );
} else {
DC->drawHandlePic( button->rect.x, button->rect.y, button->rect.w, button->rect.h, button->hShaderNormal );
}
if ( button->data[0] ) {
trap_R_SetColor( NULL );
}
}
panel_button_t* BG_PanelButtons_GetFocusButton( void ) {
return bg_focusButton;
}
void BG_PanelButtons_SetFocusButton( panel_button_t* button ) {
bg_focusButton = button;
}
void BG_FitTextToWidth_Ext( char* instr, float scale, float w, int size, fontInfo_t* font ) {
char buffer[1024];
char *s, *p, *c, *ls;
int l;
Q_strncpyz( buffer, instr, 1024 );
memset( instr, 0, size );
c = s = instr;
p = buffer;
ls = NULL;
l = 0;
while ( *p ) {
*c = *p++;
l++;
if ( *c == ' ' ) {
ls = c;
} // store last space, to try not to break mid word
c++;
if ( *p == '\n' ) {
s = c + 1;
l = 0;
} else if ( DC->textWidthExt( s, scale, 0, font ) > w ) {
if ( ls ) {
*ls = '\n';
s = ls + 1;
} else {
*c = *( c - 1 );
*( c - 1 ) = '\n';
s = c++;
}
ls = NULL;
l = 0;
}
}
if ( c != buffer && ( *( c - 1 ) != '\n' ) ) {
*c++ = '\n';
}
*c = '\0';
}