mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-12-11 13:11:55 +00:00
9fcb2bb336
Override the video mode list in the Team Arena data files with detected modes from SDL like in ioquake3's Q3 UI. Add the aspect ratio to the end of the video resolution (i.e., "640x480 (4:3)"). Add the current (custom) video mode to the list. Before when using a custom resolution in the menu you could not change the video mode using the mouse because the resolution text was blank. Now custom video resolution is displayed and can be clicked.
6066 lines
153 KiB
C
6066 lines
153 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
|
|
This file is part of Quake III Arena source code.
|
|
|
|
Quake III Arena source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
Quake III Arena source code is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Quake III Arena source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
//
|
|
// string allocation/management
|
|
|
|
#include "ui_shared.h"
|
|
|
|
#define SCROLL_TIME_START 500
|
|
#define SCROLL_TIME_ADJUST 150
|
|
#define SCROLL_TIME_ADJUSTOFFSET 40
|
|
#define SCROLL_TIME_FLOOR 20
|
|
|
|
typedef struct scrollInfo_s {
|
|
int nextScrollTime;
|
|
int nextAdjustTime;
|
|
int adjustValue;
|
|
int scrollKey;
|
|
float xStart;
|
|
float yStart;
|
|
itemDef_t *item;
|
|
qboolean scrollDir;
|
|
} scrollInfo_t;
|
|
|
|
static scrollInfo_t scrollInfo;
|
|
|
|
static void (*captureFunc) (void *p) = 0;
|
|
static void *captureData = NULL;
|
|
static itemDef_t *itemCapture = NULL; // item that has the mouse captured ( if any )
|
|
|
|
displayContextDef_t *DC = NULL;
|
|
|
|
static qboolean g_waitingForKey = qfalse;
|
|
static qboolean g_editingField = qfalse;
|
|
|
|
static itemDef_t *g_bindItem = NULL;
|
|
static itemDef_t *g_editItem = NULL;
|
|
|
|
menuDef_t Menus[MAX_MENUS]; // defined menus
|
|
int menuCount = 0; // how many
|
|
|
|
menuDef_t *menuStack[MAX_OPEN_MENUS];
|
|
int openMenuCount = 0;
|
|
|
|
static qboolean debugMode = qfalse;
|
|
|
|
#define DOUBLE_CLICK_DELAY 300
|
|
static int lastListBoxClickTime = 0;
|
|
|
|
void Item_RunScript(itemDef_t *item, const char *s);
|
|
void Item_SetupKeywordHash(void);
|
|
void Menu_SetupKeywordHash(void);
|
|
int BindingIDFromName(const char *name);
|
|
qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down);
|
|
itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu);
|
|
itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu);
|
|
static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y);
|
|
|
|
#ifdef CGAME
|
|
#define MEM_POOL_SIZE 128 * 1024
|
|
#else
|
|
#define MEM_POOL_SIZE 1024 * 1024
|
|
#endif
|
|
|
|
static char memoryPool[MEM_POOL_SIZE];
|
|
static int allocPoint, outOfMemory;
|
|
|
|
|
|
/*
|
|
===============
|
|
UI_Alloc
|
|
===============
|
|
*/
|
|
void *UI_Alloc( int size ) {
|
|
char *p;
|
|
|
|
if ( allocPoint + size > MEM_POOL_SIZE ) {
|
|
outOfMemory = qtrue;
|
|
if (DC->Print) {
|
|
DC->Print("UI_Alloc: Failure. Out of memory!\n");
|
|
}
|
|
//DC->trap_Print(S_COLOR_YELLOW"WARNING: UI Out of Memory!\n");
|
|
return NULL;
|
|
}
|
|
|
|
p = &memoryPool[allocPoint];
|
|
|
|
allocPoint += ( size + 15 ) & ~15;
|
|
|
|
return p;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
UI_InitMemory
|
|
===============
|
|
*/
|
|
void UI_InitMemory( void ) {
|
|
allocPoint = 0;
|
|
outOfMemory = qfalse;
|
|
}
|
|
|
|
qboolean UI_OutOfMemory( void ) {
|
|
return outOfMemory;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define HASH_TABLE_SIZE 2048
|
|
/*
|
|
================
|
|
return a hash value for the string
|
|
================
|
|
*/
|
|
static unsigned hashForString(const char *str) {
|
|
int i;
|
|
unsigned hash;
|
|
char letter;
|
|
|
|
hash = 0;
|
|
i = 0;
|
|
while (str[i] != '\0') {
|
|
letter = tolower(str[i]);
|
|
hash+=(unsigned)(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;
|
|
unsigned hash;
|
|
stringDef_t *str, *last;
|
|
static const char *staticNULL = "";
|
|
|
|
if (p == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (*p == 0) {
|
|
return staticNULL;
|
|
}
|
|
|
|
hash = hashForString(p);
|
|
|
|
str = strHandle[hash];
|
|
while (str) {
|
|
if (strcmp(p, str->str) == 0) {
|
|
return str->str;
|
|
}
|
|
str = str->next;
|
|
}
|
|
|
|
len = strlen(p);
|
|
if (len + strPoolIndex + 1 < STRING_POOL_SIZE) {
|
|
int ph = strPoolIndex;
|
|
strcpy(&strPool[strPoolIndex], p);
|
|
strPoolIndex += len + 1;
|
|
|
|
str = strHandle[hash];
|
|
last = str;
|
|
while (str && str->next) {
|
|
last = str;
|
|
str = str->next;
|
|
}
|
|
|
|
str = UI_Alloc(sizeof(stringDef_t));
|
|
if (!str) {
|
|
return NULL;
|
|
}
|
|
str->next = NULL;
|
|
str->str = &strPool[ph];
|
|
if (last) {
|
|
last->next = str;
|
|
} else {
|
|
strHandle[hash] = str;
|
|
}
|
|
return &strPool[ph];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void String_Report(void) {
|
|
float f;
|
|
Com_Printf("Memory/String Pool Info\n");
|
|
Com_Printf("----------------\n");
|
|
f = strPoolIndex;
|
|
f /= STRING_POOL_SIZE;
|
|
f *= 100;
|
|
Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE);
|
|
f = allocPoint;
|
|
f /= MEM_POOL_SIZE;
|
|
f *= 100;
|
|
Com_Printf("Memory Pool is %.1f%% full, %i bytes out of %i used.\n", f, allocPoint, MEM_POOL_SIZE);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
String_Init
|
|
=================
|
|
*/
|
|
void String_Init(void) {
|
|
int i;
|
|
for (i = 0; i < HASH_TABLE_SIZE; i++) {
|
|
strHandle[i] = NULL;
|
|
}
|
|
strHandleCount = 0;
|
|
strPoolIndex = 0;
|
|
menuCount = 0;
|
|
openMenuCount = 0;
|
|
UI_InitMemory();
|
|
Item_SetupKeywordHash();
|
|
Menu_SetupKeywordHash();
|
|
if (DC && DC->getBindingBuf) {
|
|
Controls_GetConfig();
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
=================
|
|
PC_SourceWarning
|
|
=================
|
|
*/
|
|
static __attribute__ ((format (printf, 2, 3))) void PC_SourceWarning(int handle, char *format, ...) {
|
|
int line;
|
|
char filename[128];
|
|
va_list argptr;
|
|
static char string[4096];
|
|
|
|
va_start (argptr, format);
|
|
Q_vsnprintf (string, sizeof(string), format, argptr);
|
|
va_end (argptr);
|
|
|
|
filename[0] = '\0';
|
|
line = 0;
|
|
trap_PC_SourceFileAndLine(handle, filename, &line);
|
|
|
|
Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
=================
|
|
PC_SourceError
|
|
=================
|
|
*/
|
|
static __attribute__ ((format (printf, 2, 3))) void PC_SourceError(int handle, char *format, ...) {
|
|
int line;
|
|
char filename[128];
|
|
va_list argptr;
|
|
static char string[4096];
|
|
|
|
va_start (argptr, format);
|
|
Q_vsnprintf (string, sizeof(string), format, argptr);
|
|
va_end (argptr);
|
|
|
|
filename[0] = '\0';
|
|
line = 0;
|
|
trap_PC_SourceFileAndLine(handle, filename, &line);
|
|
|
|
Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
LerpColor
|
|
=================
|
|
*/
|
|
void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
|
|
{
|
|
int i;
|
|
|
|
// lerp and clamp each component
|
|
for (i=0; i<4; i++)
|
|
{
|
|
c[i] = a[i] + t*(b[i]-a[i]);
|
|
if (c[i] < 0)
|
|
c[i] = 0;
|
|
else if (c[i] > 1.0)
|
|
c[i] = 1.0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Float_Parse
|
|
=================
|
|
*/
|
|
qboolean Float_Parse(char **p, float *f) {
|
|
char *token;
|
|
token = COM_ParseExt(p, qfalse);
|
|
if (token && token[0] != 0) {
|
|
*f = atof(token);
|
|
return qtrue;
|
|
} else {
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PC_Float_Parse
|
|
=================
|
|
*/
|
|
qboolean PC_Float_Parse(int handle, float *f) {
|
|
pc_token_t token;
|
|
int negative = qfalse;
|
|
|
|
if (!trap_PC_ReadToken(handle, &token))
|
|
return qfalse;
|
|
if (token.string[0] == '-') {
|
|
if (!trap_PC_ReadToken(handle, &token))
|
|
return qfalse;
|
|
negative = qtrue;
|
|
}
|
|
if (token.type != TT_NUMBER) {
|
|
PC_SourceError(handle, "expected float but found %s", token.string);
|
|
return qfalse;
|
|
}
|
|
if (negative)
|
|
*f = -token.floatvalue;
|
|
else
|
|
*f = token.floatvalue;
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Color_Parse
|
|
=================
|
|
*/
|
|
qboolean Color_Parse(char **p, vec4_t *c) {
|
|
int i;
|
|
float f;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (!Float_Parse(p, &f)) {
|
|
return qfalse;
|
|
}
|
|
(*c)[i] = f;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PC_Color_Parse
|
|
=================
|
|
*/
|
|
qboolean PC_Color_Parse(int handle, vec4_t *c) {
|
|
int i;
|
|
float f;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (!PC_Float_Parse(handle, &f)) {
|
|
return qfalse;
|
|
}
|
|
(*c)[i] = f;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Int_Parse
|
|
=================
|
|
*/
|
|
qboolean Int_Parse(char **p, int *i) {
|
|
char *token;
|
|
token = COM_ParseExt(p, qfalse);
|
|
|
|
if (token && token[0] != 0) {
|
|
*i = atoi(token);
|
|
return qtrue;
|
|
} else {
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PC_Int_Parse
|
|
=================
|
|
*/
|
|
qboolean PC_Int_Parse(int handle, int *i) {
|
|
pc_token_t token;
|
|
int negative = qfalse;
|
|
|
|
if (!i)
|
|
return qfalse;
|
|
if (!trap_PC_ReadToken(handle, &token))
|
|
return qfalse;
|
|
if (token.string[0] == '-') {
|
|
if (!trap_PC_ReadToken(handle, &token))
|
|
return qfalse;
|
|
negative = qtrue;
|
|
}
|
|
if (token.type != TT_NUMBER) {
|
|
PC_SourceError(handle, "expected integer but found %s", token.string);
|
|
return qfalse;
|
|
}
|
|
*i = token.intvalue;
|
|
if (negative)
|
|
*i = - *i;
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Rect_Parse
|
|
=================
|
|
*/
|
|
qboolean Rect_Parse(char **p, rectDef_t *r) {
|
|
if (Float_Parse(p, &r->x)) {
|
|
if (Float_Parse(p, &r->y)) {
|
|
if (Float_Parse(p, &r->w)) {
|
|
if (Float_Parse(p, &r->h)) {
|
|
return qtrue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PC_Rect_Parse
|
|
=================
|
|
*/
|
|
qboolean PC_Rect_Parse(int handle, rectDef_t *r) {
|
|
if (PC_Float_Parse(handle, &r->x)) {
|
|
if (PC_Float_Parse(handle, &r->y)) {
|
|
if (PC_Float_Parse(handle, &r->w)) {
|
|
if (PC_Float_Parse(handle, &r->h)) {
|
|
return qtrue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
String_Parse
|
|
=================
|
|
*/
|
|
qboolean String_Parse(char **p, const char **out) {
|
|
char *token;
|
|
|
|
token = COM_ParseExt(p, qfalse);
|
|
if (token && token[0] != 0) {
|
|
*(out) = String_Alloc(token);
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PC_String_Parse
|
|
=================
|
|
*/
|
|
qboolean PC_String_Parse(int handle, const char **out) {
|
|
pc_token_t token;
|
|
|
|
if (!trap_PC_ReadToken(handle, &token))
|
|
return qfalse;
|
|
|
|
*(out) = String_Alloc(token.string);
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
PC_Script_Parse
|
|
=================
|
|
*/
|
|
qboolean PC_Script_Parse(int handle, const char **out) {
|
|
char script[1024];
|
|
pc_token_t token;
|
|
|
|
memset(script, 0, sizeof(script));
|
|
// scripts start with { and have ; separated command lists.. commands are command, arg..
|
|
// basically we want everything between the { } as it will be interpreted at run time
|
|
|
|
if (!trap_PC_ReadToken(handle, &token))
|
|
return qfalse;
|
|
if (Q_stricmp(token.string, "{") != 0) {
|
|
return qfalse;
|
|
}
|
|
|
|
while ( 1 ) {
|
|
if (!trap_PC_ReadToken(handle, &token))
|
|
return qfalse;
|
|
|
|
if (Q_stricmp(token.string, "}") == 0) {
|
|
*out = String_Alloc(script);
|
|
return qtrue;
|
|
}
|
|
|
|
if (token.string[1] != '\0') {
|
|
Q_strcat(script, 1024, va("\"%s\"", token.string));
|
|
} else {
|
|
Q_strcat(script, 1024, token.string);
|
|
}
|
|
Q_strcat(script, 1024, " ");
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
// 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 = {0};
|
|
rectDef_t fillRect;
|
|
|
|
if ( w == NULL ) {
|
|
return;
|
|
}
|
|
|
|
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->style == 0 && w->border == 0) {
|
|
return;
|
|
}
|
|
|
|
fillRect = w->rect;
|
|
|
|
if (w->border != 0) {
|
|
fillRect.x += w->borderSize;
|
|
fillRect.y += w->borderSize;
|
|
fillRect.w -= w->borderSize + 1;
|
|
fillRect.h -= w->borderSize + 1;
|
|
}
|
|
|
|
if (w->style == WINDOW_STYLE_FILLED) {
|
|
// box, but possible a shader that needs filled
|
|
if (w->background) {
|
|
Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount);
|
|
DC->setColor(w->backColor);
|
|
DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
|
|
DC->setColor(NULL);
|
|
} else {
|
|
DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor);
|
|
}
|
|
} else if (w->style == WINDOW_STYLE_GRADIENT) {
|
|
GradientBar_Paint(&fillRect, w->backColor);
|
|
// gradient bar
|
|
} else if (w->style == WINDOW_STYLE_SHADER) {
|
|
if (w->flags & WINDOW_FORECOLORSET) {
|
|
DC->setColor(w->foreColor);
|
|
}
|
|
DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
|
|
DC->setColor(NULL);
|
|
} else if (w->style == WINDOW_STYLE_TEAMCOLOR) {
|
|
if (DC->getTeamColor) {
|
|
DC->getTeamColor(&color);
|
|
DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, color);
|
|
}
|
|
} else if (w->style == WINDOW_STYLE_CINEMATIC) {
|
|
if (w->cinematic == -1) {
|
|
w->cinematic = DC->playCinematic(w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
|
|
if (w->cinematic == -1) {
|
|
w->cinematic = -2;
|
|
}
|
|
}
|
|
if (w->cinematic >= 0) {
|
|
DC->runCinematicFrame(w->cinematic);
|
|
DC->drawCinematic(w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
|
|
}
|
|
}
|
|
|
|
if (w->border == WINDOW_BORDER_FULL) {
|
|
// full
|
|
// HACK HACK HACK
|
|
if (w->style == WINDOW_STYLE_TEAMCOLOR) {
|
|
if (color[0] > 0) {
|
|
// red
|
|
color[0] = 1;
|
|
color[1] = color[2] = .5;
|
|
|
|
} else {
|
|
color[2] = 1;
|
|
color[0] = color[1] = .5;
|
|
}
|
|
color[3] = 1;
|
|
DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, color);
|
|
} else {
|
|
DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor);
|
|
}
|
|
} else if (w->border == WINDOW_BORDER_HORZ) {
|
|
// top/bottom
|
|
DC->setColor(w->borderColor);
|
|
DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
|
|
DC->setColor( NULL );
|
|
} else if (w->border == WINDOW_BORDER_VERT) {
|
|
// left right
|
|
DC->setColor(w->borderColor);
|
|
DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
|
|
DC->setColor( NULL );
|
|
} else if (w->border == WINDOW_BORDER_KCGRADIENT) {
|
|
// this is just two gradient bars along each horz edge
|
|
rectDef_t r = w->rect;
|
|
r.h = w->borderSize;
|
|
GradientBar_Paint(&r, w->borderColor);
|
|
r.y = w->rect.y + w->rect.h - 1;
|
|
GradientBar_Paint(&r, w->borderColor);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void Item_SetScreenCoords(itemDef_t *item, float x, float y) {
|
|
|
|
if (item == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (item->window.border != 0) {
|
|
x += item->window.borderSize;
|
|
y += item->window.borderSize;
|
|
}
|
|
|
|
item->window.rect.x = x + item->window.rectClient.x;
|
|
item->window.rect.y = y + item->window.rectClient.y;
|
|
item->window.rect.w = item->window.rectClient.w;
|
|
item->window.rect.h = item->window.rectClient.h;
|
|
|
|
// force the text rects to recompute
|
|
item->textRect.w = 0;
|
|
item->textRect.h = 0;
|
|
}
|
|
|
|
// FIXME: consolidate this with nearby stuff
|
|
void Item_UpdatePosition(itemDef_t *item) {
|
|
float x, y;
|
|
menuDef_t *menu;
|
|
|
|
if (item == NULL || item->parent == NULL) {
|
|
return;
|
|
}
|
|
|
|
menu = item->parent;
|
|
|
|
x = menu->window.rect.x;
|
|
y = menu->window.rect.y;
|
|
|
|
if (menu->window.border != 0) {
|
|
x += menu->window.borderSize;
|
|
y += menu->window.borderSize;
|
|
}
|
|
|
|
Item_SetScreenCoords(item, x, y);
|
|
|
|
}
|
|
|
|
// menus
|
|
void Menu_UpdatePosition(menuDef_t *menu) {
|
|
int i;
|
|
float x, y;
|
|
|
|
if (menu == NULL) {
|
|
return;
|
|
}
|
|
|
|
x = menu->window.rect.x;
|
|
y = menu->window.rect.y;
|
|
if (menu->window.border != 0) {
|
|
x += menu->window.borderSize;
|
|
y += menu->window.borderSize;
|
|
}
|
|
|
|
for (i = 0; i < menu->itemCount; i++) {
|
|
Item_SetScreenCoords(menu->items[i], x, y);
|
|
}
|
|
}
|
|
|
|
void Menu_PostParse(menuDef_t *menu) {
|
|
if (menu == NULL) {
|
|
return;
|
|
}
|
|
if (menu->fullScreen) {
|
|
menu->window.rect.x = 0;
|
|
menu->window.rect.y = 0;
|
|
menu->window.rect.w = 640;
|
|
menu->window.rect.h = 480;
|
|
}
|
|
Menu_UpdatePosition(menu);
|
|
}
|
|
|
|
itemDef_t *Menu_ClearFocus(menuDef_t *menu) {
|
|
int i;
|
|
itemDef_t *ret = NULL;
|
|
|
|
if (menu == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < menu->itemCount; i++) {
|
|
if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
|
|
ret = menu->items[i];
|
|
}
|
|
menu->items[i]->window.flags &= ~WINDOW_HASFOCUS;
|
|
if (menu->items[i]->leaveFocus) {
|
|
Item_RunScript(menu->items[i], menu->items[i]->leaveFocus);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
qboolean IsVisible(int flags) {
|
|
return (flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT));
|
|
}
|
|
|
|
qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) {
|
|
if (rect) {
|
|
if (x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h) {
|
|
return qtrue;
|
|
}
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name) {
|
|
int i;
|
|
int count = 0;
|
|
for (i = 0; i < menu->itemCount; i++) {
|
|
if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name) {
|
|
int i;
|
|
int count = 0;
|
|
for (i = 0; i < menu->itemCount; i++) {
|
|
if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
|
|
if (count == index) {
|
|
return menu->items[i];
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
void Script_SetColor(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
int i;
|
|
float f;
|
|
vec4_t *out;
|
|
// expecting type of color to set and 4 args for the color
|
|
if (String_Parse(args, &name)) {
|
|
out = NULL;
|
|
if (Q_stricmp(name, "backcolor") == 0) {
|
|
out = &item->window.backColor;
|
|
item->window.flags |= WINDOW_BACKCOLORSET;
|
|
} else if (Q_stricmp(name, "forecolor") == 0) {
|
|
out = &item->window.foreColor;
|
|
item->window.flags |= WINDOW_FORECOLORSET;
|
|
} else if (Q_stricmp(name, "bordercolor") == 0) {
|
|
out = &item->window.borderColor;
|
|
}
|
|
|
|
if (out) {
|
|
for (i = 0; i < 4; i++) {
|
|
if (!Float_Parse(args, &f)) {
|
|
return;
|
|
}
|
|
(*out)[i] = f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Script_SetAsset(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
// expecting name to set asset to
|
|
if (String_Parse(args, &name)) {
|
|
// check for a model
|
|
if (item->type == ITEM_TYPE_MODEL) {
|
|
}
|
|
}
|
|
}
|
|
|
|
void Script_SetBackground(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
// expecting name to set asset to
|
|
if (String_Parse(args, &name)) {
|
|
item->window.background = DC->registerShaderNoMip(name);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) {
|
|
int i;
|
|
if (menu == NULL || p == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < menu->itemCount; i++) {
|
|
if (Q_stricmp(p, menu->items[i]->window.name) == 0) {
|
|
return menu->items[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void Script_SetTeamColor(itemDef_t *item, char **args) {
|
|
if (DC->getTeamColor) {
|
|
int i;
|
|
vec4_t color;
|
|
DC->getTeamColor(&color);
|
|
for (i = 0; i < 4; i++) {
|
|
item->window.backColor[i] = color[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
void Script_SetItemColor(itemDef_t *item, char **args) {
|
|
const char *itemname;
|
|
const char *name;
|
|
vec4_t color;
|
|
int i;
|
|
vec4_t *out;
|
|
// expecting type of color to set and 4 args for the color
|
|
if (String_Parse(args, &itemname) && String_Parse(args, &name)) {
|
|
itemDef_t *item2;
|
|
int j;
|
|
int count = Menu_ItemsMatchingGroup(item->parent, itemname);
|
|
|
|
if (!Color_Parse(args, &color)) {
|
|
return;
|
|
}
|
|
|
|
for (j = 0; j < count; j++) {
|
|
item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname);
|
|
if (item2 != NULL) {
|
|
out = NULL;
|
|
if (Q_stricmp(name, "backcolor") == 0) {
|
|
out = &item2->window.backColor;
|
|
} else if (Q_stricmp(name, "forecolor") == 0) {
|
|
out = &item2->window.foreColor;
|
|
item2->window.flags |= WINDOW_FORECOLORSET;
|
|
} else if (Q_stricmp(name, "bordercolor") == 0) {
|
|
out = &item2->window.borderColor;
|
|
}
|
|
|
|
if (out) {
|
|
for (i = 0; i < 4; i++) {
|
|
(*out)[i] = color[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow) {
|
|
itemDef_t *item;
|
|
int i;
|
|
int count = Menu_ItemsMatchingGroup(menu, p);
|
|
for (i = 0; i < count; i++) {
|
|
item = Menu_GetMatchingItemByNumber(menu, i, p);
|
|
if (item != NULL) {
|
|
if (bShow) {
|
|
item->window.flags |= WINDOW_VISIBLE;
|
|
} else {
|
|
item->window.flags &= ~WINDOW_VISIBLE;
|
|
// stop cinematics playing in the window
|
|
if (item->window.cinematic >= 0) {
|
|
DC->stopCinematic(item->window.cinematic);
|
|
item->window.cinematic = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut) {
|
|
itemDef_t *item;
|
|
int i;
|
|
int count = Menu_ItemsMatchingGroup(menu, p);
|
|
for (i = 0; i < count; i++) {
|
|
item = Menu_GetMatchingItemByNumber(menu, i, p);
|
|
if (item != NULL) {
|
|
if (fadeOut) {
|
|
item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE);
|
|
item->window.flags &= ~WINDOW_FADINGIN;
|
|
} else {
|
|
item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN);
|
|
item->window.flags &= ~WINDOW_FADINGOUT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
menuDef_t *Menus_FindByName(const char *p) {
|
|
int i;
|
|
for (i = 0; i < menuCount; i++) {
|
|
if (Q_stricmp(Menus[i].window.name, p) == 0) {
|
|
return &Menus[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void Menus_ShowByName(const char *p) {
|
|
menuDef_t *menu = Menus_FindByName(p);
|
|
if (menu) {
|
|
Menus_Activate(menu);
|
|
}
|
|
}
|
|
|
|
void Menus_OpenByName(const char *p) {
|
|
Menus_ActivateByName(p);
|
|
}
|
|
|
|
static void Menu_RunCloseScript(menuDef_t *menu) {
|
|
if (menu && menu->window.flags & WINDOW_VISIBLE && menu->onClose) {
|
|
itemDef_t item;
|
|
item.parent = menu;
|
|
Item_RunScript(&item, menu->onClose);
|
|
}
|
|
}
|
|
|
|
void Menus_CloseByName(const char *p) {
|
|
menuDef_t *menu = Menus_FindByName(p);
|
|
if (menu != NULL) {
|
|
Menu_RunCloseScript(menu);
|
|
menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS);
|
|
}
|
|
}
|
|
|
|
void Menus_CloseAll(void) {
|
|
int i;
|
|
for (i = 0; i < menuCount; i++) {
|
|
Menu_RunCloseScript(&Menus[i]);
|
|
Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
|
|
}
|
|
}
|
|
|
|
|
|
void Script_Show(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
if (String_Parse(args, &name)) {
|
|
Menu_ShowItemByName(item->parent, name, qtrue);
|
|
}
|
|
}
|
|
|
|
void Script_Hide(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
if (String_Parse(args, &name)) {
|
|
Menu_ShowItemByName(item->parent, name, qfalse);
|
|
}
|
|
}
|
|
|
|
void Script_FadeIn(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
if (String_Parse(args, &name)) {
|
|
Menu_FadeItemByName(item->parent, name, qfalse);
|
|
}
|
|
}
|
|
|
|
void Script_FadeOut(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
if (String_Parse(args, &name)) {
|
|
Menu_FadeItemByName(item->parent, name, qtrue);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Script_Open(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
if (String_Parse(args, &name)) {
|
|
Menus_OpenByName(name);
|
|
}
|
|
}
|
|
|
|
void Script_ConditionalOpen(itemDef_t *item, char **args) {
|
|
const char *cvar;
|
|
const char *name1;
|
|
const char *name2;
|
|
float val;
|
|
|
|
if ( String_Parse(args, &cvar) && String_Parse(args, &name1) && String_Parse(args, &name2) ) {
|
|
val = DC->getCVarValue( cvar );
|
|
if ( val == 0.f ) {
|
|
Menus_OpenByName(name2);
|
|
} else {
|
|
Menus_OpenByName(name1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Script_Close(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
if (String_Parse(args, &name)) {
|
|
Menus_CloseByName(name);
|
|
}
|
|
}
|
|
|
|
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 = fabs(rectTo.x - rectFrom.x) / amt;
|
|
item->window.rectEffects2.y = fabs(rectTo.y - rectFrom.y) / amt;
|
|
item->window.rectEffects2.w = fabs(rectTo.w - rectFrom.w) / amt;
|
|
item->window.rectEffects2.h = fabs(rectTo.h - rectFrom.h) / amt;
|
|
Item_UpdatePosition(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Script_Transition(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
rectDef_t rectFrom, rectTo;
|
|
int time;
|
|
float amt;
|
|
|
|
if (String_Parse(args, &name)) {
|
|
if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) {
|
|
Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) {
|
|
itemDef_t *item;
|
|
int i;
|
|
int count = Menu_ItemsMatchingGroup(menu, p);
|
|
for (i = 0; i < count; i++) {
|
|
item = Menu_GetMatchingItemByNumber(menu, i, p);
|
|
if (item != NULL) {
|
|
item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE);
|
|
item->window.offsetTime = time;
|
|
item->window.rectEffects.x = cx;
|
|
item->window.rectEffects.y = cy;
|
|
item->window.rectClient.x = x;
|
|
item->window.rectClient.y = y;
|
|
Item_UpdatePosition(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Script_Orbit(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
float cx, cy, x, y;
|
|
int time;
|
|
|
|
if (String_Parse(args, &name)) {
|
|
if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) {
|
|
Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Script_SetFocus(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
itemDef_t *focusItem;
|
|
|
|
if (String_Parse(args, &name)) {
|
|
focusItem = Menu_FindItemByName(item->parent, name);
|
|
if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION) && !(focusItem->window.flags & WINDOW_HASFOCUS)) {
|
|
Menu_ClearFocus(item->parent);
|
|
focusItem->window.flags |= WINDOW_HASFOCUS;
|
|
if (focusItem->onFocus) {
|
|
Item_RunScript(focusItem, focusItem->onFocus);
|
|
}
|
|
if (DC->Assets.itemFocusSound) {
|
|
DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Script_SetPlayerModel(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
if (String_Parse(args, &name)) {
|
|
DC->setCVar("team_model", name);
|
|
}
|
|
}
|
|
|
|
void Script_SetPlayerHead(itemDef_t *item, char **args) {
|
|
const char *name;
|
|
if (String_Parse(args, &name)) {
|
|
DC->setCVar("team_headmodel", name);
|
|
}
|
|
}
|
|
|
|
void Script_SetCvar(itemDef_t *item, char **args) {
|
|
const char *cvar, *val;
|
|
if (String_Parse(args, &cvar) && String_Parse(args, &val)) {
|
|
DC->setCVar(cvar, val);
|
|
}
|
|
|
|
}
|
|
|
|
void Script_Exec(itemDef_t *item, char **args) {
|
|
const char *val;
|
|
if (String_Parse(args, &val)) {
|
|
DC->executeText(EXEC_APPEND, va("%s ; ", val));
|
|
}
|
|
}
|
|
|
|
void Script_Play(itemDef_t *item, char **args) {
|
|
const char *val;
|
|
if (String_Parse(args, &val)) {
|
|
DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_LOCAL_SOUND);
|
|
}
|
|
}
|
|
|
|
void Script_playLooped(itemDef_t *item, char **args) {
|
|
const char *val;
|
|
if (String_Parse(args, &val)) {
|
|
DC->stopBackgroundTrack();
|
|
DC->startBackgroundTrack(val, val);
|
|
}
|
|
}
|
|
|
|
|
|
commandDef_t commandList[] =
|
|
{
|
|
{"fadein", &Script_FadeIn}, // group/name
|
|
{"fadeout", &Script_FadeOut}, // group/name
|
|
{"show", &Script_Show}, // group/name
|
|
{"hide", &Script_Hide}, // group/name
|
|
{"setcolor", &Script_SetColor}, // works on this
|
|
{"open", &Script_Open}, // menu
|
|
{"conditionalopen", &Script_ConditionalOpen}, // menu
|
|
{"close", &Script_Close}, // menu
|
|
{"setasset", &Script_SetAsset}, // works on this
|
|
{"setbackground", &Script_SetBackground}, // works on this
|
|
{"setitemcolor", &Script_SetItemColor}, // group/name
|
|
{"setteamcolor", &Script_SetTeamColor}, // sets this background color to team color
|
|
{"setfocus", &Script_SetFocus}, // sets this background color to team color
|
|
{"setplayermodel", &Script_SetPlayerModel}, // sets this background color to team color
|
|
{"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color
|
|
{"transition", &Script_Transition}, // group/name
|
|
{"setcvar", &Script_SetCvar}, // group/name
|
|
{"exec", &Script_Exec}, // group/name
|
|
{"play", &Script_Play}, // group/name
|
|
{"playlooped", &Script_playLooped}, // group/name
|
|
{"orbit", &Script_Orbit} // group/name
|
|
};
|
|
|
|
int scriptCommandCount = ARRAY_LEN(commandList);
|
|
|
|
|
|
void Item_RunScript(itemDef_t *item, const char *s) {
|
|
char script[1024], *p;
|
|
int i;
|
|
qboolean bRan;
|
|
memset(script, 0, sizeof(script));
|
|
if (item && s && s[0]) {
|
|
Q_strcat(script, 1024, s);
|
|
p = script;
|
|
while (1) {
|
|
const char *command;
|
|
// expect command then arguments, ; ends command, NULL ends script
|
|
if (!String_Parse(&p, &command)) {
|
|
return;
|
|
}
|
|
|
|
if (command[0] == ';' && command[1] == '\0') {
|
|
continue;
|
|
}
|
|
|
|
bRan = qfalse;
|
|
for (i = 0; i < scriptCommandCount; i++) {
|
|
if (Q_stricmp(command, commandList[i].name) == 0) {
|
|
(commandList[i].handler(item, &p));
|
|
bRan = qtrue;
|
|
break;
|
|
}
|
|
}
|
|
// not in our auto list, pass to handler
|
|
if (!bRan) {
|
|
DC->runScript(&p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) {
|
|
char script[1024], *p;
|
|
memset(script, 0, sizeof(script));
|
|
if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
|
|
char buff[1024];
|
|
DC->getCVarString(item->cvarTest, buff, sizeof(buff));
|
|
|
|
Q_strcat(script, 1024, item->enableCvar);
|
|
p = script;
|
|
while (1) {
|
|
const char *val;
|
|
// expect value then ; or NULL, NULL ends list
|
|
if (!String_Parse(&p, &val)) {
|
|
return (item->cvarFlags & flag) ? qfalse : qtrue;
|
|
}
|
|
|
|
if (val[0] == ';' && val[1] == '\0') {
|
|
continue;
|
|
}
|
|
|
|
// enable it if any of the values are true
|
|
if (item->cvarFlags & flag) {
|
|
if (Q_stricmp(buff, val) == 0) {
|
|
return qtrue;
|
|
}
|
|
} else {
|
|
// disable it if any of the values are true
|
|
if (Q_stricmp(buff, val) == 0) {
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
}
|
|
return (item->cvarFlags & flag) ? qfalse : qtrue;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
// will optionaly set focus to this item
|
|
qboolean Item_SetFocus(itemDef_t *item, float x, float y) {
|
|
int i;
|
|
itemDef_t *oldFocus;
|
|
sfxHandle_t *sfx = &DC->Assets.itemFocusSound;
|
|
qboolean playSound = qfalse;
|
|
menuDef_t *parent;
|
|
// 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;
|
|
}
|
|
|
|
// this can be NULL
|
|
parent = (menuDef_t*)item->parent;
|
|
|
|
// items can be enabled and disabled based on cvars
|
|
if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
|
|
return qfalse;
|
|
}
|
|
|
|
if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
|
|
return qfalse;
|
|
}
|
|
|
|
oldFocus = Menu_ClearFocus(item->parent);
|
|
|
|
if (item->type == ITEM_TYPE_TEXT) {
|
|
rectDef_t r;
|
|
r = item->textRect;
|
|
r.y -= r.h;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
item->window.flags |= WINDOW_HASFOCUS;
|
|
if (item->focusSound) {
|
|
sfx = &item->focusSound;
|
|
}
|
|
playSound = qtrue;
|
|
} else {
|
|
if (oldFocus) {
|
|
oldFocus->window.flags |= WINDOW_HASFOCUS;
|
|
if (oldFocus->onFocus) {
|
|
Item_RunScript(oldFocus, oldFocus->onFocus);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
item->window.flags |= WINDOW_HASFOCUS;
|
|
if (item->onFocus) {
|
|
Item_RunScript(item, item->onFocus);
|
|
}
|
|
if (item->focusSound) {
|
|
sfx = &item->focusSound;
|
|
}
|
|
playSound = qtrue;
|
|
}
|
|
|
|
if (playSound && sfx) {
|
|
DC->startLocalSound( *sfx, CHAN_LOCAL_SOUND );
|
|
}
|
|
|
|
for (i = 0; i < parent->itemCount; i++) {
|
|
if (parent->items[i] == item) {
|
|
parent->cursorItem = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
int Item_ListBox_MaxScroll(itemDef_t *item) {
|
|
listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
|
|
int count = DC->feederCount(item->special);
|
|
int max;
|
|
|
|
if (item->window.flags & WINDOW_HORIZONTAL) {
|
|
max = count - (item->window.rect.w / listPtr->elementWidth) + 1;
|
|
}
|
|
else {
|
|
max = count - (item->window.rect.h / listPtr->elementHeight) + 1;
|
|
}
|
|
if (max < 0) {
|
|
return 0;
|
|
}
|
|
return max;
|
|
}
|
|
|
|
int Item_ListBox_ThumbPosition(itemDef_t *item) {
|
|
float max, pos, size;
|
|
listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
|
|
|
|
max = Item_ListBox_MaxScroll(item);
|
|
if (item->window.flags & WINDOW_HORIZONTAL) {
|
|
size = item->window.rect.w - (SCROLLBAR_SIZE * 2) - 2;
|
|
if (max > 0) {
|
|
pos = (size-SCROLLBAR_SIZE) / (float) max;
|
|
} else {
|
|
pos = 0;
|
|
}
|
|
pos *= listPtr->startPos;
|
|
return item->window.rect.x + 1 + SCROLLBAR_SIZE + pos;
|
|
}
|
|
else {
|
|
size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2;
|
|
if (max > 0) {
|
|
pos = (size-SCROLLBAR_SIZE) / (float) max;
|
|
} else {
|
|
pos = 0;
|
|
}
|
|
pos *= listPtr->startPos;
|
|
return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos;
|
|
}
|
|
}
|
|
|
|
int Item_ListBox_ThumbDrawPosition(itemDef_t *item) {
|
|
int min, max;
|
|
|
|
if (itemCapture == item) {
|
|
if (item->window.flags & WINDOW_HORIZONTAL) {
|
|
min = item->window.rect.x + SCROLLBAR_SIZE + 1;
|
|
max = item->window.rect.x + item->window.rect.w - 2*SCROLLBAR_SIZE - 1;
|
|
if (DC->cursorx >= min + SCROLLBAR_SIZE/2 && DC->cursorx <= max + SCROLLBAR_SIZE/2) {
|
|
return DC->cursorx - SCROLLBAR_SIZE/2;
|
|
}
|
|
else {
|
|
return Item_ListBox_ThumbPosition(item);
|
|
}
|
|
}
|
|
else {
|
|
min = item->window.rect.y + SCROLLBAR_SIZE + 1;
|
|
max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1;
|
|
if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) {
|
|
return DC->cursory - SCROLLBAR_SIZE/2;
|
|
}
|
|
else {
|
|
return Item_ListBox_ThumbPosition(item);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
return Item_ListBox_ThumbPosition(item);
|
|
}
|
|
}
|
|
|
|
float Item_Slider_ThumbPosition(itemDef_t *item) {
|
|
float value, range, x;
|
|
editFieldDef_t *editDef = item->typeData;
|
|
|
|
if (item->text) {
|
|
x = item->textRect.x + item->textRect.w + 8;
|
|
} else {
|
|
x = item->window.rect.x;
|
|
}
|
|
|
|
if (!editDef || !item->cvar) {
|
|
return x;
|
|
}
|
|
|
|
value = DC->getCVarValue(item->cvar);
|
|
|
|
if (value < editDef->minVal) {
|
|
value = editDef->minVal;
|
|
} else if (value > editDef->maxVal) {
|
|
value = editDef->maxVal;
|
|
}
|
|
|
|
range = editDef->maxVal - editDef->minVal;
|
|
value -= editDef->minVal;
|
|
value /= range;
|
|
//value /= (editDef->maxVal - editDef->minVal);
|
|
value *= SLIDER_WIDTH;
|
|
x += value;
|
|
// vm fuckage
|
|
//x = x + (((float)value / editDef->maxVal) * SLIDER_WIDTH);
|
|
return x;
|
|
}
|
|
|
|
int Item_Slider_OverSlider(itemDef_t *item, float x, float y) {
|
|
rectDef_t r;
|
|
|
|
r.x = Item_Slider_ThumbPosition(item) - (SLIDER_THUMB_WIDTH / 2);
|
|
r.y = item->window.rect.y - 2;
|
|
r.w = SLIDER_THUMB_WIDTH;
|
|
r.h = SLIDER_THUMB_HEIGHT;
|
|
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_THUMB;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Item_ListBox_OverLB(itemDef_t *item, float x, float y) {
|
|
rectDef_t r;
|
|
int thumbstart;
|
|
|
|
if (item->window.flags & WINDOW_HORIZONTAL) {
|
|
// check if on left arrow
|
|
r.x = item->window.rect.x;
|
|
r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
|
|
r.h = r.w = SCROLLBAR_SIZE;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_LEFTARROW;
|
|
}
|
|
// check if on right arrow
|
|
r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_RIGHTARROW;
|
|
}
|
|
// check if on thumb
|
|
thumbstart = Item_ListBox_ThumbPosition(item);
|
|
r.x = thumbstart;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_THUMB;
|
|
}
|
|
r.x = item->window.rect.x + SCROLLBAR_SIZE;
|
|
r.w = thumbstart - r.x;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_PGUP;
|
|
}
|
|
r.x = thumbstart + SCROLLBAR_SIZE;
|
|
r.w = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_PGDN;
|
|
}
|
|
} else {
|
|
r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
|
|
r.y = item->window.rect.y;
|
|
r.h = r.w = SCROLLBAR_SIZE;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_LEFTARROW;
|
|
}
|
|
r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_RIGHTARROW;
|
|
}
|
|
thumbstart = Item_ListBox_ThumbPosition(item);
|
|
r.y = thumbstart;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_THUMB;
|
|
}
|
|
r.y = item->window.rect.y + SCROLLBAR_SIZE;
|
|
r.h = thumbstart - r.y;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_PGUP;
|
|
}
|
|
r.y = thumbstart + SCROLLBAR_SIZE;
|
|
r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
return WINDOW_LB_PGDN;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y)
|
|
{
|
|
rectDef_t r;
|
|
listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
|
|
|
|
item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
|
|
item->window.flags |= Item_ListBox_OverLB(item, x, y);
|
|
|
|
if (item->window.flags & WINDOW_HORIZONTAL) {
|
|
if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
|
|
// check for selection hit as we have exausted buttons and thumb
|
|
if (listPtr->elementStyle == LISTBOX_IMAGE) {
|
|
r.x = item->window.rect.x;
|
|
r.y = item->window.rect.y;
|
|
r.h = item->window.rect.h - SCROLLBAR_SIZE;
|
|
r.w = item->window.rect.w - listPtr->drawPadding;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
listPtr->cursorPos = (int)((x - r.x) / listPtr->elementWidth) + listPtr->startPos;
|
|
if (listPtr->cursorPos >= listPtr->endPos) {
|
|
listPtr->cursorPos = listPtr->endPos;
|
|
}
|
|
}
|
|
} else {
|
|
// text hit..
|
|
}
|
|
}
|
|
} else if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
|
|
r.x = item->window.rect.x;
|
|
r.y = item->window.rect.y;
|
|
r.w = item->window.rect.w - SCROLLBAR_SIZE;
|
|
r.h = item->window.rect.h - listPtr->drawPadding;
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
listPtr->cursorPos = (int)((y - 2 - r.y) / listPtr->elementHeight) + listPtr->startPos;
|
|
if (listPtr->cursorPos > listPtr->endPos) {
|
|
listPtr->cursorPos = listPtr->endPos;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Item_MouseEnter(itemDef_t *item, float x, float y) {
|
|
rectDef_t r;
|
|
if (item) {
|
|
r = item->textRect;
|
|
r.y -= r.h;
|
|
// in the text rect?
|
|
|
|
// items can be enabled and disabled based on cvars
|
|
if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
|
|
return;
|
|
}
|
|
|
|
if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
|
|
return;
|
|
}
|
|
|
|
if (Rect_ContainsPoint(&r, x, y)) {
|
|
if (!(item->window.flags & WINDOW_MOUSEOVERTEXT)) {
|
|
Item_RunScript(item, item->mouseEnterText);
|
|
item->window.flags |= WINDOW_MOUSEOVERTEXT;
|
|
}
|
|
if (!(item->window.flags & WINDOW_MOUSEOVER)) {
|
|
Item_RunScript(item, item->mouseEnter);
|
|
item->window.flags |= WINDOW_MOUSEOVER;
|
|
}
|
|
|
|
} else {
|
|
// not in the text rect
|
|
if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
|
|
// if we were
|
|
Item_RunScript(item, item->mouseExitText);
|
|
item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
|
|
}
|
|
if (!(item->window.flags & WINDOW_MOUSEOVER)) {
|
|
Item_RunScript(item, item->mouseEnter);
|
|
item->window.flags |= WINDOW_MOUSEOVER;
|
|
}
|
|
|
|
if (item->type == ITEM_TYPE_LISTBOX) {
|
|
Item_ListBox_MouseEnter(item, x, y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Item_MouseLeave(itemDef_t *item) {
|
|
if (item) {
|
|
if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
|
|
Item_RunScript(item, item->mouseExitText);
|
|
item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
|
|
}
|
|
Item_RunScript(item, item->mouseExit);
|
|
item->window.flags &= ~(WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW);
|
|
}
|
|
}
|
|
|
|
itemDef_t *Menu_HitTest(menuDef_t *menu, float x, float y) {
|
|
int i;
|
|
for (i = 0; i < menu->itemCount; i++) {
|
|
if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
|
|
return menu->items[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void Item_SetMouseOver(itemDef_t *item, qboolean focus) {
|
|
if (item) {
|
|
if (focus) {
|
|
item->window.flags |= WINDOW_MOUSEOVER;
|
|
} else {
|
|
item->window.flags &= ~WINDOW_MOUSEOVER;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) {
|
|
if (item && DC->ownerDrawHandleKey) {
|
|
return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key);
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force) {
|
|
listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
|
|
int count = DC->feederCount(item->special);
|
|
int max, viewmax;
|
|
|
|
if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) {
|
|
max = Item_ListBox_MaxScroll(item);
|
|
if (item->window.flags & WINDOW_HORIZONTAL) {
|
|
viewmax = (item->window.rect.w / listPtr->elementWidth);
|
|
if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
|
|
{
|
|
if (!listPtr->notselectable) {
|
|
listPtr->cursorPos--;
|
|
if (listPtr->cursorPos < 0) {
|
|
listPtr->cursorPos = 0;
|
|
}
|
|
if (listPtr->cursorPos < listPtr->startPos) {
|
|
listPtr->startPos = listPtr->cursorPos;
|
|
}
|
|
if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
|
|
listPtr->startPos = listPtr->cursorPos - viewmax + 1;
|
|
}
|
|
item->cursorPos = listPtr->cursorPos;
|
|
DC->feederSelection(item->special, item->cursorPos);
|
|
}
|
|
else {
|
|
listPtr->startPos--;
|
|
if (listPtr->startPos < 0)
|
|
listPtr->startPos = 0;
|
|
}
|
|
return qtrue;
|
|
}
|
|
if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
|
|
{
|
|
if (!listPtr->notselectable) {
|
|
listPtr->cursorPos++;
|
|
if (listPtr->cursorPos < listPtr->startPos) {
|
|
listPtr->startPos = listPtr->cursorPos;
|
|
}
|
|
if (listPtr->cursorPos >= count) {
|
|
listPtr->cursorPos = count-1;
|
|
}
|
|
if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
|
|
listPtr->startPos = listPtr->cursorPos - viewmax + 1;
|
|
}
|
|
item->cursorPos = listPtr->cursorPos;
|
|
DC->feederSelection(item->special, item->cursorPos);
|
|
}
|
|
else {
|
|
listPtr->startPos++;
|
|
if (listPtr->startPos >= count)
|
|
listPtr->startPos = count-1;
|
|
}
|
|
return qtrue;
|
|
}
|
|
}
|
|
else {
|
|
viewmax = (item->window.rect.h / listPtr->elementHeight);
|
|
if ( key == K_UPARROW || key == K_KP_UPARROW )
|
|
{
|
|
if (!listPtr->notselectable) {
|
|
listPtr->cursorPos--;
|
|
if (listPtr->cursorPos < 0) {
|
|
listPtr->cursorPos = 0;
|
|
}
|
|
if (listPtr->cursorPos < listPtr->startPos) {
|
|
listPtr->startPos = listPtr->cursorPos;
|
|
}
|
|
if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
|
|
listPtr->startPos = listPtr->cursorPos - viewmax + 1;
|
|
}
|
|
item->cursorPos = listPtr->cursorPos;
|
|
DC->feederSelection(item->special, item->cursorPos);
|
|
}
|
|
else {
|
|
listPtr->startPos--;
|
|
if (listPtr->startPos < 0)
|
|
listPtr->startPos = 0;
|
|
}
|
|
return qtrue;
|
|
}
|
|
if ( key == K_DOWNARROW || key == K_KP_DOWNARROW )
|
|
{
|
|
if (!listPtr->notselectable) {
|
|
listPtr->cursorPos++;
|
|
if (listPtr->cursorPos < listPtr->startPos) {
|
|
listPtr->startPos = listPtr->cursorPos;
|
|
}
|
|
if (listPtr->cursorPos >= count) {
|
|
listPtr->cursorPos = count-1;
|
|
}
|
|
if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
|
|
listPtr->startPos = listPtr->cursorPos - viewmax + 1;
|
|
}
|
|
item->cursorPos = listPtr->cursorPos;
|
|
DC->feederSelection(item->special, item->cursorPos);
|
|
}
|
|
else {
|
|
listPtr->startPos++;
|
|
if (listPtr->startPos > max)
|
|
listPtr->startPos = max;
|
|
}
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
// Use mouse wheel in vertical and horizontal menus.
|
|
// If scrolling 3 items would replace over half of the
|
|
// displayed items, only scroll 1 item at a time.
|
|
if ( key == K_MWHEELUP ) {
|
|
int scroll = viewmax < 6 ? 1 : 3;
|
|
listPtr->startPos -= scroll;
|
|
if (listPtr->startPos < 0) {
|
|
listPtr->startPos = 0;
|
|
}
|
|
return qtrue;
|
|
}
|
|
if ( key == K_MWHEELDOWN ) {
|
|
int scroll = viewmax < 6 ? 1 : 3;
|
|
listPtr->startPos += scroll;
|
|
if (listPtr->startPos > max) {
|
|
listPtr->startPos = max;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
// mouse hit
|
|
if (key == K_MOUSE1 || key == K_MOUSE2) {
|
|
if (item->window.flags & WINDOW_LB_LEFTARROW) {
|
|
listPtr->startPos--;
|
|
if (listPtr->startPos < 0) {
|
|
listPtr->startPos = 0;
|
|
}
|
|
} else if (item->window.flags & WINDOW_LB_RIGHTARROW) {
|
|
// one down
|
|
listPtr->startPos++;
|
|
if (listPtr->startPos > max) {
|
|
listPtr->startPos = max;
|
|
}
|
|
} else if (item->window.flags & WINDOW_LB_PGUP) {
|
|
// page up
|
|
listPtr->startPos -= viewmax;
|
|
if (listPtr->startPos < 0) {
|
|
listPtr->startPos = 0;
|
|
}
|
|
} else if (item->window.flags & WINDOW_LB_PGDN) {
|
|
// page down
|
|
listPtr->startPos += viewmax;
|
|
if (listPtr->startPos > max) {
|
|
listPtr->startPos = max;
|
|
}
|
|
} else if (item->window.flags & WINDOW_LB_THUMB) {
|
|
// Display_SetCaptureItem(item);
|
|
} else {
|
|
// select an item
|
|
if (DC->realTime < lastListBoxClickTime && listPtr->doubleClick) {
|
|
Item_RunScript(item, listPtr->doubleClick);
|
|
}
|
|
lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
|
|
if (item->cursorPos != listPtr->cursorPos) {
|
|
item->cursorPos = listPtr->cursorPos;
|
|
DC->feederSelection(item->special, item->cursorPos);
|
|
}
|
|
}
|
|
return qtrue;
|
|
}
|
|
if ( key == K_HOME || key == K_KP_HOME) {
|
|
// home
|
|
listPtr->startPos = 0;
|
|
return qtrue;
|
|
}
|
|
if ( key == K_END || key == K_KP_END) {
|
|
// end
|
|
listPtr->startPos = max;
|
|
return qtrue;
|
|
}
|
|
if (key == K_PGUP || key == K_KP_PGUP ) {
|
|
// page up
|
|
if (!listPtr->notselectable) {
|
|
listPtr->cursorPos -= viewmax;
|
|
if (listPtr->cursorPos < 0) {
|
|
listPtr->cursorPos = 0;
|
|
}
|
|
if (listPtr->cursorPos < listPtr->startPos) {
|
|
listPtr->startPos = listPtr->cursorPos;
|
|
}
|
|
if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
|
|
listPtr->startPos = listPtr->cursorPos - viewmax + 1;
|
|
}
|
|
item->cursorPos = listPtr->cursorPos;
|
|
DC->feederSelection(item->special, item->cursorPos);
|
|
}
|
|
else {
|
|
listPtr->startPos -= viewmax;
|
|
if (listPtr->startPos < 0) {
|
|
listPtr->startPos = 0;
|
|
}
|
|
}
|
|
return qtrue;
|
|
}
|
|
if ( key == K_PGDN || key == K_KP_PGDN ) {
|
|
// page down
|
|
if (!listPtr->notselectable) {
|
|
listPtr->cursorPos += viewmax;
|
|
if (listPtr->cursorPos < listPtr->startPos) {
|
|
listPtr->startPos = listPtr->cursorPos;
|
|
}
|
|
if (listPtr->cursorPos >= count) {
|
|
listPtr->cursorPos = count-1;
|
|
}
|
|
if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
|
|
listPtr->startPos = listPtr->cursorPos - viewmax + 1;
|
|
}
|
|
item->cursorPos = listPtr->cursorPos;
|
|
DC->feederSelection(item->special, item->cursorPos);
|
|
}
|
|
else {
|
|
listPtr->startPos += viewmax;
|
|
if (listPtr->startPos > max) {
|
|
listPtr->startPos = max;
|
|
}
|
|
}
|
|
return qtrue;
|
|
}
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) {
|
|
|
|
if (item->cvar) {
|
|
qboolean action = qfalse;
|
|
if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) {
|
|
if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS) {
|
|
action = qtrue;
|
|
}
|
|
} else if (UI_SelectForKey(key) != 0) {
|
|
action = qtrue;
|
|
}
|
|
if (action) {
|
|
DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar)));
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
return qfalse;
|
|
|
|
}
|
|
|
|
int Item_Multi_CountSettings(itemDef_t *item) {
|
|
multiDef_t *multiPtr = (multiDef_t*)item->typeData;
|
|
if (multiPtr == NULL) {
|
|
return 0;
|
|
}
|
|
return multiPtr->count;
|
|
}
|
|
|
|
int Item_Multi_FindCvarByValue(itemDef_t *item) {
|
|
char buff[1024];
|
|
float value = 0;
|
|
int i;
|
|
multiDef_t *multiPtr = (multiDef_t*)item->typeData;
|
|
if (multiPtr) {
|
|
if (multiPtr->strDef) {
|
|
DC->getCVarString(item->cvar, buff, sizeof(buff));
|
|
} else {
|
|
value = DC->getCVarValue(item->cvar);
|
|
}
|
|
for (i = 0; i < multiPtr->count; i++) {
|
|
if (multiPtr->strDef) {
|
|
if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
|
|
return i;
|
|
}
|
|
} else {
|
|
if (multiPtr->cvarValue[i] == value) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const char *Item_Multi_Setting(itemDef_t *item) {
|
|
char buff[1024];
|
|
float value = 0;
|
|
int i;
|
|
multiDef_t *multiPtr = (multiDef_t*)item->typeData;
|
|
if (multiPtr) {
|
|
if (multiPtr->strDef) {
|
|
DC->getCVarString(item->cvar, buff, sizeof(buff));
|
|
} else {
|
|
value = DC->getCVarValue(item->cvar);
|
|
}
|
|
for (i = 0; i < multiPtr->count; i++) {
|
|
if (multiPtr->strDef) {
|
|
if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
|
|
return multiPtr->cvarList[i];
|
|
}
|
|
} else {
|
|
if (multiPtr->cvarValue[i] == value) {
|
|
return multiPtr->cvarList[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
qboolean Item_Multi_HandleKey(itemDef_t *item, int key) {
|
|
multiDef_t *multiPtr = (multiDef_t*)item->typeData;
|
|
if (multiPtr) {
|
|
if (item->cvar) {
|
|
int select = 0;
|
|
if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) {
|
|
if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS) {
|
|
select = (key == K_MOUSE2) ? -1 : 1;
|
|
}
|
|
} else {
|
|
select = UI_SelectForKey(key);
|
|
}
|
|
if (select != 0) {
|
|
int current = Item_Multi_FindCvarByValue(item) + select;
|
|
int max = Item_Multi_CountSettings(item);
|
|
if ( current < 0 ) {
|
|
current = max-1;
|
|
} else if ( current >= max ) {
|
|
current = 0;
|
|
}
|
|
|
|
if (multiPtr->videoMode) {
|
|
if (multiPtr->cvarValue[current] != -1) {
|
|
DC->setCVar("r_mode", va("%i", (int) multiPtr->cvarValue[current] ));
|
|
} else {
|
|
int w, h;
|
|
char *x;
|
|
char str[8];
|
|
|
|
x = strchr( multiPtr->cvarStr[current], 'x' ) + 1;
|
|
Q_strncpyz( str, multiPtr->cvarStr[current], MIN( x-multiPtr->cvarStr[current], sizeof( str ) ) );
|
|
w = atoi( str );
|
|
h = atoi( x );
|
|
|
|
DC->setCVar("r_mode", "-1");
|
|
DC->setCVar("r_customwidth", va("%i", w));
|
|
DC->setCVar("r_customheight", va("%i", h));
|
|
}
|
|
}
|
|
|
|
if (multiPtr->strDef) {
|
|
DC->setCVar(item->cvar, multiPtr->cvarStr[current]);
|
|
} else {
|
|
float value = multiPtr->cvarValue[current];
|
|
if (((float)((int) value)) == value) {
|
|
DC->setCVar(item->cvar, va("%i", (int) value ));
|
|
}
|
|
else {
|
|
DC->setCVar(item->cvar, va("%f", value ));
|
|
}
|
|
}
|
|
return qtrue;
|
|
}
|
|
}
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean Item_TextField_HandleKey(itemDef_t *item, int key) {
|
|
char buff[1024];
|
|
int len;
|
|
itemDef_t *newItem = NULL;
|
|
editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
|
|
|
|
if (item->cvar) {
|
|
|
|
memset(buff, 0, sizeof(buff));
|
|
DC->getCVarString(item->cvar, buff, sizeof(buff));
|
|
len = strlen(buff);
|
|
if (editPtr->maxChars && len > editPtr->maxChars) {
|
|
len = editPtr->maxChars;
|
|
}
|
|
if ( key & K_CHAR_FLAG ) {
|
|
key &= ~K_CHAR_FLAG;
|
|
|
|
|
|
if (key == 'h' - 'a' + 1 ) { // ctrl-h is backspace
|
|
if ( item->cursorPos > 0 ) {
|
|
memmove( &buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
|
|
item->cursorPos--;
|
|
if (item->cursorPos < editPtr->paintOffset) {
|
|
editPtr->paintOffset--;
|
|
}
|
|
}
|
|
DC->setCVar(item->cvar, buff);
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
//
|
|
// ignore any non printable chars
|
|
//
|
|
if ( key < 32 || !item->cvar) {
|
|
return qtrue;
|
|
}
|
|
|
|
if (item->type == ITEM_TYPE_NUMERICFIELD) {
|
|
if (key < '0' || key > '9') {
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
if (!DC->getOverstrikeMode()) {
|
|
if (( len == MAX_EDITFIELD - 1 ) || (editPtr->maxChars && len >= editPtr->maxChars)) {
|
|
return qtrue;
|
|
}
|
|
memmove( &buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos );
|
|
} else {
|
|
if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars) {
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
buff[item->cursorPos] = key;
|
|
|
|
DC->setCVar(item->cvar, buff);
|
|
|
|
if (item->cursorPos < len + 1) {
|
|
item->cursorPos++;
|
|
if (editPtr->maxPaintChars && item->cursorPos > editPtr->maxPaintChars) {
|
|
editPtr->paintOffset++;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( key == K_DEL || key == K_KP_DEL ) {
|
|
if ( item->cursorPos < len ) {
|
|
memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos);
|
|
DC->setCVar(item->cvar, buff);
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
|
|
{
|
|
if (editPtr->maxPaintChars && item->cursorPos >= editPtr->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;
|
|
}
|
|
}
|
|
|
|
if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE) {
|
|
return qfalse;
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
|
|
}
|
|
|
|
static void Scroll_ListBox_AutoFunc(void *p) {
|
|
scrollInfo_t *si = (scrollInfo_t*)p;
|
|
if (DC->realTime > si->nextScrollTime) {
|
|
// need to scroll which is done by simulating a click to the item
|
|
// this is done a bit sideways as the autoscroll "knows" that the item is a listbox
|
|
// so it calls it directly
|
|
Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
|
|
si->nextScrollTime = DC->realTime + si->adjustValue;
|
|
}
|
|
|
|
if (DC->realTime > si->nextAdjustTime) {
|
|
si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
|
|
if (si->adjustValue > SCROLL_TIME_FLOOR) {
|
|
si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Scroll_ListBox_ThumbFunc(void *p) {
|
|
scrollInfo_t *si = (scrollInfo_t*)p;
|
|
rectDef_t r;
|
|
int pos, max;
|
|
|
|
listBoxDef_t *listPtr = (listBoxDef_t*)si->item->typeData;
|
|
if (si->item->window.flags & WINDOW_HORIZONTAL) {
|
|
if (DC->cursorx == si->xStart) {
|
|
return;
|
|
}
|
|
r.x = si->item->window.rect.x + SCROLLBAR_SIZE + 1;
|
|
r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_SIZE - 1;
|
|
r.h = SCROLLBAR_SIZE;
|
|
r.w = si->item->window.rect.w - (SCROLLBAR_SIZE*2) - 2;
|
|
max = Item_ListBox_MaxScroll(si->item);
|
|
//
|
|
pos = (DC->cursorx - r.x - SCROLLBAR_SIZE/2) * max / (r.w - SCROLLBAR_SIZE);
|
|
if (pos < 0) {
|
|
pos = 0;
|
|
}
|
|
else if (pos > max) {
|
|
pos = max;
|
|
}
|
|
listPtr->startPos = pos;
|
|
si->xStart = DC->cursorx;
|
|
}
|
|
else if (DC->cursory != si->yStart) {
|
|
|
|
r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1;
|
|
r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1;
|
|
r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2;
|
|
r.w = SCROLLBAR_SIZE;
|
|
max = Item_ListBox_MaxScroll(si->item);
|
|
//
|
|
pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE);
|
|
if (pos < 0) {
|
|
pos = 0;
|
|
}
|
|
else if (pos > max) {
|
|
pos = max;
|
|
}
|
|
listPtr->startPos = pos;
|
|
si->yStart = DC->cursory;
|
|
}
|
|
|
|
if (DC->realTime > si->nextScrollTime) {
|
|
// need to scroll which is done by simulating a click to the item
|
|
// this is done a bit sideways as the autoscroll "knows" that the item is a listbox
|
|
// so it calls it directly
|
|
Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
|
|
si->nextScrollTime = DC->realTime + si->adjustValue;
|
|
}
|
|
|
|
if (DC->realTime > si->nextAdjustTime) {
|
|
si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
|
|
if (si->adjustValue > SCROLL_TIME_FLOOR) {
|
|
si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Scroll_Slider_ThumbFunc(void *p) {
|
|
float x, value, cursorx;
|
|
scrollInfo_t *si = (scrollInfo_t*)p;
|
|
editFieldDef_t *editDef = si->item->typeData;
|
|
|
|
if (si->item->text) {
|
|
x = si->item->textRect.x + si->item->textRect.w + 8;
|
|
} else {
|
|
x = si->item->window.rect.x;
|
|
}
|
|
|
|
cursorx = DC->cursorx;
|
|
|
|
if (cursorx < x) {
|
|
cursorx = x;
|
|
} else if (cursorx > x + SLIDER_WIDTH) {
|
|
cursorx = x + SLIDER_WIDTH;
|
|
}
|
|
value = cursorx - x;
|
|
value /= SLIDER_WIDTH;
|
|
value *= (editDef->maxVal - editDef->minVal);
|
|
value += editDef->minVal;
|
|
DC->setCVar(si->item->cvar, va("%f", value));
|
|
}
|
|
|
|
void Item_StartCapture(itemDef_t *item, int key) {
|
|
int flags;
|
|
switch (item->type) {
|
|
case ITEM_TYPE_EDITFIELD:
|
|
case ITEM_TYPE_NUMERICFIELD:
|
|
|
|
case ITEM_TYPE_LISTBOX:
|
|
{
|
|
flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory);
|
|
if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) {
|
|
scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
|
|
scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
|
|
scrollInfo.adjustValue = SCROLL_TIME_START;
|
|
scrollInfo.scrollKey = key;
|
|
scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse;
|
|
scrollInfo.item = item;
|
|
captureData = &scrollInfo;
|
|
captureFunc = &Scroll_ListBox_AutoFunc;
|
|
itemCapture = item;
|
|
} else if (flags & WINDOW_LB_THUMB) {
|
|
scrollInfo.scrollKey = key;
|
|
scrollInfo.item = item;
|
|
scrollInfo.xStart = DC->cursorx;
|
|
scrollInfo.yStart = DC->cursory;
|
|
captureData = &scrollInfo;
|
|
captureFunc = &Scroll_ListBox_ThumbFunc;
|
|
itemCapture = item;
|
|
}
|
|
break;
|
|
}
|
|
case ITEM_TYPE_SLIDER:
|
|
{
|
|
flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory);
|
|
if (flags & WINDOW_LB_THUMB) {
|
|
scrollInfo.scrollKey = key;
|
|
scrollInfo.item = item;
|
|
scrollInfo.xStart = DC->cursorx;
|
|
scrollInfo.yStart = DC->cursory;
|
|
captureData = &scrollInfo;
|
|
captureFunc = &Scroll_Slider_ThumbFunc;
|
|
itemCapture = item;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Item_StopCapture(itemDef_t *item) {
|
|
|
|
}
|
|
|
|
qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) {
|
|
float x, value, width, work;
|
|
|
|
//DC->Print("slider handle key\n");
|
|
if (item->cvar) {
|
|
if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) {
|
|
editFieldDef_t *editDef = item->typeData;
|
|
if (editDef && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS) {
|
|
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;
|
|
}
|
|
}
|
|
} else {
|
|
int select = UI_SelectForKey(key);
|
|
if (select != 0) {
|
|
editFieldDef_t *editDef = item->typeData;
|
|
if (editDef) {
|
|
// 20 is number of steps
|
|
value = DC->getCVarValue(item->cvar) + (((editDef->maxVal - editDef->minVal)/20) * select);
|
|
|
|
if (value < editDef->minVal)
|
|
value = editDef->minVal;
|
|
else if (value > editDef->maxVal)
|
|
value = editDef->maxVal;
|
|
|
|
DC->setCVar(item->cvar, va("%f", value));
|
|
return qtrue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DC->Print("slider handle key exit\n");
|
|
return qfalse;
|
|
}
|
|
|
|
|
|
qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) {
|
|
|
|
if (itemCapture) {
|
|
Item_StopCapture(itemCapture);
|
|
itemCapture = NULL;
|
|
captureFunc = 0;
|
|
captureData = NULL;
|
|
} else {
|
|
if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
|
|
Item_StartCapture(item, key);
|
|
}
|
|
}
|
|
|
|
if (!down) {
|
|
return qfalse;
|
|
}
|
|
|
|
switch (item->type) {
|
|
case ITEM_TYPE_BUTTON:
|
|
return qfalse;
|
|
break;
|
|
case ITEM_TYPE_RADIOBUTTON:
|
|
return qfalse;
|
|
break;
|
|
case ITEM_TYPE_CHECKBOX:
|
|
return qfalse;
|
|
break;
|
|
case ITEM_TYPE_EDITFIELD:
|
|
case ITEM_TYPE_NUMERICFIELD:
|
|
//return Item_TextField_HandleKey(item, key);
|
|
return qfalse;
|
|
break;
|
|
case ITEM_TYPE_COMBO:
|
|
return qfalse;
|
|
break;
|
|
case ITEM_TYPE_LISTBOX:
|
|
return Item_ListBox_HandleKey(item, key, down, qfalse);
|
|
break;
|
|
case ITEM_TYPE_YESNO:
|
|
return Item_YesNo_HandleKey(item, key);
|
|
break;
|
|
case ITEM_TYPE_MULTI:
|
|
return Item_Multi_HandleKey(item, key);
|
|
break;
|
|
case ITEM_TYPE_OWNERDRAW:
|
|
return Item_OwnerDraw_HandleKey(item, key);
|
|
break;
|
|
case ITEM_TYPE_BIND:
|
|
return Item_Bind_HandleKey(item, key, down);
|
|
break;
|
|
case ITEM_TYPE_SLIDER:
|
|
return Item_Slider_HandleKey(item, key, down);
|
|
break;
|
|
//case ITEM_TYPE_IMAGE:
|
|
// Item_Image_Paint(item);
|
|
// break;
|
|
default:
|
|
return qfalse;
|
|
break;
|
|
}
|
|
|
|
//return qfalse;
|
|
}
|
|
|
|
void Item_Action(itemDef_t *item) {
|
|
if (item) {
|
|
Item_RunScript(item, item->action);
|
|
}
|
|
}
|
|
|
|
itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu) {
|
|
qboolean wrapped = qfalse;
|
|
int oldCursor = menu->cursorItem;
|
|
|
|
if (menu->cursorItem < 0) {
|
|
menu->cursorItem = menu->itemCount-1;
|
|
wrapped = qtrue;
|
|
}
|
|
|
|
while (menu->cursorItem > -1) {
|
|
|
|
menu->cursorItem--;
|
|
if (menu->cursorItem < 0 && !wrapped) {
|
|
wrapped = qtrue;
|
|
menu->cursorItem = menu->itemCount -1;
|
|
}
|
|
|
|
if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
|
|
Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
|
|
return menu->items[menu->cursorItem];
|
|
}
|
|
}
|
|
menu->cursorItem = oldCursor;
|
|
return NULL;
|
|
|
|
}
|
|
|
|
itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu) {
|
|
|
|
qboolean wrapped = qfalse;
|
|
int oldCursor = menu->cursorItem;
|
|
|
|
|
|
if (menu->cursorItem == -1) {
|
|
menu->cursorItem = 0;
|
|
wrapped = qtrue;
|
|
}
|
|
|
|
while (menu->cursorItem < menu->itemCount) {
|
|
|
|
menu->cursorItem++;
|
|
if (menu->cursorItem >= menu->itemCount && !wrapped) {
|
|
wrapped = qtrue;
|
|
menu->cursorItem = 0;
|
|
}
|
|
if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
|
|
Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
|
|
return menu->items[menu->cursorItem];
|
|
}
|
|
|
|
}
|
|
|
|
menu->cursorItem = oldCursor;
|
|
return NULL;
|
|
}
|
|
|
|
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( void ) {
|
|
int i;
|
|
for (i = 0; i < menuCount; i++) {
|
|
Menu_CloseCinematics(&Menus[i]);
|
|
}
|
|
}
|
|
|
|
void Menus_Activate(menuDef_t *menu) {
|
|
menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
|
|
if (menu->onOpen) {
|
|
itemDef_t item;
|
|
item.parent = menu;
|
|
Item_RunScript(&item, menu->onOpen);
|
|
}
|
|
|
|
if (menu->soundName && *menu->soundName) {
|
|
// DC->stopBackgroundTrack(); // you don't want to do this since it will reset s_rawend
|
|
DC->startBackgroundTrack(menu->soundName, menu->soundName);
|
|
}
|
|
|
|
Display_CloseCinematics();
|
|
|
|
}
|
|
|
|
int Display_VisibleMenuCount( void ) {
|
|
int i, count;
|
|
count = 0;
|
|
for (i = 0; i < menuCount; i++) {
|
|
if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE)) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down) {
|
|
if (menu) {
|
|
int i;
|
|
// basically the behaviour we are looking for is if there are windows in the stack.. see if
|
|
// the cursor is within any of them.. if not close them otherwise activate them and pass the
|
|
// key on.. force a mouse move to activate focus and script stuff
|
|
if (down && menu->window.flags & WINDOW_OOB_CLICK) {
|
|
Menu_RunCloseScript(menu);
|
|
menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
|
|
}
|
|
|
|
for (i = 0; i < menuCount; i++) {
|
|
if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory)) {
|
|
Menu_RunCloseScript(menu);
|
|
menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
|
|
Menus_Activate(&Menus[i]);
|
|
Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory);
|
|
Menu_HandleKey(&Menus[i], key, down);
|
|
}
|
|
}
|
|
|
|
if (Display_VisibleMenuCount() == 0) {
|
|
if (DC->Pause) {
|
|
DC->Pause(qfalse);
|
|
}
|
|
}
|
|
Display_CloseCinematics();
|
|
}
|
|
}
|
|
|
|
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 ▭
|
|
}
|
|
|
|
// menu item key horizontal action: -1 = previous value, 1 = next value, 0 = no change
|
|
int UI_SelectForKey(int key)
|
|
{
|
|
switch (key) {
|
|
case K_MOUSE1:
|
|
case K_MOUSE3:
|
|
case K_ENTER:
|
|
case K_KP_ENTER:
|
|
case K_RIGHTARROW:
|
|
case K_KP_RIGHTARROW:
|
|
case K_JOY1:
|
|
case K_JOY2:
|
|
case K_JOY3:
|
|
case K_JOY4:
|
|
return 1; // next
|
|
|
|
case K_MOUSE2:
|
|
case K_LEFTARROW:
|
|
case K_KP_LEFTARROW:
|
|
return -1; // previous
|
|
}
|
|
|
|
// no change
|
|
return 0;
|
|
}
|
|
|
|
void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) {
|
|
int i;
|
|
itemDef_t *item = NULL;
|
|
|
|
if (g_waitingForKey && down) {
|
|
Item_Bind_HandleKey(g_bindItem, key, down);
|
|
return;
|
|
}
|
|
|
|
if (g_editingField && down) {
|
|
if (!Item_TextField_HandleKey(g_editItem, key)) {
|
|
g_editingField = qfalse;
|
|
g_editItem = NULL;
|
|
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) {
|
|
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;
|
|
if (!inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
|
|
inHandleKey = qtrue;
|
|
Menus_HandleOOBClick(menu, key, down);
|
|
inHandleKey = 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);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!down) {
|
|
return;
|
|
}
|
|
|
|
// default handling
|
|
switch ( key ) {
|
|
|
|
case K_F11:
|
|
if (DC->getCVarValue("developer")) {
|
|
debugMode ^= 1;
|
|
}
|
|
break;
|
|
|
|
case K_F12:
|
|
if (DC->getCVarValue("developer")) {
|
|
DC->executeText(EXEC_APPEND, "screenshot\n");
|
|
}
|
|
break;
|
|
case K_KP_UPARROW:
|
|
case K_UPARROW:
|
|
Menu_SetPrevCursorItem(menu);
|
|
break;
|
|
|
|
case K_ESCAPE:
|
|
if (!g_waitingForKey && menu->onESC) {
|
|
itemDef_t it;
|
|
it.parent = menu;
|
|
Item_RunScript(&it, menu->onESC);
|
|
}
|
|
break;
|
|
case K_TAB:
|
|
case K_KP_DOWNARROW:
|
|
case K_DOWNARROW:
|
|
Menu_SetNextCursorItem(menu);
|
|
break;
|
|
|
|
case K_MOUSE1:
|
|
case K_MOUSE2:
|
|
if (item) {
|
|
if (item->type == ITEM_TYPE_TEXT) {
|
|
if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory)) {
|
|
Item_Action(item);
|
|
}
|
|
} else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
|
|
if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
|
|
item->cursorPos = 0;
|
|
g_editingField = qtrue;
|
|
g_editItem = item;
|
|
}
|
|
} 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:
|
|
case K_KP_ENTER:
|
|
case K_ENTER:
|
|
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;
|
|
}
|
|
}
|
|
|
|
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)) {
|
|
int originalWidth = DC->textWidth(item->text, item->textscale, 0);
|
|
|
|
if (item->type == ITEM_TYPE_OWNERDRAW && (item->textalignment == ITEM_ALIGN_CENTER || item->textalignment == ITEM_ALIGN_RIGHT)) {
|
|
originalWidth += DC->ownerDrawWidth(item->window.ownerDraw, item->textscale);
|
|
} else if (item->type == ITEM_TYPE_EDITFIELD && item->textalignment == ITEM_ALIGN_CENTER && item->cvar) {
|
|
char buff[256];
|
|
DC->getCVarString(item->cvar, buff, 256);
|
|
originalWidth += DC->textWidth(buff, item->textscale, 0);
|
|
}
|
|
|
|
*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->textRect.x = item->textalignx - originalWidth / 2;
|
|
}
|
|
|
|
ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
|
|
}
|
|
}
|
|
|
|
void Item_TextColor(itemDef_t *item, vec4_t *newColor) {
|
|
vec4_t lowLight;
|
|
menuDef_t *parent = (menuDef_t*)item->parent;
|
|
|
|
Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
|
|
|
|
if (item->window.flags & WINDOW_HASFOCUS) {
|
|
lowLight[0] = 0.8 * parent->focusColor[0];
|
|
lowLight[1] = 0.8 * parent->focusColor[1];
|
|
lowLight[2] = 0.8 * parent->focusColor[2];
|
|
lowLight[3] = 0.8 * parent->focusColor[3];
|
|
LerpColor(parent->focusColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
|
|
} else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
|
|
lowLight[0] = 0.8 * item->window.foreColor[0];
|
|
lowLight[1] = 0.8 * item->window.foreColor[1];
|
|
lowLight[2] = 0.8 * item->window.foreColor[2];
|
|
lowLight[3] = 0.8 * item->window.foreColor[3];
|
|
LerpColor(item->window.foreColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
|
|
} else {
|
|
memcpy(newColor, &item->window.foreColor, sizeof(vec4_t));
|
|
// items can be enabled and disabled based on cvars
|
|
}
|
|
|
|
if (item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
|
|
if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
|
|
memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Item_Text_AutoWrapped_Paint(itemDef_t *item) {
|
|
char text[1024];
|
|
const char *p, *textPtr, *newLinePtr;
|
|
char buff[1024];
|
|
int width, height, len, textWidth, newLine, newLineWidth;
|
|
float y;
|
|
vec4_t color;
|
|
|
|
textWidth = 0;
|
|
newLinePtr = NULL;
|
|
|
|
if (item->text == NULL) {
|
|
if (item->cvar == NULL) {
|
|
return;
|
|
}
|
|
else {
|
|
DC->getCVarString(item->cvar, text, sizeof(text));
|
|
textPtr = text;
|
|
}
|
|
}
|
|
else {
|
|
textPtr = item->text;
|
|
}
|
|
if (*textPtr == '\0') {
|
|
return;
|
|
}
|
|
Item_TextColor(item, &color);
|
|
Item_SetTextExtents(item, &width, &height, textPtr);
|
|
|
|
y = item->textaligny;
|
|
len = 0;
|
|
buff[0] = '\0';
|
|
newLine = 0;
|
|
newLineWidth = 0;
|
|
p = textPtr;
|
|
while (p) {
|
|
if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\0') {
|
|
newLine = len;
|
|
newLinePtr = p+1;
|
|
newLineWidth = textWidth;
|
|
}
|
|
textWidth = DC->textWidth(buff, item->textscale, 0);
|
|
if ( (newLine && textWidth > item->window.rect.w) || *p == '\n' || *p == '\0') {
|
|
if (len) {
|
|
if (item->textalignment == ITEM_ALIGN_LEFT) {
|
|
item->textRect.x = item->textalignx;
|
|
} else if (item->textalignment == ITEM_ALIGN_RIGHT) {
|
|
item->textRect.x = item->textalignx - newLineWidth;
|
|
} else if (item->textalignment == ITEM_ALIGN_CENTER) {
|
|
item->textRect.x = item->textalignx - newLineWidth / 2;
|
|
}
|
|
item->textRect.y = y;
|
|
ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
|
|
//
|
|
buff[newLine] = '\0';
|
|
DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, buff, 0, 0, item->textStyle);
|
|
}
|
|
if (*p == '\0') {
|
|
break;
|
|
}
|
|
//
|
|
y += height + 5;
|
|
p = newLinePtr;
|
|
len = 0;
|
|
newLine = 0;
|
|
newLineWidth = 0;
|
|
continue;
|
|
}
|
|
buff[len++] = *p++;
|
|
buff[len] = '\0';
|
|
}
|
|
}
|
|
|
|
void Item_Text_Wrapped_Paint(itemDef_t *item) {
|
|
char text[1024];
|
|
const char *p, *start, *textPtr;
|
|
char buff[1024];
|
|
int width, height;
|
|
float x, y;
|
|
vec4_t color;
|
|
|
|
// now paint the text and/or any optional images
|
|
// default to left
|
|
|
|
if (item->text == NULL) {
|
|
if (item->cvar == NULL) {
|
|
return;
|
|
}
|
|
else {
|
|
DC->getCVarString(item->cvar, text, sizeof(text));
|
|
textPtr = text;
|
|
}
|
|
}
|
|
else {
|
|
textPtr = item->text;
|
|
}
|
|
if (*textPtr == '\0') {
|
|
return;
|
|
}
|
|
|
|
Item_TextColor(item, &color);
|
|
Item_SetTextExtents(item, &width, &height, textPtr);
|
|
|
|
x = item->textRect.x;
|
|
y = item->textRect.y;
|
|
start = textPtr;
|
|
p = strchr(textPtr, '\r');
|
|
while (p && *p) {
|
|
strncpy(buff, start, p-start+1);
|
|
buff[p-start] = '\0';
|
|
DC->drawText(x, y, item->textscale, color, buff, 0, 0, item->textStyle);
|
|
y += height + 5;
|
|
start += p - start + 1;
|
|
p = strchr(p+1, '\r');
|
|
}
|
|
DC->drawText(x, y, item->textscale, color, start, 0, 0, item->textStyle);
|
|
}
|
|
|
|
void Item_Text_Paint(itemDef_t *item) {
|
|
char text[1024];
|
|
const char *textPtr;
|
|
int height, width;
|
|
vec4_t color;
|
|
|
|
if (item->window.flags & WINDOW_WRAPPED) {
|
|
Item_Text_Wrapped_Paint(item);
|
|
return;
|
|
}
|
|
if (item->window.flags & WINDOW_AUTOWRAPPED) {
|
|
Item_Text_AutoWrapped_Paint(item);
|
|
return;
|
|
}
|
|
|
|
if (item->text == NULL) {
|
|
if (item->cvar == NULL) {
|
|
return;
|
|
}
|
|
else {
|
|
DC->getCVarString(item->cvar, text, sizeof(text));
|
|
textPtr = text;
|
|
}
|
|
}
|
|
else {
|
|
textPtr = item->text;
|
|
}
|
|
|
|
// this needs to go here as it sets extents for cvar types as well
|
|
Item_SetTextExtents(item, &width, &height, textPtr);
|
|
|
|
if (*textPtr == '\0') {
|
|
return;
|
|
}
|
|
|
|
|
|
Item_TextColor(item, &color);
|
|
|
|
//FIXME: this is a fucking mess
|
|
/*
|
|
adjust = 0;
|
|
if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
|
|
adjust = 0.5;
|
|
}
|
|
|
|
if (item->textStyle == ITEM_TEXTSTYLE_SHADOWED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
|
|
Fade(&item->window.flags, &DC->Assets.shadowColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
|
|
DC->drawText(item->textRect.x + DC->Assets.shadowX, item->textRect.y + DC->Assets.shadowY, item->textscale, DC->Assets.shadowColor, textPtr, adjust);
|
|
}
|
|
*/
|
|
|
|
|
|
// if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
|
|
// Fade(&item->window.flags, &item->window.outlineColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
|
|
// /*
|
|
// Text_Paint(item->textRect.x-1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
|
|
// Text_Paint(item->textRect.x, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
|
|
// Text_Paint(item->textRect.x+1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
|
|
// Text_Paint(item->textRect.x-1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
|
|
// Text_Paint(item->textRect.x+1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
|
|
// Text_Paint(item->textRect.x-1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
|
|
// Text_Paint(item->textRect.x, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
|
|
// Text_Paint(item->textRect.x+1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
|
|
// */
|
|
// DC->drawText(item->textRect.x - 1, item->textRect.y + 1, item->textscale * 1.02, item->window.outlineColor, textPtr, adjust);
|
|
// }
|
|
|
|
DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, 0, item->textStyle);
|
|
}
|
|
|
|
|
|
|
|
//float trap_Cvar_VariableValue( const char *var_name );
|
|
//void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
|
|
|
|
void Item_TextField_Paint(itemDef_t *item) {
|
|
char buff[1024];
|
|
vec4_t newColor, lowLight;
|
|
int offset;
|
|
menuDef_t *parent = (menuDef_t*)item->parent;
|
|
editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
|
|
|
|
Item_Text_Paint(item);
|
|
|
|
buff[0] = '\0';
|
|
|
|
if (item->cvar) {
|
|
DC->getCVarString(item->cvar, buff, sizeof(buff));
|
|
}
|
|
|
|
if (item->window.flags & WINDOW_HASFOCUS) {
|
|
lowLight[0] = 0.8 * parent->focusColor[0];
|
|
lowLight[1] = 0.8 * parent->focusColor[1];
|
|
lowLight[2] = 0.8 * parent->focusColor[2];
|
|
lowLight[3] = 0.8 * parent->focusColor[3];
|
|
LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
|
|
} else {
|
|
memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
|
|
}
|
|
|
|
offset = (item->text && *item->text) ? 8 : 0;
|
|
if (item->window.flags & WINDOW_HASFOCUS && g_editingField) {
|
|
char cursor = DC->getOverstrikeMode() ? '_' : '|';
|
|
DC->drawTextWithCursor(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, item->cursorPos - editPtr->paintOffset , cursor, editPtr->maxPaintChars, item->textStyle);
|
|
} else {
|
|
DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle);
|
|
}
|
|
|
|
}
|
|
|
|
void Item_YesNo_Paint(itemDef_t *item) {
|
|
vec4_t newColor, lowLight;
|
|
float value;
|
|
menuDef_t *parent = (menuDef_t*)item->parent;
|
|
|
|
value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
|
|
|
|
if (item->window.flags & WINDOW_HASFOCUS) {
|
|
lowLight[0] = 0.8 * parent->focusColor[0];
|
|
lowLight[1] = 0.8 * parent->focusColor[1];
|
|
lowLight[2] = 0.8 * parent->focusColor[2];
|
|
lowLight[3] = 0.8 * parent->focusColor[3];
|
|
LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
|
|
} else {
|
|
memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
|
|
}
|
|
|
|
if (item->text) {
|
|
Item_Text_Paint(item);
|
|
DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
|
|
} else {
|
|
DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
|
|
}
|
|
}
|
|
|
|
void Item_Multi_Paint(itemDef_t *item) {
|
|
vec4_t newColor, lowLight;
|
|
const char *text = "";
|
|
menuDef_t *parent = (menuDef_t*)item->parent;
|
|
|
|
if (item->window.flags & WINDOW_HASFOCUS) {
|
|
lowLight[0] = 0.8 * parent->focusColor[0];
|
|
lowLight[1] = 0.8 * parent->focusColor[1];
|
|
lowLight[2] = 0.8 * parent->focusColor[2];
|
|
lowLight[3] = 0.8 * parent->focusColor[3];
|
|
LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
|
|
} else {
|
|
memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
|
|
}
|
|
|
|
text = Item_Multi_Setting(item);
|
|
|
|
if (item->text) {
|
|
Item_Text_Paint(item);
|
|
DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
|
|
} else {
|
|
DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
|
|
}
|
|
}
|
|
|
|
|
|
typedef struct {
|
|
char *command;
|
|
int defaultbind1;
|
|
int defaultbind2;
|
|
int bind1;
|
|
int bind2;
|
|
} bind_t;
|
|
|
|
typedef struct
|
|
{
|
|
char* name;
|
|
float defaultvalue;
|
|
float value;
|
|
} configcvar_t;
|
|
|
|
|
|
static bind_t g_bindings[] =
|
|
{
|
|
{"+scores", K_TAB, -1, -1, -1},
|
|
{"+button2", K_ENTER, -1, -1, -1},
|
|
{"+speed", K_SHIFT, -1, -1, -1},
|
|
{"+forward", K_UPARROW, -1, -1, -1},
|
|
{"+back", K_DOWNARROW, -1, -1, -1},
|
|
{"+moveleft", ',', -1, -1, -1},
|
|
{"+moveright", '.', -1, -1, -1},
|
|
{"+moveup", K_SPACE, -1, -1, -1},
|
|
{"+movedown", 'c', -1, -1, -1},
|
|
{"+left", K_LEFTARROW, -1, -1, -1},
|
|
{"+right", K_RIGHTARROW, -1, -1, -1},
|
|
{"+strafe", K_ALT, -1, -1, -1},
|
|
{"+lookup", K_PGDN, -1, -1, -1},
|
|
{"+lookdown", K_DEL, -1, -1, -1},
|
|
{"+mlook", '/', -1, -1, -1},
|
|
{"centerview", K_END, -1, -1, -1},
|
|
{"+zoom", -1, -1, -1, -1},
|
|
{"weapon 1", '1', -1, -1, -1},
|
|
{"weapon 2", '2', -1, -1, -1},
|
|
{"weapon 3", '3', -1, -1, -1},
|
|
{"weapon 4", '4', -1, -1, -1},
|
|
{"weapon 5", '5', -1, -1, -1},
|
|
{"weapon 6", '6', -1, -1, -1},
|
|
{"weapon 7", '7', -1, -1, -1},
|
|
{"weapon 8", '8', -1, -1, -1},
|
|
{"weapon 9", '9', -1, -1, -1},
|
|
{"weapon 10", '0', -1, -1, -1},
|
|
{"weapon 11", -1, -1, -1, -1},
|
|
{"weapon 12", -1, -1, -1, -1},
|
|
{"weapon 13", -1, -1, -1, -1},
|
|
{"+attack", K_CTRL, -1, -1, -1},
|
|
{"weapprev", '[', -1, -1, -1},
|
|
{"weapnext", ']', -1, -1, -1},
|
|
{"+button3", K_MOUSE3, -1, -1, -1},
|
|
{"+button4", K_MOUSE4, -1, -1, -1},
|
|
{"prevTeamMember", 'w', -1, -1, -1},
|
|
{"nextTeamMember", 'r', -1, -1, -1},
|
|
{"nextOrder", 't', -1, -1, -1},
|
|
{"confirmOrder", 'y', -1, -1, -1},
|
|
{"denyOrder", 'n', -1, -1, -1},
|
|
{"taskOffense", 'o', -1, -1, -1},
|
|
{"taskDefense", 'd', -1, -1, -1},
|
|
{"taskPatrol", 'p', -1, -1, -1},
|
|
{"taskCamp", 'c', -1, -1, -1},
|
|
{"taskFollow", 'f', -1, -1, -1},
|
|
{"taskRetrieve", 'v', -1, -1, -1},
|
|
{"taskEscort", 'e', -1, -1, -1},
|
|
{"taskOwnFlag", 'i', -1, -1, -1},
|
|
{"taskSuicide", 'k', -1, -1, -1},
|
|
{"tauntKillInsult", K_F1, -1, -1, -1},
|
|
{"tauntPraise", K_F2, -1, -1, -1},
|
|
{"tauntTaunt", K_F3, -1, -1, -1},
|
|
{"tauntDeathInsult", K_F4, -1, -1, -1},
|
|
{"tauntGauntlet", K_F5, -1, -1, -1},
|
|
{"scoresUp", K_KP_PGUP, -1, -1, -1},
|
|
{"scoresDown", K_KP_PGDN, -1, -1, -1},
|
|
{"messagemode", -1, -1, -1, -1},
|
|
{"messagemode2", -1, -1, -1, -1},
|
|
{"messagemode3", -1, -1, -1, -1},
|
|
{"messagemode4", -1, -1, -1, -1}
|
|
};
|
|
|
|
|
|
static const int g_bindCount = ARRAY_LEN(g_bindings);
|
|
|
|
#ifndef MISSIONPACK
|
|
static configcvar_t g_configcvars[] =
|
|
{
|
|
{"cl_run", 0, 0},
|
|
{"m_pitch", 0, 0},
|
|
{"cg_autoswitch", 0, 0},
|
|
{"sensitivity", 0, 0},
|
|
{"in_joystick", 0, 0},
|
|
{"joy_threshold", 0, 0},
|
|
{"m_filter", 0, 0},
|
|
{"cl_freelook", 0, 0},
|
|
{NULL, 0, 0}
|
|
};
|
|
#endif
|
|
|
|
/*
|
|
=================
|
|
Controls_GetKeyAssignment
|
|
=================
|
|
*/
|
|
static void Controls_GetKeyAssignment (char *command, int *twokeys)
|
|
{
|
|
int count;
|
|
int j;
|
|
char b[256];
|
|
|
|
twokeys[0] = twokeys[1] = -1;
|
|
count = 0;
|
|
|
|
for ( j = 0; j < 256; j++ )
|
|
{
|
|
DC->getBindingBuf( j, b, 256 );
|
|
if ( *b == 0 ) {
|
|
continue;
|
|
}
|
|
if ( !Q_stricmp( b, command ) ) {
|
|
twokeys[count] = j;
|
|
count++;
|
|
if (count == 2) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Controls_GetConfig
|
|
=================
|
|
*/
|
|
void Controls_GetConfig( void )
|
|
{
|
|
int i;
|
|
int twokeys[2];
|
|
|
|
// iterate each command, get its numeric binding
|
|
for (i=0; i < g_bindCount; i++)
|
|
{
|
|
|
|
Controls_GetKeyAssignment(g_bindings[i].command, twokeys);
|
|
|
|
g_bindings[i].bind1 = twokeys[0];
|
|
g_bindings[i].bind2 = twokeys[1];
|
|
}
|
|
|
|
//s_controls.invertmouse.curvalue = DC->getCVarValue( "m_pitch" ) < 0;
|
|
//s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
|
|
//s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
|
|
//s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) );
|
|
//s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
|
|
//s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
|
|
//s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05, 0.75, Controls_GetCvarValue( "joy_threshold" ) );
|
|
//s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Controls_SetConfig
|
|
=================
|
|
*/
|
|
void Controls_SetConfig(qboolean restart)
|
|
{
|
|
int i;
|
|
|
|
// iterate each command, get its numeric binding
|
|
for (i=0; i < g_bindCount; i++)
|
|
{
|
|
|
|
if (g_bindings[i].bind1 != -1)
|
|
{
|
|
DC->setBinding( g_bindings[i].bind1, g_bindings[i].command );
|
|
|
|
if (g_bindings[i].bind2 != -1)
|
|
DC->setBinding( g_bindings[i].bind2, g_bindings[i].command );
|
|
}
|
|
}
|
|
|
|
//if ( s_controls.invertmouse.curvalue )
|
|
// DC->setCVar("m_pitch", va("%f),-fabs( DC->getCVarValue( "m_pitch" ) ) );
|
|
//else
|
|
// trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
|
|
|
|
//trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
|
|
//trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
|
|
//trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
|
|
//trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
|
|
//trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
|
|
//trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
|
|
//trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
|
|
DC->executeText(EXEC_APPEND, "in_restart\n");
|
|
//trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Controls_SetDefaults
|
|
=================
|
|
*/
|
|
void Controls_SetDefaults( void )
|
|
{
|
|
int i;
|
|
|
|
// iterate each command, set its default binding
|
|
for (i=0; i < g_bindCount; i++)
|
|
{
|
|
g_bindings[i].bind1 = g_bindings[i].defaultbind1;
|
|
g_bindings[i].bind2 = g_bindings[i].defaultbind2;
|
|
}
|
|
|
|
//s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0;
|
|
//s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" );
|
|
//s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" );
|
|
//s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" );
|
|
//s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" );
|
|
//s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" );
|
|
//s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
|
|
//s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" );
|
|
}
|
|
|
|
int BindingIDFromName(const char *name) {
|
|
int i;
|
|
for (i=0; i < g_bindCount; i++)
|
|
{
|
|
if (Q_stricmp(name, g_bindings[i].command) == 0) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
char g_nameBind1[32];
|
|
char g_nameBind2[32];
|
|
|
|
void BindingFromName(const char *cvar) {
|
|
int i, b1, b2;
|
|
|
|
// iterate each command, set its default binding
|
|
for (i=0; i < g_bindCount; i++)
|
|
{
|
|
if (Q_stricmp(cvar, g_bindings[i].command) == 0) {
|
|
b1 = g_bindings[i].bind1;
|
|
if (b1 == -1) {
|
|
break;
|
|
}
|
|
DC->keynumToStringBuf( b1, g_nameBind1, 32 );
|
|
Q_strupr(g_nameBind1);
|
|
|
|
b2 = g_bindings[i].bind2;
|
|
if (b2 != -1)
|
|
{
|
|
DC->keynumToStringBuf( b2, g_nameBind2, 32 );
|
|
Q_strupr(g_nameBind2);
|
|
strcat( g_nameBind1, " or " );
|
|
strcat( g_nameBind1, g_nameBind2 );
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
strcpy(g_nameBind1, "???");
|
|
}
|
|
|
|
void Item_Slider_Paint(itemDef_t *item) {
|
|
vec4_t newColor, lowLight;
|
|
float x, y;
|
|
menuDef_t *parent = (menuDef_t*)item->parent;
|
|
|
|
if (item->window.flags & WINDOW_HASFOCUS) {
|
|
lowLight[0] = 0.8 * parent->focusColor[0];
|
|
lowLight[1] = 0.8 * parent->focusColor[1];
|
|
lowLight[2] = 0.8 * parent->focusColor[2];
|
|
lowLight[3] = 0.8 * parent->focusColor[3];
|
|
LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
|
|
} else {
|
|
memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
|
|
}
|
|
|
|
y = item->window.rect.y;
|
|
if (item->text) {
|
|
Item_Text_Paint(item);
|
|
x = item->textRect.x + item->textRect.w + 8;
|
|
} else {
|
|
x = item->window.rect.x;
|
|
}
|
|
DC->setColor(newColor);
|
|
DC->drawHandlePic( x, y, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar );
|
|
|
|
x = Item_Slider_ThumbPosition(item);
|
|
DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y - 2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb );
|
|
}
|
|
|
|
void Item_Bind_Paint(itemDef_t *item) {
|
|
vec4_t newColor, lowLight;
|
|
int maxChars = 0;
|
|
menuDef_t *parent = (menuDef_t*)item->parent;
|
|
editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
|
|
if (editPtr) {
|
|
maxChars = editPtr->maxPaintChars;
|
|
}
|
|
|
|
if (item->window.flags & WINDOW_HASFOCUS) {
|
|
if (g_bindItem == item) {
|
|
lowLight[0] = 0.8f * 1.0f;
|
|
lowLight[1] = 0.8f * 0.0f;
|
|
lowLight[2] = 0.8f * 0.0f;
|
|
lowLight[3] = 0.8f * 1.0f;
|
|
} else {
|
|
lowLight[0] = 0.8f * parent->focusColor[0];
|
|
lowLight[1] = 0.8f * parent->focusColor[1];
|
|
lowLight[2] = 0.8f * parent->focusColor[2];
|
|
lowLight[3] = 0.8f * parent->focusColor[3];
|
|
}
|
|
LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
|
|
} else {
|
|
memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
|
|
}
|
|
|
|
if (item->text) {
|
|
Item_Text_Paint(item);
|
|
BindingFromName(item->cvar);
|
|
DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, 0, maxChars, item->textStyle);
|
|
} else {
|
|
DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, "FIXME", 0, maxChars, item->textStyle);
|
|
}
|
|
}
|
|
|
|
qboolean Display_KeyBindPending(void) {
|
|
return g_waitingForKey;
|
|
}
|
|
|
|
qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) {
|
|
int id;
|
|
int i;
|
|
|
|
if (!g_waitingForKey)
|
|
{
|
|
if (down && ((key == K_MOUSE1 && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory))
|
|
|| key == K_ENTER || key == K_KP_ENTER || key == K_JOY1 || key == K_JOY2 || key == K_JOY3 || key == K_JOY4)) {
|
|
g_waitingForKey = qtrue;
|
|
g_bindItem = item;
|
|
}
|
|
return qtrue;
|
|
}
|
|
else
|
|
{
|
|
if (g_bindItem == NULL) {
|
|
return qtrue;
|
|
}
|
|
|
|
if (key & K_CHAR_FLAG) {
|
|
return qtrue;
|
|
}
|
|
|
|
switch (key)
|
|
{
|
|
case K_ESCAPE:
|
|
g_waitingForKey = qfalse;
|
|
return qtrue;
|
|
|
|
case K_BACKSPACE:
|
|
id = BindingIDFromName(item->cvar);
|
|
if (id != -1) {
|
|
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;
|
|
}
|
|
}
|
|
Controls_SetConfig(qtrue);
|
|
g_waitingForKey = qfalse;
|
|
g_bindItem = NULL;
|
|
return qtrue;
|
|
|
|
case '`':
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
if (key != -1)
|
|
{
|
|
|
|
for (i=0; i < g_bindCount; i++)
|
|
{
|
|
|
|
if (g_bindings[i].bind2 == key) {
|
|
g_bindings[i].bind2 = -1;
|
|
}
|
|
|
|
if (g_bindings[i].bind1 == key)
|
|
{
|
|
g_bindings[i].bind1 = g_bindings[i].bind2;
|
|
g_bindings[i].bind2 = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
id = BindingIDFromName(item->cvar);
|
|
|
|
if (id != -1) {
|
|
if (key == -1) {
|
|
if( g_bindings[id].bind1 != -1 ) {
|
|
DC->setBinding( g_bindings[id].bind1, "" );
|
|
g_bindings[id].bind1 = -1;
|
|
}
|
|
if( g_bindings[id].bind2 != -1 ) {
|
|
DC->setBinding( g_bindings[id].bind2, "" );
|
|
g_bindings[id].bind2 = -1;
|
|
}
|
|
}
|
|
else if (g_bindings[id].bind1 == -1) {
|
|
g_bindings[id].bind1 = key;
|
|
}
|
|
else if (g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1) {
|
|
g_bindings[id].bind2 = key;
|
|
}
|
|
else {
|
|
DC->setBinding( g_bindings[id].bind1, "" );
|
|
DC->setBinding( g_bindings[id].bind2, "" );
|
|
g_bindings[id].bind1 = key;
|
|
g_bindings[id].bind2 = -1;
|
|
}
|
|
}
|
|
|
|
Controls_SetConfig(qtrue);
|
|
g_waitingForKey = qfalse;
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
|
|
void AdjustFrom640(float *x, float *y, float *w, float *h) {
|
|
//*x = *x * DC->scale + DC->bias;
|
|
*x *= DC->xscale;
|
|
*y *= DC->yscale;
|
|
*w *= DC->xscale;
|
|
*h *= DC->yscale;
|
|
}
|
|
|
|
void Item_Model_Paint(itemDef_t *item) {
|
|
float x, y, w, h;
|
|
refdef_t refdef;
|
|
refEntity_t ent;
|
|
vec3_t mins, maxs, origin;
|
|
vec3_t angles;
|
|
modelDef_t *modelPtr = (modelDef_t*)item->typeData;
|
|
|
|
if (modelPtr == NULL) {
|
|
return;
|
|
}
|
|
|
|
// 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( item->asset, mins, maxs );
|
|
|
|
origin[2] = -0.5 * ( mins[2] + maxs[2] );
|
|
origin[1] = 0.5 * ( mins[1] + maxs[1] );
|
|
|
|
// calculate distance so the model nearly fills the box
|
|
if (qtrue) {
|
|
float len = 0.5 * ( maxs[2] - mins[2] );
|
|
origin[0] = len / 0.268; // len / tan( fov/2 )
|
|
//origin[0] = len / tan(w/2);
|
|
} else {
|
|
origin[0] = item->textscale;
|
|
}
|
|
refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w;
|
|
refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h;
|
|
|
|
//refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
|
|
//xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
|
|
//refdef.fov_y = atan2( refdef.height, xx );
|
|
//refdef.fov_y *= ( 360 / M_PI );
|
|
|
|
DC->clearScene();
|
|
|
|
refdef.time = DC->realTime;
|
|
|
|
// add the model
|
|
|
|
memset( &ent, 0, sizeof(ent) );
|
|
|
|
//adjust = 5.0 * sin( (float)uis.realtime / 500 );
|
|
//adjust = 360 % (int)((float)uis.realtime / 1000);
|
|
//VectorSet( angles, 0, 0, 1 );
|
|
|
|
// use item storage to track
|
|
if (modelPtr->rotationSpeed) {
|
|
if (DC->realTime > item->window.nextTime) {
|
|
item->window.nextTime = DC->realTime + modelPtr->rotationSpeed;
|
|
modelPtr->angle = (int)(modelPtr->angle + 1) % 360;
|
|
}
|
|
}
|
|
VectorSet( angles, 0, modelPtr->angle, 0 );
|
|
AnglesToAxis( angles, ent.axis );
|
|
|
|
ent.hModel = item->asset;
|
|
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, thumb;
|
|
int count, i;
|
|
qhandle_t image;
|
|
qhandle_t optionalImage;
|
|
listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
|
|
|
|
// the listbox is horizontal or vertical and has a fixed size scroll bar going either direction
|
|
// elements are enumerated from the DC and either text or image handles are acquired from the DC as well
|
|
// textscale is used to size the text, textalignx and textaligny are used to size image elements
|
|
// there is no clipping available so only the last completely visible item is painted
|
|
count = DC->feederCount(item->special);
|
|
// default is vertical if horizontal flag is not here
|
|
if (item->window.flags & WINDOW_HORIZONTAL) {
|
|
// draw scrollbar in bottom of the window
|
|
// bar
|
|
x = item->window.rect.x + 1;
|
|
y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE - 1;
|
|
DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft);
|
|
x += SCROLLBAR_SIZE - 1;
|
|
size = item->window.rect.w - (SCROLLBAR_SIZE * 2);
|
|
DC->drawHandlePic(x, y, size+1, SCROLLBAR_SIZE, DC->Assets.scrollBar);
|
|
x += size - 1;
|
|
DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowRight);
|
|
// thumb
|
|
thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
|
|
if (thumb > x - SCROLLBAR_SIZE - 1) {
|
|
thumb = x - SCROLLBAR_SIZE - 1;
|
|
}
|
|
DC->drawHandlePic(thumb, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
|
|
//
|
|
listPtr->endPos = listPtr->startPos;
|
|
size = item->window.rect.w - 2;
|
|
// items
|
|
// size contains max available space
|
|
if (listPtr->elementStyle == LISTBOX_IMAGE) {
|
|
// fit = 0;
|
|
x = item->window.rect.x + 1;
|
|
y = item->window.rect.y + 1;
|
|
for (i = listPtr->startPos; i < count; i++) {
|
|
// always draw at least one
|
|
// which may overdraw the box if it is too small for the element
|
|
image = DC->feederItemImage(item->special, i);
|
|
if (image) {
|
|
DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
|
|
}
|
|
|
|
if (i == item->cursorPos) {
|
|
DC->drawRect(x, y, listPtr->elementWidth-1, listPtr->elementHeight-1, item->window.borderSize, item->window.borderColor);
|
|
}
|
|
|
|
size -= listPtr->elementWidth;
|
|
if (size < listPtr->elementWidth) {
|
|
listPtr->drawPadding = size; //listPtr->elementWidth - size;
|
|
break;
|
|
}
|
|
x += listPtr->elementWidth;
|
|
listPtr->endPos++;
|
|
// fit++;
|
|
}
|
|
} else {
|
|
//
|
|
}
|
|
} else {
|
|
// draw scrollbar to right side of the window
|
|
x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1;
|
|
y = item->window.rect.y + 1;
|
|
DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp);
|
|
y += SCROLLBAR_SIZE - 1;
|
|
|
|
listPtr->endPos = listPtr->startPos;
|
|
size = item->window.rect.h - (SCROLLBAR_SIZE * 2);
|
|
DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar);
|
|
y += size - 1;
|
|
DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown);
|
|
// thumb
|
|
thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
|
|
if (thumb > y - SCROLLBAR_SIZE - 1) {
|
|
thumb = y - SCROLLBAR_SIZE - 1;
|
|
}
|
|
DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
|
|
|
|
// adjust size for item painting
|
|
size = item->window.rect.h - 2;
|
|
if (listPtr->elementStyle == LISTBOX_IMAGE) {
|
|
// fit = 0;
|
|
x = item->window.rect.x + 1;
|
|
y = item->window.rect.y + 1;
|
|
for (i = listPtr->startPos; i < count; i++) {
|
|
// always draw at least one
|
|
// which may overdraw the box if it is too small for the element
|
|
image = DC->feederItemImage(item->special, i);
|
|
if (image) {
|
|
DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
|
|
}
|
|
|
|
if (i == item->cursorPos) {
|
|
DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.borderColor);
|
|
}
|
|
|
|
listPtr->endPos++;
|
|
size -= listPtr->elementWidth;
|
|
if (size < listPtr->elementHeight) {
|
|
listPtr->drawPadding = listPtr->elementHeight - size;
|
|
break;
|
|
}
|
|
y += listPtr->elementHeight;
|
|
// fit++;
|
|
}
|
|
} else {
|
|
x = item->window.rect.x + 1;
|
|
y = item->window.rect.y + 1;
|
|
for (i = listPtr->startPos; i < count; i++) {
|
|
const char *text;
|
|
// always draw at least one
|
|
// which may overdraw the box if it is too small for the element
|
|
|
|
if (listPtr->numColumns > 0) {
|
|
int j;
|
|
for (j = 0; j < listPtr->numColumns; j++) {
|
|
text = DC->feederItemText(item->special, i, j, &optionalImage);
|
|
if (optionalImage >= 0) {
|
|
DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
|
|
} else if (text) {
|
|
DC->drawText(x + 4 + listPtr->columnInfo[j].pos, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, listPtr->columnInfo[j].maxChars, item->textStyle);
|
|
}
|
|
}
|
|
} else {
|
|
text = DC->feederItemText(item->special, i, 0, &optionalImage);
|
|
if (optionalImage >= 0) {
|
|
//DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
|
|
} else if (text) {
|
|
DC->drawText(x + 4, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, 0, item->textStyle);
|
|
}
|
|
}
|
|
|
|
if (i == item->cursorPos) {
|
|
DC->fillRect(x + 2, y + 2, item->window.rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight, item->window.outlineColor);
|
|
}
|
|
|
|
size -= listPtr->elementHeight;
|
|
if (size < listPtr->elementHeight) {
|
|
listPtr->drawPadding = listPtr->elementHeight - size;
|
|
break;
|
|
}
|
|
listPtr->endPos++;
|
|
y += listPtr->elementHeight;
|
|
// fit++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Item_OwnerDraw_Paint(itemDef_t *item) {
|
|
if (item == NULL) {
|
|
return;
|
|
}
|
|
|
|
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);
|
|
for (i = 0; i < item->numColors; i++) {
|
|
if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high) {
|
|
memcpy(&color, &item->colorRanges[i].color, sizeof(color));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (item->window.flags & WINDOW_HASFOCUS) {
|
|
lowLight[0] = 0.8 * parent->focusColor[0];
|
|
lowLight[1] = 0.8 * parent->focusColor[1];
|
|
lowLight[2] = 0.8 * parent->focusColor[2];
|
|
lowLight[3] = 0.8 * parent->focusColor[3];
|
|
LerpColor(parent->focusColor,lowLight,color,0.5+0.5*sin(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)) {
|
|
Com_Memcpy(color, parent->disableColor, sizeof(vec4_t));
|
|
}
|
|
|
|
if (item->text) {
|
|
Item_Text_Paint(item);
|
|
if (item->text[0]) {
|
|
// +8 is an offset kludge to properly align owner draw items that have text combined with them
|
|
DC->ownerDrawItem(item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
|
|
} else {
|
|
DC->ownerDrawItem(item->textRect.x + item->textRect.w, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
|
|
}
|
|
} else {
|
|
DC->ownerDrawItem(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, item->textalignx, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Item_Paint(itemDef_t *item) {
|
|
vec4_t red;
|
|
menuDef_t *parent;
|
|
|
|
red[0] = red[3] = 1;
|
|
red[1] = red[2] = 0;
|
|
|
|
if (item == NULL) {
|
|
return;
|
|
}
|
|
|
|
parent = (menuDef_t*)item->parent;
|
|
|
|
if (item->window.flags & WINDOW_ORBITING) {
|
|
if (DC->realTime > item->window.nextTime) {
|
|
float rx, ry, a, c, s, w, h;
|
|
|
|
item->window.nextTime = DC->realTime + item->window.offsetTime;
|
|
// translate
|
|
w = item->window.rectClient.w / 2;
|
|
h = item->window.rectClient.h / 2;
|
|
rx = item->window.rectClient.x + w - item->window.rectEffects.x;
|
|
ry = item->window.rectClient.y + h - item->window.rectEffects.y;
|
|
a = 3 * M_PI / 180;
|
|
c = cos(a);
|
|
s = sin(a);
|
|
item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w;
|
|
item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h;
|
|
Item_UpdatePosition(item);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (item->window.flags & WINDOW_INTRANSITION) {
|
|
if (DC->realTime > item->window.nextTime) {
|
|
int done = 0;
|
|
item->window.nextTime = DC->realTime + item->window.offsetTime;
|
|
// transition the x,y
|
|
if (item->window.rectClient.x == item->window.rectEffects.x) {
|
|
done++;
|
|
} else {
|
|
if (item->window.rectClient.x < item->window.rectEffects.x) {
|
|
item->window.rectClient.x += item->window.rectEffects2.x;
|
|
if (item->window.rectClient.x > item->window.rectEffects.x) {
|
|
item->window.rectClient.x = item->window.rectEffects.x;
|
|
done++;
|
|
}
|
|
} else {
|
|
item->window.rectClient.x -= item->window.rectEffects2.x;
|
|
if (item->window.rectClient.x < item->window.rectEffects.x) {
|
|
item->window.rectClient.x = item->window.rectEffects.x;
|
|
done++;
|
|
}
|
|
}
|
|
}
|
|
if (item->window.rectClient.y == item->window.rectEffects.y) {
|
|
done++;
|
|
} else {
|
|
if (item->window.rectClient.y < item->window.rectEffects.y) {
|
|
item->window.rectClient.y += item->window.rectEffects2.y;
|
|
if (item->window.rectClient.y > item->window.rectEffects.y) {
|
|
item->window.rectClient.y = item->window.rectEffects.y;
|
|
done++;
|
|
}
|
|
} else {
|
|
item->window.rectClient.y -= item->window.rectEffects2.y;
|
|
if (item->window.rectClient.y < item->window.rectEffects.y) {
|
|
item->window.rectClient.y = item->window.rectEffects.y;
|
|
done++;
|
|
}
|
|
}
|
|
}
|
|
if (item->window.rectClient.w == item->window.rectEffects.w) {
|
|
done++;
|
|
} else {
|
|
if (item->window.rectClient.w < item->window.rectEffects.w) {
|
|
item->window.rectClient.w += item->window.rectEffects2.w;
|
|
if (item->window.rectClient.w > item->window.rectEffects.w) {
|
|
item->window.rectClient.w = item->window.rectEffects.w;
|
|
done++;
|
|
}
|
|
} else {
|
|
item->window.rectClient.w -= item->window.rectEffects2.w;
|
|
if (item->window.rectClient.w < item->window.rectEffects.w) {
|
|
item->window.rectClient.w = item->window.rectEffects.w;
|
|
done++;
|
|
}
|
|
}
|
|
}
|
|
if (item->window.rectClient.h == item->window.rectEffects.h) {
|
|
done++;
|
|
} else {
|
|
if (item->window.rectClient.h < item->window.rectEffects.h) {
|
|
item->window.rectClient.h += item->window.rectEffects2.h;
|
|
if (item->window.rectClient.h > item->window.rectEffects.h) {
|
|
item->window.rectClient.h = item->window.rectEffects.h;
|
|
done++;
|
|
}
|
|
} else {
|
|
item->window.rectClient.h -= item->window.rectEffects2.h;
|
|
if (item->window.rectClient.h < item->window.rectEffects.h) {
|
|
item->window.rectClient.h = item->window.rectEffects.h;
|
|
done++;
|
|
}
|
|
}
|
|
}
|
|
|
|
Item_UpdatePosition(item);
|
|
|
|
if (done == 4) {
|
|
item->window.flags &= ~WINDOW_INTRANSITION;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (item->window.ownerDrawFlags && DC->ownerDrawVisible) {
|
|
if (!DC->ownerDrawVisible(item->window.ownerDrawFlags)) {
|
|
item->window.flags &= ~WINDOW_VISIBLE;
|
|
} else {
|
|
item->window.flags |= WINDOW_VISIBLE;
|
|
}
|
|
}
|
|
|
|
if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE)) {
|
|
if (!Item_EnableShowViaCvar(item, CVAR_SHOW)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (item->window.flags & WINDOW_TIMEDVISIBLE) {
|
|
|
|
}
|
|
|
|
if (!(item->window.flags & WINDOW_VISIBLE)) {
|
|
return;
|
|
}
|
|
|
|
// paint the rect first..
|
|
Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle);
|
|
|
|
if (debugMode) {
|
|
vec4_t color;
|
|
rectDef_t *r = Item_CorrectedTextRect(item);
|
|
color[1] = color[3] = 1;
|
|
color[0] = color[2] = 0;
|
|
DC->drawRect(r->x, r->y, r->w, r->h, 1, color);
|
|
}
|
|
|
|
//DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red);
|
|
|
|
switch (item->type) {
|
|
case ITEM_TYPE_OWNERDRAW:
|
|
Item_OwnerDraw_Paint(item);
|
|
break;
|
|
case ITEM_TYPE_TEXT:
|
|
case ITEM_TYPE_BUTTON:
|
|
Item_Text_Paint(item);
|
|
break;
|
|
case ITEM_TYPE_RADIOBUTTON:
|
|
break;
|
|
case ITEM_TYPE_CHECKBOX:
|
|
break;
|
|
case ITEM_TYPE_EDITFIELD:
|
|
case ITEM_TYPE_NUMERICFIELD:
|
|
Item_TextField_Paint(item);
|
|
break;
|
|
case ITEM_TYPE_COMBO:
|
|
break;
|
|
case ITEM_TYPE_LISTBOX:
|
|
Item_ListBox_Paint(item);
|
|
break;
|
|
//case ITEM_TYPE_IMAGE:
|
|
// Item_Image_Paint(item);
|
|
// break;
|
|
case ITEM_TYPE_MODEL:
|
|
Item_Model_Paint(item);
|
|
break;
|
|
case ITEM_TYPE_YESNO:
|
|
Item_YesNo_Paint(item);
|
|
break;
|
|
case ITEM_TYPE_MULTI:
|
|
Item_Multi_Paint(item);
|
|
break;
|
|
case ITEM_TYPE_BIND:
|
|
Item_Bind_Paint(item);
|
|
break;
|
|
case ITEM_TYPE_SLIDER:
|
|
Item_Slider_Paint(item);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void Menu_Init(menuDef_t *menu) {
|
|
memset(menu, 0, sizeof(menuDef_t));
|
|
menu->cursorItem = -1;
|
|
menu->fadeAmount = DC->Assets.fadeAmount;
|
|
menu->fadeClamp = DC->Assets.fadeClamp;
|
|
menu->fadeCycle = DC->Assets.fadeCycle;
|
|
Window_Init(&menu->window);
|
|
}
|
|
|
|
itemDef_t *Menu_GetFocusedItem(menuDef_t *menu) {
|
|
int i;
|
|
if (menu) {
|
|
for (i = 0; i < menu->itemCount; i++) {
|
|
if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
|
|
return menu->items[i];
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
menuDef_t *Menu_GetFocused(void) {
|
|
int i;
|
|
for (i = 0; i < menuCount; i++) {
|
|
if (Menus[i].window.flags & WINDOW_HASFOCUS && Menus[i].window.flags & WINDOW_VISIBLE) {
|
|
return &Menus[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
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(void) {
|
|
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) {
|
|
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 (openMenuCount < MAX_OPEN_MENUS && focus != NULL) {
|
|
menuStack[openMenuCount++] = focus;
|
|
}
|
|
} else {
|
|
Menus[i].window.flags &= ~WINDOW_HASFOCUS;
|
|
}
|
|
}
|
|
Display_CloseCinematics();
|
|
return m;
|
|
}
|
|
|
|
|
|
void Item_Init(itemDef_t *item) {
|
|
if (item == NULL) {
|
|
return;
|
|
}
|
|
|
|
memset(item, 0, sizeof(itemDef_t));
|
|
item->textscale = 0.55f;
|
|
Window_Init(&item->window);
|
|
}
|
|
|
|
void Menu_HandleMouseMove(menuDef_t *menu, float x, float y) {
|
|
int i, pass;
|
|
qboolean focusSet = qfalse;
|
|
|
|
itemDef_t *overItem;
|
|
if (menu == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
|
|
return;
|
|
}
|
|
|
|
if (itemCapture) {
|
|
//Item_MouseMove(itemCapture, x, y);
|
|
return;
|
|
}
|
|
|
|
if (g_waitingForKey || g_editingField) {
|
|
return;
|
|
}
|
|
|
|
// FIXME: this is the whole issue of focus vs. mouse over..
|
|
// need a better overall solution as i don't like going through everything twice
|
|
for (pass = 0; pass < 2; pass++) {
|
|
for (i = 0; i < menu->itemCount; i++) {
|
|
// turn off focus each item
|
|
// menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
|
|
|
|
if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
|
|
continue;
|
|
}
|
|
|
|
// items can be enabled and disabled based on cvars
|
|
if (menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE)) {
|
|
continue;
|
|
}
|
|
|
|
if (menu->items[i]->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_SHOW)) {
|
|
continue;
|
|
}
|
|
|
|
|
|
|
|
if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
|
|
if (pass == 1) {
|
|
overItem = menu->items[i];
|
|
if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
|
|
if (!Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
|
|
continue;
|
|
}
|
|
}
|
|
// if we are over an item
|
|
if (IsVisible(overItem->window.flags)) {
|
|
// different one
|
|
Item_MouseEnter(overItem, x, y);
|
|
// Item_SetMouseOver(overItem, qtrue);
|
|
|
|
// if item is not a decoration see if it can take focus
|
|
if (!focusSet) {
|
|
focusSet = Item_SetFocus(overItem, x, y);
|
|
}
|
|
}
|
|
}
|
|
} else if (menu->items[i] && menu->items[i]->window.flags & WINDOW_MOUSEOVER) {
|
|
Item_MouseLeave(menu->items[i]);
|
|
Item_SetMouseOver(menu->items[i], qfalse);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void Menu_Paint(menuDef_t *menu, qboolean forcePaint) {
|
|
int i;
|
|
|
|
if (menu == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (!(menu->window.flags & WINDOW_VISIBLE) && !forcePaint) {
|
|
return;
|
|
}
|
|
|
|
if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags)) {
|
|
return;
|
|
}
|
|
|
|
if (forcePaint) {
|
|
menu->window.flags |= WINDOW_FORCED;
|
|
}
|
|
|
|
// draw the background if necessary
|
|
if (menu->fullScreen) {
|
|
// implies a background shader
|
|
// FIXME: make sure we have a default shader if fullscreen is set with no background
|
|
DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background );
|
|
} else if (menu->window.background) {
|
|
// this allows a background shader without being full screen
|
|
//UI_DrawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader);
|
|
}
|
|
|
|
// paint the background and or border
|
|
Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle );
|
|
|
|
for (i = 0; i < menu->itemCount; i++) {
|
|
Item_Paint(menu->items[i]);
|
|
}
|
|
|
|
if (debugMode) {
|
|
vec4_t color;
|
|
color[0] = color[2] = color[3] = 1;
|
|
color[1] = 0;
|
|
DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color);
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
Item_ValidateTypeData
|
|
===============
|
|
*/
|
|
void Item_ValidateTypeData(itemDef_t *item) {
|
|
if (item->typeData) {
|
|
return;
|
|
}
|
|
|
|
if (item->type == ITEM_TYPE_LISTBOX) {
|
|
item->typeData = UI_Alloc(sizeof(listBoxDef_t));
|
|
memset(item->typeData, 0, sizeof(listBoxDef_t));
|
|
} else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD || item->type == ITEM_TYPE_YESNO || item->type == ITEM_TYPE_BIND || item->type == ITEM_TYPE_SLIDER || item->type == ITEM_TYPE_TEXT) {
|
|
item->typeData = UI_Alloc(sizeof(editFieldDef_t));
|
|
memset(item->typeData, 0, sizeof(editFieldDef_t));
|
|
if (item->type == ITEM_TYPE_EDITFIELD) {
|
|
if (!((editFieldDef_t *) item->typeData)->maxPaintChars) {
|
|
((editFieldDef_t *) item->typeData)->maxPaintChars = MAX_EDITFIELD;
|
|
}
|
|
}
|
|
} else if (item->type == ITEM_TYPE_MULTI) {
|
|
item->typeData = UI_Alloc(sizeof(multiDef_t));
|
|
} else if (item->type == ITEM_TYPE_MODEL) {
|
|
item->typeData = UI_Alloc(sizeof(modelDef_t));
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
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 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 <string>
|
|
qboolean ItemParse_name( itemDef_t *item, int handle ) {
|
|
if (!PC_String_Parse(handle, &item->window.name)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
// name <string>
|
|
qboolean ItemParse_focusSound( itemDef_t *item, int handle ) {
|
|
const char *temp;
|
|
if (!PC_String_Parse(handle, &temp)) {
|
|
return qfalse;
|
|
}
|
|
item->focusSound = DC->registerSound(temp, qfalse);
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
// text <string>
|
|
qboolean ItemParse_text( itemDef_t *item, int handle ) {
|
|
if (!PC_String_Parse(handle, &item->text)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
// group <string>
|
|
qboolean ItemParse_group( itemDef_t *item, int handle ) {
|
|
if (!PC_String_Parse(handle, &item->window.group)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
// asset_model <string>
|
|
qboolean ItemParse_asset_model( itemDef_t *item, int handle ) {
|
|
const char *temp;
|
|
modelDef_t *modelPtr;
|
|
Item_ValidateTypeData(item);
|
|
modelPtr = (modelDef_t*)item->typeData;
|
|
|
|
if (!PC_String_Parse(handle, &temp)) {
|
|
return qfalse;
|
|
}
|
|
item->asset = DC->registerModel(temp);
|
|
modelPtr->angle = rand() % 360;
|
|
return qtrue;
|
|
}
|
|
|
|
// asset_shader <string>
|
|
qboolean ItemParse_asset_shader( itemDef_t *item, int handle ) {
|
|
const char *temp;
|
|
|
|
if (!PC_String_Parse(handle, &temp)) {
|
|
return qfalse;
|
|
}
|
|
item->asset = DC->registerShaderNoMip(temp);
|
|
return qtrue;
|
|
}
|
|
|
|
// model_origin <number> <number> <number>
|
|
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 <number>
|
|
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 <number>
|
|
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 <integer>
|
|
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 <integer>
|
|
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;
|
|
}
|
|
|
|
// rect <rectangle>
|
|
qboolean ItemParse_rect( itemDef_t *item, int handle ) {
|
|
if (!PC_Rect_Parse(handle, &item->window.rectClient)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
// style <integer>
|
|
qboolean ItemParse_style( itemDef_t *item, int handle ) {
|
|
if (!PC_Int_Parse(handle, &item->window.style)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
// decoration
|
|
qboolean ItemParse_decoration( itemDef_t *item, int handle ) {
|
|
item->window.flags |= WINDOW_DECORATION;
|
|
return qtrue;
|
|
}
|
|
|
|
// notselectable
|
|
qboolean ItemParse_notselectable( itemDef_t *item, int handle ) {
|
|
listBoxDef_t *listPtr;
|
|
Item_ValidateTypeData(item);
|
|
listPtr = (listBoxDef_t*)item->typeData;
|
|
if (item->type == ITEM_TYPE_LISTBOX && listPtr) {
|
|
listPtr->notselectable = qtrue;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
// manually wrapped
|
|
qboolean ItemParse_wrapped( itemDef_t *item, int handle ) {
|
|
item->window.flags |= WINDOW_WRAPPED;
|
|
return qtrue;
|
|
}
|
|
|
|
// auto wrapped
|
|
qboolean ItemParse_autowrapped( itemDef_t *item, int handle ) {
|
|
item->window.flags |= WINDOW_AUTOWRAPPED;
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
// horizontalscroll
|
|
qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) {
|
|
item->window.flags |= WINDOW_HORIZONTAL;
|
|
return qtrue;
|
|
}
|
|
|
|
// type <integer>
|
|
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 <float>
|
|
qboolean ItemParse_feeder( itemDef_t *item, int handle ) {
|
|
if (!PC_Float_Parse(handle, &item->special)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
// elementtype, used to specify what type of elements a listbox contains
|
|
// uses textstyle for storage
|
|
qboolean ItemParse_elementtype( itemDef_t *item, int handle ) {
|
|
listBoxDef_t *listPtr;
|
|
|
|
Item_ValidateTypeData(item);
|
|
if (!item->typeData)
|
|
return qfalse;
|
|
listPtr = (listBoxDef_t*)item->typeData;
|
|
if (!PC_Int_Parse(handle, &listPtr->elementStyle)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
// columns sets a number of columns and an x pos and width per..
|
|
qboolean ItemParse_columns( itemDef_t *item, int handle ) {
|
|
int num, i;
|
|
listBoxDef_t *listPtr;
|
|
|
|
Item_ValidateTypeData(item);
|
|
if (!item->typeData)
|
|
return qfalse;
|
|
listPtr = (listBoxDef_t*)item->typeData;
|
|
if (PC_Int_Parse(handle, &num)) {
|
|
if (num > MAX_LB_COLUMNS) {
|
|
num = MAX_LB_COLUMNS;
|
|
}
|
|
listPtr->numColumns = num;
|
|
for (i = 0; i < num; i++) {
|
|
int pos, width, maxChars;
|
|
|
|
if (PC_Int_Parse(handle, &pos) && PC_Int_Parse(handle, &width) && PC_Int_Parse(handle, &maxChars)) {
|
|
listPtr->columnInfo[i].pos = pos;
|
|
listPtr->columnInfo[i].width = width;
|
|
listPtr->columnInfo[i].maxChars = maxChars;
|
|
} else {
|
|
return qfalse;
|
|
}
|
|
}
|
|
} else {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_border( itemDef_t *item, int handle ) {
|
|
if (!PC_Int_Parse(handle, &item->window.border)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_bordersize( itemDef_t *item, int handle ) {
|
|
if (!PC_Float_Parse(handle, &item->window.borderSize)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_visible( itemDef_t *item, int handle ) {
|
|
int i;
|
|
|
|
if (!PC_Int_Parse(handle, &i)) {
|
|
return qfalse;
|
|
}
|
|
if (i) {
|
|
item->window.flags |= WINDOW_VISIBLE;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_ownerdraw( itemDef_t *item, int handle ) {
|
|
if (!PC_Int_Parse(handle, &item->window.ownerDraw)) {
|
|
return qfalse;
|
|
}
|
|
item->type = ITEM_TYPE_OWNERDRAW;
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_align( itemDef_t *item, int handle ) {
|
|
if (!PC_Int_Parse(handle, &item->alignment)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_textalign( itemDef_t *item, int handle ) {
|
|
if (!PC_Int_Parse(handle, &item->textalignment)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_textalignx( itemDef_t *item, int handle ) {
|
|
if (!PC_Float_Parse(handle, &item->textalignx)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_textaligny( itemDef_t *item, int handle ) {
|
|
if (!PC_Float_Parse(handle, &item->textaligny)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_textscale( itemDef_t *item, int handle ) {
|
|
if (!PC_Float_Parse(handle, &item->textscale)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_textstyle( itemDef_t *item, int handle ) {
|
|
if (!PC_Int_Parse(handle, &item->textStyle)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_backcolor( itemDef_t *item, int handle ) {
|
|
int i;
|
|
float f;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (!PC_Float_Parse(handle, &f)) {
|
|
return qfalse;
|
|
}
|
|
item->window.backColor[i] = f;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_forecolor( itemDef_t *item, int handle ) {
|
|
int i;
|
|
float f;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (!PC_Float_Parse(handle, &f)) {
|
|
return qfalse;
|
|
}
|
|
item->window.foreColor[i] = f;
|
|
item->window.flags |= WINDOW_FORECOLORSET;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_bordercolor( itemDef_t *item, int handle ) {
|
|
int i;
|
|
float f;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (!PC_Float_Parse(handle, &f)) {
|
|
return qfalse;
|
|
}
|
|
item->window.borderColor[i] = f;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_outlinecolor( itemDef_t *item, int handle ) {
|
|
if (!PC_Color_Parse(handle, &item->window.outlineColor)){
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_background( itemDef_t *item, int handle ) {
|
|
const char *temp;
|
|
|
|
if (!PC_String_Parse(handle, &temp)) {
|
|
return qfalse;
|
|
}
|
|
item->window.background = DC->registerShaderNoMip(temp);
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_cinematic( itemDef_t *item, int handle ) {
|
|
if (!PC_String_Parse(handle, &item->window.cinematicName)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_doubleClick( itemDef_t *item, int handle ) {
|
|
listBoxDef_t *listPtr;
|
|
|
|
Item_ValidateTypeData(item);
|
|
if (!item->typeData) {
|
|
return qfalse;
|
|
}
|
|
|
|
listPtr = (listBoxDef_t*)item->typeData;
|
|
|
|
if (!PC_Script_Parse(handle, &listPtr->doubleClick)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_onFocus( itemDef_t *item, int handle ) {
|
|
if (!PC_Script_Parse(handle, &item->onFocus)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_leaveFocus( itemDef_t *item, int handle ) {
|
|
if (!PC_Script_Parse(handle, &item->leaveFocus)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_mouseEnter( itemDef_t *item, int handle ) {
|
|
if (!PC_Script_Parse(handle, &item->mouseEnter)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_mouseExit( itemDef_t *item, int handle ) {
|
|
if (!PC_Script_Parse(handle, &item->mouseExit)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_mouseEnterText( itemDef_t *item, int handle ) {
|
|
if (!PC_Script_Parse(handle, &item->mouseEnterText)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_mouseExitText( itemDef_t *item, int handle ) {
|
|
if (!PC_Script_Parse(handle, &item->mouseExitText)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_action( itemDef_t *item, int handle ) {
|
|
if (!PC_Script_Parse(handle, &item->action)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_special( itemDef_t *item, int handle ) {
|
|
if (!PC_Float_Parse(handle, &item->special)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) {
|
|
if (!PC_String_Parse(handle, &item->cvarTest)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_cvar( itemDef_t *item, int handle ) {
|
|
editFieldDef_t *editPtr;
|
|
|
|
Item_ValidateTypeData(item);
|
|
if (!PC_String_Parse(handle, &item->cvar)) {
|
|
return qfalse;
|
|
}
|
|
if (item->typeData) {
|
|
editPtr = (editFieldDef_t*)item->typeData;
|
|
editPtr->minVal = -1;
|
|
editPtr->maxVal = -1;
|
|
editPtr->defVal = -1;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_maxChars( itemDef_t *item, int handle ) {
|
|
editFieldDef_t *editPtr;
|
|
int maxChars;
|
|
|
|
Item_ValidateTypeData(item);
|
|
if (!item->typeData)
|
|
return qfalse;
|
|
|
|
if (!PC_Int_Parse(handle, &maxChars)) {
|
|
return qfalse;
|
|
}
|
|
editPtr = (editFieldDef_t*)item->typeData;
|
|
editPtr->maxChars = maxChars;
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_maxPaintChars( itemDef_t *item, int handle ) {
|
|
editFieldDef_t *editPtr;
|
|
int maxChars;
|
|
|
|
Item_ValidateTypeData(item);
|
|
if (!item->typeData)
|
|
return qfalse;
|
|
|
|
if (!PC_Int_Parse(handle, &maxChars)) {
|
|
return qfalse;
|
|
}
|
|
editPtr = (editFieldDef_t*)item->typeData;
|
|
editPtr->maxPaintChars = maxChars;
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
|
|
qboolean ItemParse_cvarFloat( itemDef_t *item, int handle ) {
|
|
editFieldDef_t *editPtr;
|
|
|
|
Item_ValidateTypeData(item);
|
|
if (!item->typeData)
|
|
return qfalse;
|
|
editPtr = (editFieldDef_t*)item->typeData;
|
|
if (PC_String_Parse(handle, &item->cvar) &&
|
|
PC_Float_Parse(handle, &editPtr->defVal) &&
|
|
PC_Float_Parse(handle, &editPtr->minVal) &&
|
|
PC_Float_Parse(handle, &editPtr->maxVal)) {
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) {
|
|
pc_token_t token;
|
|
multiDef_t *multiPtr;
|
|
int pass;
|
|
|
|
Item_ValidateTypeData(item);
|
|
if (!item->typeData)
|
|
return qfalse;
|
|
multiPtr = (multiDef_t*)item->typeData;
|
|
multiPtr->count = 0;
|
|
multiPtr->strDef = qtrue;
|
|
multiPtr->videoMode = qfalse;
|
|
|
|
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");
|
|
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;
|
|
}
|
|
|
|
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;
|
|
multiPtr->videoMode = 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");
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
qboolean ItemParse_addColorRange( itemDef_t *item, int handle ) {
|
|
colorRangeDef_t color;
|
|
|
|
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_ownerdrawFlag( itemDef_t *item, int handle ) {
|
|
int i;
|
|
if (!PC_Int_Parse(handle, &i)) {
|
|
return qfalse;
|
|
}
|
|
item->window.ownerDrawFlags |= i;
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean ItemParse_enableCvar( itemDef_t *item, int handle ) {
|
|
if (PC_Script_Parse(handle, &item->enableCvar)) {
|
|
item->cvarFlags = CVAR_ENABLE;
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean ItemParse_disableCvar( itemDef_t *item, int handle ) {
|
|
if (PC_Script_Parse(handle, &item->enableCvar)) {
|
|
item->cvarFlags = CVAR_DISABLE;
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean ItemParse_showCvar( itemDef_t *item, int handle ) {
|
|
if (PC_Script_Parse(handle, &item->enableCvar)) {
|
|
item->cvarFlags = CVAR_SHOW;
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean ItemParse_hideCvar( itemDef_t *item, int handle ) {
|
|
if (PC_Script_Parse(handle, &item->enableCvar)) {
|
|
item->cvarFlags = CVAR_HIDE;
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
|
|
keywordHash_t itemParseKeywords[] = {
|
|
{"name", ItemParse_name, NULL},
|
|
{"text", ItemParse_text, NULL},
|
|
{"group", ItemParse_group, NULL},
|
|
{"asset_model", ItemParse_asset_model, NULL},
|
|
{"asset_shader", ItemParse_asset_shader, NULL},
|
|
{"model_origin", ItemParse_model_origin, NULL},
|
|
{"model_fovx", ItemParse_model_fovx, NULL},
|
|
{"model_fovy", ItemParse_model_fovy, NULL},
|
|
{"model_rotation", ItemParse_model_rotation, NULL},
|
|
{"model_angle", ItemParse_model_angle, NULL},
|
|
{"rect", ItemParse_rect, NULL},
|
|
{"style", ItemParse_style, NULL},
|
|
{"decoration", ItemParse_decoration, NULL},
|
|
{"notselectable", ItemParse_notselectable, NULL},
|
|
{"wrapped", ItemParse_wrapped, NULL},
|
|
{"autowrapped", ItemParse_autowrapped, NULL},
|
|
{"horizontalscroll", ItemParse_horizontalscroll, NULL},
|
|
{"type", ItemParse_type, NULL},
|
|
{"elementwidth", ItemParse_elementwidth, NULL},
|
|
{"elementheight", ItemParse_elementheight, NULL},
|
|
{"feeder", ItemParse_feeder, NULL},
|
|
{"elementtype", ItemParse_elementtype, NULL},
|
|
{"columns", ItemParse_columns, NULL},
|
|
{"border", ItemParse_border, NULL},
|
|
{"bordersize", ItemParse_bordersize, NULL},
|
|
{"visible", ItemParse_visible, NULL},
|
|
{"ownerdraw", ItemParse_ownerdraw, NULL},
|
|
{"align", ItemParse_align, NULL},
|
|
{"textalign", ItemParse_textalign, NULL},
|
|
{"textalignx", ItemParse_textalignx, NULL},
|
|
{"textaligny", ItemParse_textaligny, NULL},
|
|
{"textscale", ItemParse_textscale, NULL},
|
|
{"textstyle", ItemParse_textstyle, NULL},
|
|
{"backcolor", ItemParse_backcolor, NULL},
|
|
{"forecolor", ItemParse_forecolor, NULL},
|
|
{"bordercolor", ItemParse_bordercolor, NULL},
|
|
{"outlinecolor", ItemParse_outlinecolor, NULL},
|
|
{"background", ItemParse_background, NULL},
|
|
{"onFocus", ItemParse_onFocus, NULL},
|
|
{"leaveFocus", ItemParse_leaveFocus, NULL},
|
|
{"mouseEnter", ItemParse_mouseEnter, NULL},
|
|
{"mouseExit", ItemParse_mouseExit, NULL},
|
|
{"mouseEnterText", ItemParse_mouseEnterText, NULL},
|
|
{"mouseExitText", ItemParse_mouseExitText, NULL},
|
|
{"action", ItemParse_action, NULL},
|
|
{"special", ItemParse_special, NULL},
|
|
{"cvar", ItemParse_cvar, NULL},
|
|
{"maxChars", ItemParse_maxChars, NULL},
|
|
{"maxPaintChars", ItemParse_maxPaintChars, NULL},
|
|
{"focusSound", ItemParse_focusSound, NULL},
|
|
{"cvarFloat", ItemParse_cvarFloat, NULL},
|
|
{"cvarStrList", ItemParse_cvarStrList, NULL},
|
|
{"cvarFloatList", ItemParse_cvarFloatList, NULL},
|
|
{"addColorRange", ItemParse_addColorRange, NULL},
|
|
{"ownerdrawFlag", ItemParse_ownerdrawFlag, NULL},
|
|
{"enableCvar", ItemParse_enableCvar, NULL},
|
|
{"cvarTest", ItemParse_cvarTest, NULL},
|
|
{"disableCvar", ItemParse_disableCvar, NULL},
|
|
{"showCvar", ItemParse_showCvar, NULL},
|
|
{"hideCvar", ItemParse_hideCvar, NULL},
|
|
{"cinematic", ItemParse_cinematic, NULL},
|
|
{"doubleclick", ItemParse_doubleClick, NULL},
|
|
{NULL, 0, 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]);
|
|
}
|
|
}
|
|
|
|
static const char *builtinResolutions[ ] =
|
|
{
|
|
"320x240",
|
|
"400x300",
|
|
"512x384",
|
|
"640x480",
|
|
"800x600",
|
|
"960x720",
|
|
"1024x768",
|
|
"1152x864",
|
|
"1280x1024",
|
|
"1600x1200",
|
|
"2048x1536",
|
|
"856x480",
|
|
NULL
|
|
};
|
|
|
|
static const char *knownRatios[ ][2] =
|
|
{
|
|
{ "1.25:1", "5:4" },
|
|
{ "1.33:1", "4:3" },
|
|
{ "1.50:1", "3:2" },
|
|
{ "1.56:1", "14:9" },
|
|
{ "1.60:1", "16:10" },
|
|
{ "1.67:1", "5:3" },
|
|
{ "1.78:1", "16:9" },
|
|
{ NULL , NULL }
|
|
};
|
|
|
|
/*
|
|
===============
|
|
UI_ResolutionToAspect
|
|
===============
|
|
*/
|
|
static void UI_ResolutionToAspect( const char *resolution, char *aspect, size_t aspectLength ) {
|
|
int i, w, h;
|
|
char *x;
|
|
char str[8];
|
|
|
|
// calculate resolution's aspect ratio
|
|
x = strchr( resolution, 'x' ) + 1;
|
|
Q_strncpyz( str, resolution, MIN( x-resolution, sizeof( str ) ) );
|
|
w = atoi( str );
|
|
h = atoi( x );
|
|
Com_sprintf( aspect, aspectLength, "%.2f:1", (float)w / (float)h );
|
|
|
|
// rename common ratios ("1.33:1" -> "4:3")
|
|
for( i = 0; knownRatios[i][0]; i++ ) {
|
|
if( !Q_stricmp( aspect, knownRatios[i][0] ) ) {
|
|
Q_strncpyz( aspect, knownRatios[i][1], aspectLength );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
Item_ApplyHacks
|
|
|
|
Hacks to fix issues with Team Arena menu scripts
|
|
===============
|
|
*/
|
|
static void Item_ApplyHacks( itemDef_t *item ) {
|
|
|
|
// Fix length of favorite address in createfavorite.menu
|
|
if ( item->type == ITEM_TYPE_EDITFIELD && item->cvar && !Q_stricmp( item->cvar, "ui_favoriteAddress" ) ) {
|
|
editFieldDef_t *editField = (editFieldDef_t *)item->typeData;
|
|
|
|
// enough to hold an IPv6 address plus null
|
|
if ( editField->maxChars < 48 ) {
|
|
Com_Printf( "Extended create favorite address edit field length to hold an IPv6 address\n" );
|
|
editField->maxChars = 48;
|
|
}
|
|
}
|
|
|
|
if ( item->type == ITEM_TYPE_EDITFIELD && item->cvar && ( !Q_stricmp( item->cvar, "ui_Name" ) || !Q_stricmp( item->cvar, "ui_findplayer" ) ) ) {
|
|
editFieldDef_t *editField = (editFieldDef_t *)item->typeData;
|
|
|
|
// enough to hold a full player name
|
|
if ( editField->maxChars < MAX_NAME_LENGTH ) {
|
|
if ( editField->maxPaintChars > editField->maxChars ) {
|
|
editField->maxPaintChars = editField->maxChars;
|
|
}
|
|
|
|
Com_Printf( "Extended player name field using cvar %s to %d characters\n", item->cvar, MAX_NAME_LENGTH );
|
|
editField->maxChars = MAX_NAME_LENGTH;
|
|
}
|
|
}
|
|
|
|
// Replace mode list and use a temporary ui_videomode cvar for handling custom modes
|
|
if ( item->type == ITEM_TYPE_MULTI && item->cvar && !Q_stricmp( item->cvar, "r_mode" ) ) {
|
|
multiDef_t *multiPtr = (multiDef_t*)item->typeData;
|
|
int i, oldCount;
|
|
char resbuf[MAX_STRING_CHARS];
|
|
char modeName[32], aspect[8];
|
|
|
|
item->cvar = "ui_videomode";
|
|
multiPtr->strDef = qtrue;
|
|
multiPtr->videoMode = qtrue;
|
|
|
|
oldCount = multiPtr->count;
|
|
multiPtr->count = 0;
|
|
|
|
DC->getCVarString( "r_availableModes", resbuf, sizeof( resbuf ) );
|
|
|
|
if ( *resbuf ) {
|
|
char *s = resbuf, *mode;
|
|
|
|
while ( s && multiPtr->count < MAX_MULTI_CVARS ) {
|
|
mode = s;
|
|
|
|
s = strchr(s, ' ');
|
|
if( s )
|
|
*s++ = '\0';
|
|
|
|
UI_ResolutionToAspect( mode, aspect, sizeof( aspect ) );
|
|
Com_sprintf( modeName, sizeof( modeName ), "%s (%s)", mode, aspect );
|
|
|
|
multiPtr->cvarList[multiPtr->count] = String_Alloc( modeName );
|
|
|
|
for ( i = 0; builtinResolutions[i]; i++ ) {
|
|
if( !Q_stricmp( builtinResolutions[i], mode ) ) {
|
|
multiPtr->cvarStr[multiPtr->count] = builtinResolutions[i];
|
|
multiPtr->cvarValue[multiPtr->count] = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( builtinResolutions[i] == NULL ) {
|
|
multiPtr->cvarStr[multiPtr->count] = String_Alloc( mode );
|
|
multiPtr->cvarValue[multiPtr->count] = -1;
|
|
}
|
|
|
|
multiPtr->count++;
|
|
}
|
|
} else {
|
|
for ( i = 0; builtinResolutions[i] && multiPtr->count < MAX_MULTI_CVARS; i++ ) {
|
|
UI_ResolutionToAspect( builtinResolutions[i], aspect, sizeof( aspect ) );
|
|
Com_sprintf( modeName, sizeof( modeName ), "%s (%s)", builtinResolutions[i], aspect );
|
|
|
|
multiPtr->cvarList[multiPtr->count] = String_Alloc( modeName );
|
|
multiPtr->cvarStr[multiPtr->count] = builtinResolutions[i];
|
|
multiPtr->cvarValue[multiPtr->count] = i;
|
|
multiPtr->count++;
|
|
}
|
|
}
|
|
|
|
// Add custom resolution if not in mode list
|
|
if ( multiPtr->count < MAX_MULTI_CVARS ) {
|
|
char currentResolution[20];
|
|
|
|
Com_sprintf( currentResolution, sizeof ( currentResolution ), "%dx%d", DC->glconfig.vidWidth, DC->glconfig.vidHeight );
|
|
for ( i = 0; i < multiPtr->count; i++ ) {
|
|
if ( !Q_stricmp( multiPtr->cvarStr[i], currentResolution ) ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( i == multiPtr->count ) {
|
|
UI_ResolutionToAspect( currentResolution, aspect, sizeof( aspect ) );
|
|
Com_sprintf( modeName, sizeof( modeName ), "%s (%s)", currentResolution, aspect );
|
|
|
|
multiPtr->cvarList[multiPtr->count] = String_Alloc( modeName );
|
|
multiPtr->cvarStr[multiPtr->count] = String_Alloc( currentResolution );
|
|
multiPtr->cvarValue[multiPtr->count] = -1;
|
|
multiPtr->count++;
|
|
}
|
|
}
|
|
|
|
Com_Printf( "Found video mode list with %d modes, replaced list with %d modes\n", oldCount, multiPtr->count );
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
===============
|
|
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");
|
|
return qfalse;
|
|
}
|
|
|
|
if (*token.string == '}') {
|
|
Item_ApplyHacks( item );
|
|
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;
|
|
}
|
|
|
|
|
|
// Item_InitControls
|
|
// init's special control types
|
|
void Item_InitControls(itemDef_t *item) {
|
|
if (item == NULL) {
|
|
return;
|
|
}
|
|
if (item->type == ITEM_TYPE_LISTBOX) {
|
|
listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
|
|
item->cursorPos = 0;
|
|
if (listPtr) {
|
|
listPtr->cursorPos = 0;
|
|
listPtr->startPos = 0;
|
|
listPtr->endPos = 0;
|
|
listPtr->cursorPos = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
Menu Keyword Parse functions
|
|
===============
|
|
*/
|
|
|
|
qboolean MenuParse_font( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (!PC_String_Parse(handle, &menu->font)) {
|
|
return qfalse;
|
|
}
|
|
if (!DC->Assets.fontRegistered) {
|
|
DC->registerFont(menu->font, 48, &DC->Assets.textFont);
|
|
DC->Assets.fontRegistered = qtrue;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_name( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (!PC_String_Parse(handle, &menu->window.name)) {
|
|
return qfalse;
|
|
}
|
|
if (Q_stricmp(menu->window.name, "main") == 0) {
|
|
// default main as having focus
|
|
//menu->window.flags |= WINDOW_HASFOCUS;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_fullscreen( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
union
|
|
{
|
|
qboolean b;
|
|
int i;
|
|
} fullScreen;
|
|
|
|
if (!PC_Int_Parse(handle, &fullScreen.i)) {
|
|
return qfalse;
|
|
}
|
|
menu->fullScreen = fullScreen.b;
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_rect( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (!PC_Rect_Parse(handle, &menu->window.rect)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_style( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (!PC_Int_Parse(handle, &menu->window.style)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_visible( itemDef_t *item, int handle ) {
|
|
int i;
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
if (!PC_Int_Parse(handle, &i)) {
|
|
return qfalse;
|
|
}
|
|
if (i) {
|
|
menu->window.flags |= WINDOW_VISIBLE;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_onOpen( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (!PC_Script_Parse(handle, &menu->onOpen)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_onClose( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (!PC_Script_Parse(handle, &menu->onClose)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_onESC( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (!PC_Script_Parse(handle, &menu->onESC)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
|
|
qboolean MenuParse_border( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (!PC_Int_Parse(handle, &menu->window.border)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_borderSize( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (!PC_Float_Parse(handle, &menu->window.borderSize)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_backcolor( itemDef_t *item, int handle ) {
|
|
int i;
|
|
float f;
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (!PC_Float_Parse(handle, &f)) {
|
|
return qfalse;
|
|
}
|
|
menu->window.backColor[i] = f;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_forecolor( itemDef_t *item, int handle ) {
|
|
int i;
|
|
float f;
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (!PC_Float_Parse(handle, &f)) {
|
|
return qfalse;
|
|
}
|
|
menu->window.foreColor[i] = f;
|
|
menu->window.flags |= WINDOW_FORECOLORSET;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_bordercolor( itemDef_t *item, int handle ) {
|
|
int i;
|
|
float f;
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (!PC_Float_Parse(handle, &f)) {
|
|
return qfalse;
|
|
}
|
|
menu->window.borderColor[i] = f;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_focuscolor( itemDef_t *item, int handle ) {
|
|
int i;
|
|
float f;
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (!PC_Float_Parse(handle, &f)) {
|
|
return qfalse;
|
|
}
|
|
menu->focusColor[i] = f;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) {
|
|
int i;
|
|
float f;
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
for (i = 0; i < 4; i++) {
|
|
if (!PC_Float_Parse(handle, &f)) {
|
|
return qfalse;
|
|
}
|
|
menu->disableColor[i] = f;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
qboolean MenuParse_outlinecolor( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (!PC_Color_Parse(handle, &menu->window.outlineColor)){
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_background( itemDef_t *item, int handle ) {
|
|
const char *buff;
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
if (!PC_String_Parse(handle, &buff)) {
|
|
return qfalse;
|
|
}
|
|
menu->window.background = DC->registerShaderNoMip(buff);
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_cinematic( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
if (!PC_String_Parse(handle, &menu->window.cinematicName)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_ownerdrawFlag( itemDef_t *item, int handle ) {
|
|
int i;
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
if (!PC_Int_Parse(handle, &i)) {
|
|
return qfalse;
|
|
}
|
|
menu->window.ownerDrawFlags |= i;
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_ownerdraw( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
if (!PC_Int_Parse(handle, &menu->window.ownerDraw)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
// decoration
|
|
qboolean MenuParse_popup( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
menu->window.flags |= WINDOW_POPUP;
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
qboolean MenuParse_outOfBounds( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
menu->window.flags |= WINDOW_OOB_CLICK;
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_soundLoop( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
if (!PC_String_Parse(handle, &menu->soundName)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_fadeClamp( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
if (!PC_Float_Parse(handle, &menu->fadeClamp)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
qboolean MenuParse_fadeAmount( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
if (!PC_Float_Parse(handle, &menu->fadeAmount)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
qboolean MenuParse_fadeCycle( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
|
|
if (!PC_Int_Parse(handle, &menu->fadeCycle)) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
|
|
qboolean MenuParse_itemDef( itemDef_t *item, int handle ) {
|
|
menuDef_t *menu = (menuDef_t*)item;
|
|
if (menu->itemCount < MAX_MENUITEMS) {
|
|
menu->items[menu->itemCount] = UI_Alloc(sizeof(itemDef_t));
|
|
if (!menu->items[menu->itemCount]) {
|
|
return qfalse;
|
|
}
|
|
Item_Init(menu->items[menu->itemCount]);
|
|
if (!Item_Parse(handle, menu->items[menu->itemCount])) {
|
|
return qfalse;
|
|
}
|
|
Item_InitControls(menu->items[menu->itemCount]);
|
|
menu->items[menu->itemCount++]->parent = menu;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
keywordHash_t menuParseKeywords[] = {
|
|
{"font", MenuParse_font, NULL},
|
|
{"name", MenuParse_name, NULL},
|
|
{"fullscreen", MenuParse_fullscreen, NULL},
|
|
{"rect", MenuParse_rect, NULL},
|
|
{"style", MenuParse_style, NULL},
|
|
{"visible", MenuParse_visible, NULL},
|
|
{"onOpen", MenuParse_onOpen, NULL},
|
|
{"onClose", MenuParse_onClose, NULL},
|
|
{"onESC", MenuParse_onESC, NULL},
|
|
{"border", MenuParse_border, NULL},
|
|
{"borderSize", MenuParse_borderSize, NULL},
|
|
{"backcolor", MenuParse_backcolor, NULL},
|
|
{"forecolor", MenuParse_forecolor, NULL},
|
|
{"bordercolor", MenuParse_bordercolor, NULL},
|
|
{"focuscolor", MenuParse_focuscolor, NULL},
|
|
{"disablecolor", MenuParse_disablecolor, NULL},
|
|
{"outlinecolor", MenuParse_outlinecolor, NULL},
|
|
{"background", MenuParse_background, NULL},
|
|
{"ownerdraw", MenuParse_ownerdraw, NULL},
|
|
{"ownerdrawFlag", MenuParse_ownerdrawFlag, NULL},
|
|
{"outOfBoundsClick", MenuParse_outOfBounds, NULL},
|
|
{"soundLoop", MenuParse_soundLoop, NULL},
|
|
{"itemDef", MenuParse_itemDef, NULL},
|
|
{"cinematic", MenuParse_cinematic, NULL},
|
|
{"popup", MenuParse_popup, NULL},
|
|
{"fadeClamp", MenuParse_fadeClamp, NULL},
|
|
{"fadeCycle", MenuParse_fadeCycle, NULL},
|
|
{"fadeAmount", MenuParse_fadeAmount, NULL},
|
|
{NULL, 0, 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");
|
|
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;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
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(void) {
|
|
return menuCount;
|
|
}
|
|
|
|
void Menu_PaintAll(void) {
|
|
int i;
|
|
if (captureFunc) {
|
|
captureFunc(captureData);
|
|
}
|
|
|
|
for (i = 0; i < Menu_Count(); i++) {
|
|
Menu_Paint(&Menus[i], qfalse);
|
|
}
|
|
|
|
if (debugMode) {
|
|
vec4_t v = {1, 1, 1, 1};
|
|
DC->drawText(5, 25, .5, v, va("fps: %f", DC->FPS), 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
void Menu_Reset(void) {
|
|
menuCount = 0;
|
|
}
|
|
|
|
displayContextDef_t *Display_GetContext(void) {
|
|
return DC;
|
|
}
|
|
|
|
#ifndef MISSIONPACK
|
|
static float captureX;
|
|
static float captureY;
|
|
#endif
|
|
|
|
void *Display_CaptureItem(int x, int y) {
|
|
int i;
|
|
|
|
for (i = 0; i < menuCount; i++) {
|
|
// turn off focus each item
|
|
// menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
|
|
if (Rect_ContainsPoint(&Menus[i].window.rect, x, y)) {
|
|
return &Menus[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// FIXME:
|
|
qboolean Display_MouseMove(void *p, int x, int y) {
|
|
int i;
|
|
menuDef_t *menu = p;
|
|
|
|
if (menu == NULL) {
|
|
menu = Menu_GetFocused();
|
|
if (menu) {
|
|
if (menu->window.flags & WINDOW_POPUP) {
|
|
Menu_HandleMouseMove(menu, x, y);
|
|
return qtrue;
|
|
}
|
|
}
|
|
for (i = 0; i < menuCount; i++) {
|
|
Menu_HandleMouseMove(&Menus[i], x, y);
|
|
}
|
|
} else {
|
|
menu->window.rect.x += x;
|
|
menu->window.rect.y += y;
|
|
Menu_UpdatePosition(menu);
|
|
}
|
|
return qtrue;
|
|
|
|
}
|
|
|
|
int Display_CursorType(int x, int y) {
|
|
int i;
|
|
for (i = 0; i < menuCount; i++) {
|
|
rectDef_t r2;
|
|
r2.x = Menus[i].window.rect.x - 3;
|
|
r2.y = Menus[i].window.rect.y - 3;
|
|
r2.w = r2.h = 7;
|
|
if (Rect_ContainsPoint(&r2, x, y)) {
|
|
return CURSOR_SIZER;
|
|
}
|
|
}
|
|
return CURSOR_ARROW;
|
|
}
|
|
|
|
|
|
void Display_HandleKey(int key, qboolean down, int x, int y) {
|
|
menuDef_t *menu = Display_CaptureItem(x, y);
|
|
if (menu == NULL) {
|
|
menu = Menu_GetFocused();
|
|
}
|
|
if (menu) {
|
|
Menu_HandleKey(menu, key, down );
|
|
}
|
|
}
|
|
|
|
static void Window_CacheContents(windowDef_t *window) {
|
|
if (window) {
|
|
if (window->cinematicName) {
|
|
int cin = DC->playCinematic(window->cinematicName, 0, 0, 0, 0);
|
|
DC->stopCinematic(cin);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void Item_CacheContents(itemDef_t *item) {
|
|
if (item) {
|
|
Window_CacheContents(&item->window);
|
|
}
|
|
|
|
}
|
|
|
|
static void Menu_CacheContents(menuDef_t *menu) {
|
|
if (menu) {
|
|
int i;
|
|
Window_CacheContents(&menu->window);
|
|
for (i = 0; i < menu->itemCount; i++) {
|
|
Item_CacheContents(menu->items[i]);
|
|
}
|
|
|
|
if (menu->soundName && *menu->soundName) {
|
|
DC->registerSound(menu->soundName, qfalse);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void Display_CacheAll(void) {
|
|
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;
|
|
}
|
|
|