Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

ui_shared.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // 
00023 // string allocation/managment
00024 
00025 #include "ui_shared.h"
00026 
00027 #define SCROLL_TIME_START                   500
00028 #define SCROLL_TIME_ADJUST              150
00029 #define SCROLL_TIME_ADJUSTOFFSET    40
00030 #define SCROLL_TIME_FLOOR                   20
00031 
00032 typedef struct scrollInfo_s {
00033     int nextScrollTime;
00034     int nextAdjustTime;
00035     int adjustValue;
00036     int scrollKey;
00037     float xStart;
00038     float yStart;
00039     itemDef_t *item;
00040     qboolean scrollDir;
00041 } scrollInfo_t;
00042 
00043 static scrollInfo_t scrollInfo;
00044 
00045 static void (*captureFunc) (void *p) = NULL;
00046 static void *captureData = NULL;
00047 static itemDef_t *itemCapture = NULL;   // item that has the mouse captured ( if any )
00048 
00049 displayContextDef_t *DC = NULL;
00050 
00051 static qboolean g_waitingForKey = qfalse;
00052 static qboolean g_editingField = qfalse;
00053 
00054 static itemDef_t *g_bindItem = NULL;
00055 static itemDef_t *g_editItem = NULL;
00056 
00057 menuDef_t Menus[MAX_MENUS];      // defined menus
00058 int menuCount = 0;               // how many
00059 
00060 menuDef_t *menuStack[MAX_OPEN_MENUS];
00061 int openMenuCount = 0;
00062 
00063 static qboolean debugMode = qfalse;
00064 
00065 #define DOUBLE_CLICK_DELAY 300
00066 static int lastListBoxClickTime = 0;
00067 
00068 void Item_RunScript(itemDef_t *item, const char *s);
00069 void Item_SetupKeywordHash(void);
00070 void Menu_SetupKeywordHash(void);
00071 int BindingIDFromName(const char *name);
00072 qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down);
00073 itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu);
00074 itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu);
00075 static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y);
00076 
00077 #ifdef CGAME
00078 #define MEM_POOL_SIZE  128 * 1024
00079 #else
00080 #define MEM_POOL_SIZE  1024 * 1024
00081 #endif
00082 
00083 static char     memoryPool[MEM_POOL_SIZE];
00084 static int      allocPoint, outOfMemory;
00085 
00086 
00087 /*
00088 ===============
00089 UI_Alloc
00090 ===============
00091 */                
00092 void *UI_Alloc( int size ) {
00093     char    *p; 
00094 
00095     if ( allocPoint + size > MEM_POOL_SIZE ) {
00096         outOfMemory = qtrue;
00097         if (DC->Print) {
00098             DC->Print("UI_Alloc: Failure. Out of memory!\n");
00099         }
00100     //DC->trap_Print(S_COLOR_YELLOW"WARNING: UI Out of Memory!\n");
00101         return NULL;
00102     }
00103 
00104     p = &memoryPool[allocPoint];
00105 
00106     allocPoint += ( size + 15 ) & ~15;
00107 
00108     return p;
00109 }
00110 
00111 /*
00112 ===============
00113 UI_InitMemory
00114 ===============
00115 */
00116 void UI_InitMemory( void ) {
00117     allocPoint = 0;
00118     outOfMemory = qfalse;
00119 }
00120 
00121 qboolean UI_OutOfMemory() {
00122     return outOfMemory;
00123 }
00124 
00125 
00126 
00127 
00128 
00129 #define HASH_TABLE_SIZE 2048
00130 /*
00131 ================
00132 return a hash value for the string
00133 ================
00134 */
00135 static long hashForString(const char *str) {
00136     int     i;
00137     long    hash;
00138     char    letter;
00139 
00140     hash = 0;
00141     i = 0;
00142     while (str[i] != '\0') {
00143         letter = tolower(str[i]);
00144         hash+=(long)(letter)*(i+119);
00145         i++;
00146     }
00147     hash &= (HASH_TABLE_SIZE-1);
00148     return hash;
00149 }
00150 
00151 typedef struct stringDef_s {
00152     struct stringDef_s *next;
00153     const char *str;
00154 } stringDef_t;
00155 
00156 static int strPoolIndex = 0;
00157 static char strPool[STRING_POOL_SIZE];
00158 
00159 static int strHandleCount = 0;
00160 static stringDef_t *strHandle[HASH_TABLE_SIZE];
00161 
00162 
00163 const char *String_Alloc(const char *p) {
00164     int len;
00165     long hash;
00166     stringDef_t *str, *last;
00167     static const char *staticNULL = "";
00168 
00169     if (p == NULL) {
00170         return NULL;
00171     }
00172 
00173     if (*p == 0) {
00174         return staticNULL;
00175     }
00176 
00177     hash = hashForString(p);
00178 
00179     str = strHandle[hash];
00180     while (str) {
00181         if (strcmp(p, str->str) == 0) {
00182             return str->str;
00183         }
00184         str = str->next;
00185     }
00186 
00187     len = strlen(p);
00188     if (len + strPoolIndex + 1 < STRING_POOL_SIZE) {
00189         int ph = strPoolIndex;
00190         strcpy(&strPool[strPoolIndex], p);
00191         strPoolIndex += len + 1;
00192 
00193         str = strHandle[hash];
00194         last = str;
00195         while (str && str->next) {
00196             last = str;
00197             str = str->next;
00198         }
00199 
00200         str  = UI_Alloc(sizeof(stringDef_t));
00201         str->next = NULL;
00202         str->str = &strPool[ph];
00203         if (last) {
00204             last->next = str;
00205         } else {
00206             strHandle[hash] = str;
00207         }
00208         return &strPool[ph];
00209     }
00210     return NULL;
00211 }
00212 
00213 void String_Report() {
00214     float f;
00215     Com_Printf("Memory/String Pool Info\n");
00216     Com_Printf("----------------\n");
00217     f = strPoolIndex;
00218     f /= STRING_POOL_SIZE;
00219     f *= 100;
00220     Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE);
00221     f = allocPoint;
00222     f /= MEM_POOL_SIZE;
00223     f *= 100;
00224     Com_Printf("Memory Pool is %.1f%% full, %i bytes out of %i used.\n", f, allocPoint, MEM_POOL_SIZE);
00225 }
00226 
00227 /*
00228 =================
00229 String_Init
00230 =================
00231 */
00232 void String_Init() {
00233     int i;
00234     for (i = 0; i < HASH_TABLE_SIZE; i++) {
00235         strHandle[i] = 0;
00236     }
00237     strHandleCount = 0;
00238     strPoolIndex = 0;
00239     menuCount = 0;
00240     openMenuCount = 0;
00241     UI_InitMemory();
00242     Item_SetupKeywordHash();
00243     Menu_SetupKeywordHash();
00244     if (DC && DC->getBindingBuf) {
00245         Controls_GetConfig();
00246     }
00247 }
00248 
00249 /*
00250 =================
00251 PC_SourceWarning
00252 =================
00253 */
00254 void PC_SourceWarning(int handle, char *format, ...) {
00255     int line;
00256     char filename[128];
00257     va_list argptr;
00258     static char string[4096];
00259 
00260     va_start (argptr, format);
00261     vsprintf (string, format, argptr);
00262     va_end (argptr);
00263 
00264     filename[0] = '\0';
00265     line = 0;
00266     trap_PC_SourceFileAndLine(handle, filename, &line);
00267 
00268     Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string);
00269 }
00270 
00271 /*
00272 =================
00273 PC_SourceError
00274 =================
00275 */
00276 void PC_SourceError(int handle, char *format, ...) {
00277     int line;
00278     char filename[128];
00279     va_list argptr;
00280     static char string[4096];
00281 
00282     va_start (argptr, format);
00283     vsprintf (string, format, argptr);
00284     va_end (argptr);
00285 
00286     filename[0] = '\0';
00287     line = 0;
00288     trap_PC_SourceFileAndLine(handle, filename, &line);
00289 
00290     Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string);
00291 }
00292 
00293 /*
00294 =================
00295 LerpColor
00296 =================
00297 */
00298 void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
00299 {
00300     int i;
00301 
00302     // lerp and clamp each component
00303     for (i=0; i<4; i++)
00304     {
00305         c[i] = a[i] + t*(b[i]-a[i]);
00306         if (c[i] < 0)
00307             c[i] = 0;
00308         else if (c[i] > 1.0)
00309             c[i] = 1.0;
00310     }
00311 }
00312 
00313 /*
00314 =================
00315 Float_Parse
00316 =================
00317 */
00318 qboolean Float_Parse(char **p, float *f) {
00319     char    *token;
00320     token = COM_ParseExt(p, qfalse);
00321     if (token && token[0] != 0) {
00322         *f = atof(token);
00323         return qtrue;
00324     } else {
00325         return qfalse;
00326     }
00327 }
00328 
00329 /*
00330 =================
00331 PC_Float_Parse
00332 =================
00333 */
00334 qboolean PC_Float_Parse(int handle, float *f) {
00335     pc_token_t token;
00336     int negative = qfalse;
00337 
00338     if (!trap_PC_ReadToken(handle, &token))
00339         return qfalse;
00340     if (token.string[0] == '-') {
00341         if (!trap_PC_ReadToken(handle, &token))
00342             return qfalse;
00343         negative = qtrue;
00344     }
00345     if (token.type != TT_NUMBER) {
00346         PC_SourceError(handle, "expected float but found %s\n", token.string);
00347         return qfalse;
00348     }
00349     if (negative)
00350         *f = -token.floatvalue;
00351     else
00352         *f = token.floatvalue;
00353     return qtrue;
00354 }
00355 
00356 /*
00357 =================
00358 Color_Parse
00359 =================
00360 */
00361 qboolean Color_Parse(char **p, vec4_t *c) {
00362     int i;
00363     float f;
00364 
00365     for (i = 0; i < 4; i++) {
00366         if (!Float_Parse(p, &f)) {
00367             return qfalse;
00368         }
00369         (*c)[i] = f;
00370     }
00371     return qtrue;
00372 }
00373 
00374 /*
00375 =================
00376 PC_Color_Parse
00377 =================
00378 */
00379 qboolean PC_Color_Parse(int handle, vec4_t *c) {
00380     int i;
00381     float f;
00382 
00383     for (i = 0; i < 4; i++) {
00384         if (!PC_Float_Parse(handle, &f)) {
00385             return qfalse;
00386         }
00387         (*c)[i] = f;
00388     }
00389     return qtrue;
00390 }
00391 
00392 /*
00393 =================
00394 Int_Parse
00395 =================
00396 */
00397 qboolean Int_Parse(char **p, int *i) {
00398     char    *token;
00399     token = COM_ParseExt(p, qfalse);
00400 
00401     if (token && token[0] != 0) {
00402         *i = atoi(token);
00403         return qtrue;
00404     } else {
00405         return qfalse;
00406     }
00407 }
00408 
00409 /*
00410 =================
00411 PC_Int_Parse
00412 =================
00413 */
00414 qboolean PC_Int_Parse(int handle, int *i) {
00415     pc_token_t token;
00416     int negative = qfalse;
00417 
00418     if (!trap_PC_ReadToken(handle, &token))
00419         return qfalse;
00420     if (token.string[0] == '-') {
00421         if (!trap_PC_ReadToken(handle, &token))
00422             return qfalse;
00423         negative = qtrue;
00424     }
00425     if (token.type != TT_NUMBER) {
00426         PC_SourceError(handle, "expected integer but found %s\n", token.string);
00427         return qfalse;
00428     }
00429     *i = token.intvalue;
00430     if (negative)
00431         *i = - *i;
00432     return qtrue;
00433 }
00434 
00435 /*
00436 =================
00437 Rect_Parse
00438 =================
00439 */
00440 qboolean Rect_Parse(char **p, rectDef_t *r) {
00441     if (Float_Parse(p, &r->x)) {
00442         if (Float_Parse(p, &r->y)) {
00443             if (Float_Parse(p, &r->w)) {
00444                 if (Float_Parse(p, &r->h)) {
00445                     return qtrue;
00446                 }
00447             }
00448         }
00449     }
00450     return qfalse;
00451 }
00452 
00453 /*
00454 =================
00455 PC_Rect_Parse
00456 =================
00457 */
00458 qboolean PC_Rect_Parse(int handle, rectDef_t *r) {
00459     if (PC_Float_Parse(handle, &r->x)) {
00460         if (PC_Float_Parse(handle, &r->y)) {
00461             if (PC_Float_Parse(handle, &r->w)) {
00462                 if (PC_Float_Parse(handle, &r->h)) {
00463                     return qtrue;
00464                 }
00465             }
00466         }
00467     }
00468     return qfalse;
00469 }
00470 
00471 /*
00472 =================
00473 String_Parse
00474 =================
00475 */
00476 qboolean String_Parse(char **p, const char **out) {
00477     char *token;
00478 
00479     token = COM_ParseExt(p, qfalse);
00480     if (token && token[0] != 0) {
00481         *(out) = String_Alloc(token);
00482         return qtrue;
00483     }
00484     return qfalse;
00485 }
00486 
00487 /*
00488 =================
00489 PC_String_Parse
00490 =================
00491 */
00492 qboolean PC_String_Parse(int handle, const char **out) {
00493     pc_token_t token;
00494 
00495     if (!trap_PC_ReadToken(handle, &token))
00496         return qfalse;
00497     
00498     *(out) = String_Alloc(token.string);
00499     return qtrue;
00500 }
00501 
00502 /*
00503 =================
00504 PC_Script_Parse
00505 =================
00506 */
00507 qboolean PC_Script_Parse(int handle, const char **out) {
00508     char script[1024];
00509     pc_token_t token;
00510 
00511     memset(script, 0, sizeof(script));
00512     // scripts start with { and have ; separated command lists.. commands are command, arg.. 
00513     // basically we want everything between the { } as it will be interpreted at run time
00514   
00515     if (!trap_PC_ReadToken(handle, &token))
00516         return qfalse;
00517     if (Q_stricmp(token.string, "{") != 0) {
00518         return qfalse;
00519     }
00520 
00521     while ( 1 ) {
00522         if (!trap_PC_ReadToken(handle, &token))
00523             return qfalse;
00524 
00525         if (Q_stricmp(token.string, "}") == 0) {
00526             *out = String_Alloc(script);
00527             return qtrue;
00528         }
00529 
00530         if (token.string[1] != '\0') {
00531             Q_strcat(script, 1024, va("\"%s\"", token.string));
00532         } else {
00533             Q_strcat(script, 1024, token.string);
00534         }
00535         Q_strcat(script, 1024, " ");
00536     }
00537     return qfalse;  // bk001105 - LCC   missing return value
00538 }
00539 
00540 // display, window, menu, item code
00541 // 
00542 
00543 /*
00544 ==================
00545 Init_Display
00546 
00547 Initializes the display with a structure to all the drawing routines
00548  ==================
00549 */
00550 void Init_Display(displayContextDef_t *dc) {
00551     DC = dc;
00552 }
00553 
00554 
00555 
00556 // type and style painting 
00557 
00558 void GradientBar_Paint(rectDef_t *rect, vec4_t color) {
00559     // gradient bar takes two paints
00560     DC->setColor( color );
00561     DC->drawHandlePic(rect->x, rect->y, rect->w, rect->h, DC->Assets.gradientBar);
00562     DC->setColor( NULL );
00563 }
00564 
00565 
00566 /*
00567 ==================
00568 Window_Init
00569 
00570 Initializes a window structure ( windowDef_t ) with defaults
00571  
00572 ==================
00573 */
00574 void Window_Init(Window *w) {
00575     memset(w, 0, sizeof(windowDef_t));
00576     w->borderSize = 1;
00577     w->foreColor[0] = w->foreColor[1] = w->foreColor[2] = w->foreColor[3] = 1.0;
00578     w->cinematic = -1;
00579 }
00580 
00581 void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount) {
00582   if (*flags & (WINDOW_FADINGOUT | WINDOW_FADINGIN)) {
00583     if (DC->realTime > *nextTime) {
00584       *nextTime = DC->realTime + offsetTime;
00585       if (*flags & WINDOW_FADINGOUT) {
00586         *f -= fadeAmount;
00587         if (bFlags && *f <= 0.0) {
00588           *flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE);
00589         }
00590       } else {
00591         *f += fadeAmount;
00592         if (*f >= clamp) {
00593           *f = clamp;
00594           if (bFlags) {
00595             *flags &= ~WINDOW_FADINGIN;
00596           }
00597         }
00598       }
00599     }
00600   }
00601 }
00602 
00603 
00604 
00605 void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle) {
00606   //float bordersize = 0;
00607   vec4_t color;
00608   rectDef_t fillRect = w->rect;
00609 
00610 
00611   if (debugMode) {
00612     color[0] = color[1] = color[2] = color[3] = 1;
00613     DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, 1, color);
00614   }
00615 
00616   if (w == NULL || (w->style == 0 && w->border == 0)) {
00617     return;
00618   }
00619 
00620   if (w->border != 0) {
00621     fillRect.x += w->borderSize;
00622     fillRect.y += w->borderSize;
00623     fillRect.w -= w->borderSize + 1;
00624     fillRect.h -= w->borderSize + 1;
00625   }
00626 
00627   if (w->style == WINDOW_STYLE_FILLED) {
00628     // box, but possible a shader that needs filled
00629         if (w->background) {
00630           Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount);
00631       DC->setColor(w->backColor);
00632         DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
00633           DC->setColor(NULL);
00634         } else {
00635         DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor);
00636         }
00637   } else if (w->style == WINDOW_STYLE_GRADIENT) {
00638     GradientBar_Paint(&fillRect, w->backColor);
00639     // gradient bar
00640   } else if (w->style == WINDOW_STYLE_SHADER) {
00641     if (w->flags & WINDOW_FORECOLORSET) {
00642       DC->setColor(w->foreColor);
00643     }
00644     DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
00645     DC->setColor(NULL);
00646   } else if (w->style == WINDOW_STYLE_TEAMCOLOR) {
00647     if (DC->getTeamColor) {
00648       DC->getTeamColor(&color);
00649       DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, color);
00650     }
00651   } else if (w->style == WINDOW_STYLE_CINEMATIC) {
00652         if (w->cinematic == -1) {
00653             w->cinematic = DC->playCinematic(w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
00654             if (w->cinematic == -1) {
00655                 w->cinematic = -2;
00656             }
00657         } 
00658         if (w->cinematic >= 0) {
00659         DC->runCinematicFrame(w->cinematic);
00660             DC->drawCinematic(w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
00661         }
00662   }
00663 
00664   if (w->border == WINDOW_BORDER_FULL) {
00665     // full
00666     // HACK HACK HACK
00667     if (w->style == WINDOW_STYLE_TEAMCOLOR) {
00668       if (color[0] > 0) { 
00669         // red
00670         color[0] = 1;
00671         color[1] = color[2] = .5;
00672 
00673       } else {
00674         color[2] = 1;
00675         color[0] = color[1] = .5;
00676       }
00677       color[3] = 1;
00678       DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, color);
00679     } else {
00680       DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor);
00681     }
00682   } else if (w->border == WINDOW_BORDER_HORZ) {
00683     // top/bottom
00684     DC->setColor(w->borderColor);
00685     DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
00686     DC->setColor( NULL );
00687   } else if (w->border == WINDOW_BORDER_VERT) {
00688     // left right
00689     DC->setColor(w->borderColor);
00690     DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
00691     DC->setColor( NULL );
00692   } else if (w->border == WINDOW_BORDER_KCGRADIENT) {
00693     // this is just two gradient bars along each horz edge
00694     rectDef_t r = w->rect;
00695     r.h = w->borderSize;
00696     GradientBar_Paint(&r, w->borderColor);
00697     r.y = w->rect.y + w->rect.h - 1;
00698     GradientBar_Paint(&r, w->borderColor);
00699   }
00700 
00701 }
00702 
00703 
00704 void Item_SetScreenCoords(itemDef_t *item, float x, float y) {
00705   
00706   if (item == NULL) {
00707     return;
00708   }
00709 
00710   if (item->window.border != 0) {
00711     x += item->window.borderSize;
00712     y += item->window.borderSize;
00713   }
00714 
00715   item->window.rect.x = x + item->window.rectClient.x;
00716   item->window.rect.y = y + item->window.rectClient.y;
00717   item->window.rect.w = item->window.rectClient.w;
00718   item->window.rect.h = item->window.rectClient.h;
00719 
00720   // force the text rects to recompute
00721   item->textRect.w = 0;
00722   item->textRect.h = 0;
00723 }
00724 
00725 // FIXME: consolidate this with nearby stuff
00726 void Item_UpdatePosition(itemDef_t *item) {
00727   float x, y;
00728   menuDef_t *menu;
00729   
00730   if (item == NULL || item->parent == NULL) {
00731     return;
00732   }
00733 
00734   menu = item->parent;
00735 
00736   x = menu->window.rect.x;
00737   y = menu->window.rect.y;
00738   
00739   if (menu->window.border != 0) {
00740     x += menu->window.borderSize;
00741     y += menu->window.borderSize;
00742   }
00743 
00744   Item_SetScreenCoords(item, x, y);
00745 
00746 }
00747 
00748 // menus
00749 void Menu_UpdatePosition(menuDef_t *menu) {
00750   int i;
00751   float x, y;
00752 
00753   if (menu == NULL) {
00754     return;
00755   }
00756   
00757   x = menu->window.rect.x;
00758   y = menu->window.rect.y;
00759   if (menu->window.border != 0) {
00760     x += menu->window.borderSize;
00761     y += menu->window.borderSize;
00762   }
00763 
00764   for (i = 0; i < menu->itemCount; i++) {
00765     Item_SetScreenCoords(menu->items[i], x, y);
00766   }
00767 }
00768 
00769 void Menu_PostParse(menuDef_t *menu) {
00770     if (menu == NULL) {
00771         return;
00772     }
00773     if (menu->fullScreen) {
00774         menu->window.rect.x = 0;
00775         menu->window.rect.y = 0;
00776         menu->window.rect.w = 640;
00777         menu->window.rect.h = 480;
00778     }
00779     Menu_UpdatePosition(menu);
00780 }
00781 
00782 itemDef_t *Menu_ClearFocus(menuDef_t *menu) {
00783   int i;
00784   itemDef_t *ret = NULL;
00785 
00786   if (menu == NULL) {
00787     return NULL;
00788   }
00789 
00790   for (i = 0; i < menu->itemCount; i++) {
00791     if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
00792       ret = menu->items[i];
00793     } 
00794     menu->items[i]->window.flags &= ~WINDOW_HASFOCUS;
00795     if (menu->items[i]->leaveFocus) {
00796       Item_RunScript(menu->items[i], menu->items[i]->leaveFocus);
00797     }
00798   }
00799  
00800   return ret;
00801 }
00802 
00803 qboolean IsVisible(int flags) {
00804   return (flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT));
00805 }
00806 
00807 qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) {
00808   if (rect) {
00809     if (x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h) {
00810       return qtrue;
00811     }
00812   }
00813   return qfalse;
00814 }
00815 
00816 int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name) {
00817   int i;
00818   int count = 0;
00819   for (i = 0; i < menu->itemCount; i++) {
00820     if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
00821       count++;
00822     } 
00823   }
00824   return count;
00825 }
00826 
00827 itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name) {
00828   int i;
00829   int count = 0;
00830   for (i = 0; i < menu->itemCount; i++) {
00831     if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
00832       if (count == index) {
00833         return menu->items[i];
00834       }
00835       count++;
00836     } 
00837   }
00838   return NULL;
00839 }
00840 
00841 
00842 
00843 void Script_SetColor(itemDef_t *item, char **args) {
00844   const char *name;
00845   int i;
00846   float f;
00847   vec4_t *out;
00848   // expecting type of color to set and 4 args for the color
00849   if (String_Parse(args, &name)) {
00850       out = NULL;
00851       if (Q_stricmp(name, "backcolor") == 0) {
00852         out = &item->window.backColor;
00853         item->window.flags |= WINDOW_BACKCOLORSET;
00854       } else if (Q_stricmp(name, "forecolor") == 0) {
00855         out = &item->window.foreColor;
00856         item->window.flags |= WINDOW_FORECOLORSET;
00857       } else if (Q_stricmp(name, "bordercolor") == 0) {
00858         out = &item->window.borderColor;
00859       }
00860 
00861       if (out) {
00862         for (i = 0; i < 4; i++) {
00863           if (!Float_Parse(args, &f)) {
00864             return;
00865           }
00866           (*out)[i] = f;
00867         }
00868       }
00869   }
00870 }
00871 
00872 void Script_SetAsset(itemDef_t *item, char **args) {
00873   const char *name;
00874   // expecting name to set asset to
00875   if (String_Parse(args, &name)) {
00876     // check for a model 
00877     if (item->type == ITEM_TYPE_MODEL) {
00878     }
00879   }
00880 }
00881 
00882 void Script_SetBackground(itemDef_t *item, char **args) {
00883   const char *name;
00884   // expecting name to set asset to
00885   if (String_Parse(args, &name)) {
00886     item->window.background = DC->registerShaderNoMip(name);
00887   }
00888 }
00889 
00890 
00891 
00892 
00893 itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) {
00894   int i;
00895   if (menu == NULL || p == NULL) {
00896     return NULL;
00897   }
00898 
00899   for (i = 0; i < menu->itemCount; i++) {
00900     if (Q_stricmp(p, menu->items[i]->window.name) == 0) {
00901       return menu->items[i];
00902     }
00903   }
00904 
00905   return NULL;
00906 }
00907 
00908 void Script_SetTeamColor(itemDef_t *item, char **args) {
00909   if (DC->getTeamColor) {
00910     int i;
00911     vec4_t color;
00912     DC->getTeamColor(&color);
00913     for (i = 0; i < 4; i++) {
00914       item->window.backColor[i] = color[i];
00915     }
00916   }
00917 }
00918 
00919 void Script_SetItemColor(itemDef_t *item, char **args) {
00920   const char *itemname;
00921   const char *name;
00922   vec4_t color;
00923   int i;
00924   vec4_t *out;
00925   // expecting type of color to set and 4 args for the color
00926   if (String_Parse(args, &itemname) && String_Parse(args, &name)) {
00927     itemDef_t *item2;
00928     int j;
00929     int count = Menu_ItemsMatchingGroup(item->parent, itemname);
00930 
00931     if (!Color_Parse(args, &color)) {
00932       return;
00933     }
00934 
00935     for (j = 0; j < count; j++) {
00936       item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname);
00937       if (item2 != NULL) {
00938         out = NULL;
00939         if (Q_stricmp(name, "backcolor") == 0) {
00940           out = &item2->window.backColor;
00941         } else if (Q_stricmp(name, "forecolor") == 0) {
00942           out = &item2->window.foreColor;
00943           item2->window.flags |= WINDOW_FORECOLORSET;
00944         } else if (Q_stricmp(name, "bordercolor") == 0) {
00945           out = &item2->window.borderColor;
00946         }
00947 
00948         if (out) {
00949           for (i = 0; i < 4; i++) {
00950             (*out)[i] = color[i];
00951           }
00952         }
00953       }
00954     }
00955   }
00956 }
00957 
00958 
00959 void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow) {
00960     itemDef_t *item;
00961     int i;
00962     int count = Menu_ItemsMatchingGroup(menu, p);
00963     for (i = 0; i < count; i++) {
00964         item = Menu_GetMatchingItemByNumber(menu, i, p);
00965         if (item != NULL) {
00966             if (bShow) {
00967                 item->window.flags |= WINDOW_VISIBLE;
00968             } else {
00969                 item->window.flags &= ~WINDOW_VISIBLE;
00970                 // stop cinematics playing in the window
00971                 if (item->window.cinematic >= 0) {
00972                     DC->stopCinematic(item->window.cinematic);
00973                     item->window.cinematic = -1;
00974                 }
00975             }
00976         }
00977     }
00978 }
00979 
00980 void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut) {
00981   itemDef_t *item;
00982   int i;
00983   int count = Menu_ItemsMatchingGroup(menu, p);
00984   for (i = 0; i < count; i++) {
00985     item = Menu_GetMatchingItemByNumber(menu, i, p);
00986     if (item != NULL) {
00987       if (fadeOut) {
00988         item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE);
00989         item->window.flags &= ~WINDOW_FADINGIN;
00990       } else {
00991         item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN);
00992         item->window.flags &= ~WINDOW_FADINGOUT;
00993       }
00994     }
00995   }
00996 }
00997 
00998 menuDef_t *Menus_FindByName(const char *p) {
00999   int i;
01000   for (i = 0; i < menuCount; i++) {
01001     if (Q_stricmp(Menus[i].window.name, p) == 0) {
01002       return &Menus[i];
01003     } 
01004   }
01005   return NULL;
01006 }
01007 
01008 void Menus_ShowByName(const char *p) {
01009     menuDef_t *menu = Menus_FindByName(p);
01010     if (menu) {
01011         Menus_Activate(menu);
01012     }
01013 }
01014 
01015 void Menus_OpenByName(const char *p) {
01016   Menus_ActivateByName(p);
01017 }
01018 
01019 static void Menu_RunCloseScript(menuDef_t *menu) {
01020     if (menu && menu->window.flags & WINDOW_VISIBLE && menu->onClose) {
01021         itemDef_t item;
01022     item.parent = menu;
01023     Item_RunScript(&item, menu->onClose);
01024     }
01025 }
01026 
01027 void Menus_CloseByName(const char *p) {
01028   menuDef_t *menu = Menus_FindByName(p);
01029   if (menu != NULL) {
01030         Menu_RunCloseScript(menu);
01031         menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS);
01032   }
01033 }
01034 
01035 void Menus_CloseAll() {
01036   int i;
01037   for (i = 0; i < menuCount; i++) {
01038         Menu_RunCloseScript(&Menus[i]);
01039         Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
01040   }
01041 }
01042 
01043 
01044 void Script_Show(itemDef_t *item, char **args) {
01045   const char *name;
01046   if (String_Parse(args, &name)) {
01047     Menu_ShowItemByName(item->parent, name, qtrue);
01048   }
01049 }
01050 
01051 void Script_Hide(itemDef_t *item, char **args) {
01052   const char *name;
01053   if (String_Parse(args, &name)) {
01054     Menu_ShowItemByName(item->parent, name, qfalse);
01055   }
01056 }
01057 
01058 void Script_FadeIn(itemDef_t *item, char **args) {
01059   const char *name;
01060   if (String_Parse(args, &name)) {
01061     Menu_FadeItemByName(item->parent, name, qfalse);
01062   }
01063 }
01064 
01065 void Script_FadeOut(itemDef_t *item, char **args) {
01066   const char *name;
01067   if (String_Parse(args, &name)) {
01068     Menu_FadeItemByName(item->parent, name, qtrue);
01069   }
01070 }
01071 
01072 
01073 
01074 void Script_Open(itemDef_t *item, char **args) {
01075   const char *name;
01076   if (String_Parse(args, &name)) {
01077     Menus_OpenByName(name);
01078   }
01079 }
01080 
01081 void Script_ConditionalOpen(itemDef_t *item, char **args) {
01082     const char *cvar;
01083     const char *name1;
01084     const char *name2;
01085     float           val;
01086 
01087     if ( String_Parse(args, &cvar) && String_Parse(args, &name1) && String_Parse(args, &name2) ) {
01088         val = DC->getCVarValue( cvar );
01089         if ( val == 0.f ) {
01090             Menus_OpenByName(name2);
01091         } else {
01092             Menus_OpenByName(name1);
01093         }
01094     }
01095 }
01096 
01097 void Script_Close(itemDef_t *item, char **args) {
01098   const char *name;
01099   if (String_Parse(args, &name)) {
01100     Menus_CloseByName(name);
01101   }
01102 }
01103 
01104 void Menu_TransitionItemByName(menuDef_t *menu, const char *p, rectDef_t rectFrom, rectDef_t rectTo, int time, float amt) {
01105   itemDef_t *item;
01106   int i;
01107   int count = Menu_ItemsMatchingGroup(menu, p);
01108   for (i = 0; i < count; i++) {
01109     item = Menu_GetMatchingItemByNumber(menu, i, p);
01110     if (item != NULL) {
01111       item->window.flags |= (WINDOW_INTRANSITION | WINDOW_VISIBLE);
01112       item->window.offsetTime = time;
01113             memcpy(&item->window.rectClient, &rectFrom, sizeof(rectDef_t));
01114             memcpy(&item->window.rectEffects, &rectTo, sizeof(rectDef_t));
01115             item->window.rectEffects2.x = abs(rectTo.x - rectFrom.x) / amt;
01116             item->window.rectEffects2.y = abs(rectTo.y - rectFrom.y) / amt;
01117             item->window.rectEffects2.w = abs(rectTo.w - rectFrom.w) / amt;
01118             item->window.rectEffects2.h = abs(rectTo.h - rectFrom.h) / amt;
01119       Item_UpdatePosition(item);
01120     }
01121   }
01122 }
01123 
01124 
01125 void Script_Transition(itemDef_t *item, char **args) {
01126   const char *name;
01127     rectDef_t rectFrom, rectTo;
01128   int time;
01129     float amt;
01130 
01131   if (String_Parse(args, &name)) {
01132     if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) {
01133       Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt);
01134     }
01135   }
01136 }
01137 
01138 
01139 void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) {
01140   itemDef_t *item;
01141   int i;
01142   int count = Menu_ItemsMatchingGroup(menu, p);
01143   for (i = 0; i < count; i++) {
01144     item = Menu_GetMatchingItemByNumber(menu, i, p);
01145     if (item != NULL) {
01146       item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE);
01147       item->window.offsetTime = time;
01148       item->window.rectEffects.x = cx;
01149       item->window.rectEffects.y = cy;
01150       item->window.rectClient.x = x;
01151       item->window.rectClient.y = y;
01152       Item_UpdatePosition(item);
01153     }
01154   }
01155 }
01156 
01157 
01158 void Script_Orbit(itemDef_t *item, char **args) {
01159   const char *name;
01160   float cx, cy, x, y;
01161   int time;
01162 
01163   if (String_Parse(args, &name)) {
01164     if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) {
01165       Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time);
01166     }
01167   }
01168 }
01169 
01170 
01171 
01172 void Script_SetFocus(itemDef_t *item, char **args) {
01173   const char *name;
01174   itemDef_t *focusItem;
01175 
01176   if (String_Parse(args, &name)) {
01177     focusItem = Menu_FindItemByName(item->parent, name);
01178     if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION) && !(focusItem->window.flags & WINDOW_HASFOCUS)) {
01179       Menu_ClearFocus(item->parent);
01180       focusItem->window.flags |= WINDOW_HASFOCUS;
01181       if (focusItem->onFocus) {
01182         Item_RunScript(focusItem, focusItem->onFocus);
01183       }
01184       if (DC->Assets.itemFocusSound) {
01185         DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
01186       }
01187     }
01188   }
01189 }
01190 
01191 void Script_SetPlayerModel(itemDef_t *item, char **args) {
01192   const char *name;
01193   if (String_Parse(args, &name)) {
01194     DC->setCVar("team_model", name);
01195   }
01196 }
01197 
01198 void Script_SetPlayerHead(itemDef_t *item, char **args) {
01199   const char *name;
01200   if (String_Parse(args, &name)) {
01201     DC->setCVar("team_headmodel", name);
01202   }
01203 }
01204 
01205 void Script_SetCvar(itemDef_t *item, char **args) {
01206     const char *cvar, *val;
01207     if (String_Parse(args, &cvar) && String_Parse(args, &val)) {
01208         DC->setCVar(cvar, val);
01209     }
01210     
01211 }
01212 
01213 void Script_Exec(itemDef_t *item, char **args) {
01214     const char *val;
01215     if (String_Parse(args, &val)) {
01216         DC->executeText(EXEC_APPEND, va("%s ; ", val));
01217     }
01218 }
01219 
01220 void Script_Play(itemDef_t *item, char **args) {
01221     const char *val;
01222     if (String_Parse(args, &val)) {
01223         DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_LOCAL_SOUND);
01224     }
01225 }
01226 
01227 void Script_playLooped(itemDef_t *item, char **args) {
01228     const char *val;
01229     if (String_Parse(args, &val)) {
01230         DC->stopBackgroundTrack();
01231         DC->startBackgroundTrack(val, val);
01232     }
01233 }
01234 
01235 
01236 commandDef_t commandList[] =
01237 {
01238   {"fadein", &Script_FadeIn},                   // group/name
01239   {"fadeout", &Script_FadeOut},                 // group/name
01240   {"show", &Script_Show},                       // group/name
01241   {"hide", &Script_Hide},                       // group/name
01242   {"setcolor", &Script_SetColor},               // works on this
01243   {"open", &Script_Open},                       // menu
01244     {"conditionalopen", &Script_ConditionalOpen},   // menu
01245   {"close", &Script_Close},                     // menu
01246   {"setasset", &Script_SetAsset},               // works on this
01247   {"setbackground", &Script_SetBackground},     // works on this
01248   {"setitemcolor", &Script_SetItemColor},       // group/name
01249   {"setteamcolor", &Script_SetTeamColor},       // sets this background color to team color
01250   {"setfocus", &Script_SetFocus},               // sets this background color to team color
01251   {"setplayermodel", &Script_SetPlayerModel},   // sets this background color to team color
01252   {"setplayerhead", &Script_SetPlayerHead},     // sets this background color to team color
01253   {"transition", &Script_Transition},           // group/name
01254   {"setcvar", &Script_SetCvar},           // group/name
01255   {"exec", &Script_Exec},           // group/name
01256   {"play", &Script_Play},           // group/name
01257   {"playlooped", &Script_playLooped},           // group/name
01258   {"orbit", &Script_Orbit}                      // group/name
01259 };
01260 
01261 int scriptCommandCount = sizeof(commandList) / sizeof(commandDef_t);
01262 
01263 
01264 void Item_RunScript(itemDef_t *item, const char *s) {
01265   char script[1024], *p;
01266   int i;
01267   qboolean bRan;
01268   memset(script, 0, sizeof(script));
01269   if (item && s && s[0]) {
01270     Q_strcat(script, 1024, s);
01271     p = script;
01272     while (1) {
01273       const char *command;
01274       // expect command then arguments, ; ends command, NULL ends script
01275       if (!String_Parse(&p, &command)) {
01276         return;
01277       }
01278 
01279       if (command[0] == ';' && command[1] == '\0') {
01280         continue;
01281       }
01282 
01283       bRan = qfalse;
01284       for (i = 0; i < scriptCommandCount; i++) {
01285         if (Q_stricmp(command, commandList[i].name) == 0) {
01286           (commandList[i].handler(item, &p));
01287           bRan = qtrue;
01288           break;
01289         }
01290       }
01291       // not in our auto list, pass to handler
01292       if (!bRan) {
01293         DC->runScript(&p);
01294       }
01295     }
01296   }
01297 }
01298 
01299 
01300 qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) {
01301   char script[1024], *p;
01302   memset(script, 0, sizeof(script));
01303   if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
01304         char buff[1024];
01305       DC->getCVarString(item->cvarTest, buff, sizeof(buff));
01306 
01307     Q_strcat(script, 1024, item->enableCvar);
01308     p = script;
01309     while (1) {
01310       const char *val;
01311       // expect value then ; or NULL, NULL ends list
01312       if (!String_Parse(&p, &val)) {
01313                 return (item->cvarFlags & flag) ? qfalse : qtrue;
01314       }
01315 
01316       if (val[0] == ';' && val[1] == '\0') {
01317         continue;
01318       }
01319 
01320             // enable it if any of the values are true
01321             if (item->cvarFlags & flag) {
01322         if (Q_stricmp(buff, val) == 0) {
01323                     return qtrue;
01324                 }
01325             } else {
01326                 // disable it if any of the values are true
01327         if (Q_stricmp(buff, val) == 0) {
01328                     return qfalse;
01329                 }
01330             }
01331 
01332     }
01333         return (item->cvarFlags & flag) ? qfalse : qtrue;
01334   }
01335     return qtrue;
01336 }
01337 
01338 
01339 // will optionaly set focus to this item 
01340 qboolean Item_SetFocus(itemDef_t *item, float x, float y) {
01341     int i;
01342     itemDef_t *oldFocus;
01343     sfxHandle_t *sfx = &DC->Assets.itemFocusSound;
01344     qboolean playSound = qfalse;
01345     menuDef_t *parent; // bk001206: = (menuDef_t*)item->parent;
01346     // sanity check, non-null, not a decoration and does not already have the focus
01347     if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS || !(item->window.flags & WINDOW_VISIBLE)) {
01348         return qfalse;
01349     }
01350 
01351     // bk001206 - this can be NULL.
01352     parent = (menuDef_t*)item->parent; 
01353       
01354     // items can be enabled and disabled based on cvars
01355     if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
01356         return qfalse;
01357     }
01358 
01359     if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
01360         return qfalse;
01361     }
01362 
01363     oldFocus = Menu_ClearFocus(item->parent);
01364 
01365     if (item->type == ITEM_TYPE_TEXT) {
01366         rectDef_t r;
01367         r = item->textRect;
01368         r.y -= r.h;
01369         if (Rect_ContainsPoint(&r, x, y)) {
01370             item->window.flags |= WINDOW_HASFOCUS;
01371             if (item->focusSound) {
01372                 sfx = &item->focusSound;
01373             }
01374             playSound = qtrue;
01375         } else {
01376             if (oldFocus) {
01377                 oldFocus->window.flags |= WINDOW_HASFOCUS;
01378                 if (oldFocus->onFocus) {
01379                     Item_RunScript(oldFocus, oldFocus->onFocus);
01380                 }
01381             }
01382         }
01383     } else {
01384         item->window.flags |= WINDOW_HASFOCUS;
01385         if (item->onFocus) {
01386             Item_RunScript(item, item->onFocus);
01387         }
01388         if (item->focusSound) {
01389             sfx = &item->focusSound;
01390         }
01391         playSound = qtrue;
01392     }
01393 
01394     if (playSound && sfx) {
01395         DC->startLocalSound( *sfx, CHAN_LOCAL_SOUND );
01396     }
01397 
01398     for (i = 0; i < parent->itemCount; i++) {
01399         if (parent->items[i] == item) {
01400             parent->cursorItem = i;
01401             break;
01402         }
01403     }
01404 
01405     return qtrue;
01406 }
01407 
01408 int Item_ListBox_MaxScroll(itemDef_t *item) {
01409     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
01410     int count = DC->feederCount(item->special);
01411     int max;
01412 
01413     if (item->window.flags & WINDOW_HORIZONTAL) {
01414         max = count - (item->window.rect.w / listPtr->elementWidth) + 1;
01415     }
01416     else {
01417         max = count - (item->window.rect.h / listPtr->elementHeight) + 1;
01418     }
01419     if (max < 0) {
01420         return 0;
01421     }
01422     return max;
01423 }
01424 
01425 int Item_ListBox_ThumbPosition(itemDef_t *item) {
01426     float max, pos, size;
01427     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
01428 
01429     max = Item_ListBox_MaxScroll(item);
01430     if (item->window.flags & WINDOW_HORIZONTAL) {
01431         size = item->window.rect.w - (SCROLLBAR_SIZE * 2) - 2;
01432         if (max > 0) {
01433             pos = (size-SCROLLBAR_SIZE) / (float) max;
01434         } else {
01435             pos = 0;
01436         }
01437         pos *= listPtr->startPos;
01438         return item->window.rect.x + 1 + SCROLLBAR_SIZE + pos;
01439     }
01440     else {
01441         size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2;
01442         if (max > 0) {
01443             pos = (size-SCROLLBAR_SIZE) / (float) max;
01444         } else {
01445             pos = 0;
01446         }
01447         pos *= listPtr->startPos;
01448         return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos;
01449     }
01450 }
01451 
01452 int Item_ListBox_ThumbDrawPosition(itemDef_t *item) {
01453     int min, max;
01454 
01455     if (itemCapture == item) {
01456         if (item->window.flags & WINDOW_HORIZONTAL) {
01457             min = item->window.rect.x + SCROLLBAR_SIZE + 1;
01458             max = item->window.rect.x + item->window.rect.w - 2*SCROLLBAR_SIZE - 1;
01459             if (DC->cursorx >= min + SCROLLBAR_SIZE/2 && DC->cursorx <= max + SCROLLBAR_SIZE/2) {
01460                 return DC->cursorx - SCROLLBAR_SIZE/2;
01461             }
01462             else {
01463                 return Item_ListBox_ThumbPosition(item);
01464             }
01465         }
01466         else {
01467             min = item->window.rect.y + SCROLLBAR_SIZE + 1;
01468             max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1;
01469             if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) {
01470                 return DC->cursory - SCROLLBAR_SIZE/2;
01471             }
01472             else {
01473                 return Item_ListBox_ThumbPosition(item);
01474             }
01475         }
01476     }
01477     else {
01478         return Item_ListBox_ThumbPosition(item);
01479     }
01480 }
01481 
01482 float Item_Slider_ThumbPosition(itemDef_t *item) {
01483     float value, range, x;
01484     editFieldDef_t *editDef = item->typeData;
01485 
01486     if (item->text) {
01487         x = item->textRect.x + item->textRect.w + 8;
01488     } else {
01489         x = item->window.rect.x;
01490     }
01491 
01492     if (editDef == NULL && item->cvar) {
01493         return x;
01494     }
01495 
01496     value = DC->getCVarValue(item->cvar);
01497 
01498     if (value < editDef->minVal) {
01499         value = editDef->minVal;
01500     } else if (value > editDef->maxVal) {
01501         value = editDef->maxVal;
01502     }
01503 
01504     range = editDef->maxVal - editDef->minVal;
01505     value -= editDef->minVal;
01506     value /= range;
01507     //value /= (editDef->maxVal - editDef->minVal);
01508     value *= SLIDER_WIDTH;
01509     x += value;
01510     // vm fuckage
01511     //x = x + (((float)value / editDef->maxVal) * SLIDER_WIDTH);
01512     return x;
01513 }
01514 
01515 int Item_Slider_OverSlider(itemDef_t *item, float x, float y) {
01516     rectDef_t r;
01517 
01518     r.x = Item_Slider_ThumbPosition(item) - (SLIDER_THUMB_WIDTH / 2);
01519     r.y = item->window.rect.y - 2;
01520     r.w = SLIDER_THUMB_WIDTH;
01521     r.h = SLIDER_THUMB_HEIGHT;
01522 
01523     if (Rect_ContainsPoint(&r, x, y)) {
01524         return WINDOW_LB_THUMB;
01525     }
01526     return 0;
01527 }
01528 
01529 int Item_ListBox_OverLB(itemDef_t *item, float x, float y) {
01530     rectDef_t r;
01531     listBoxDef_t *listPtr;
01532     int thumbstart;
01533     int count;
01534 
01535     count = DC->feederCount(item->special);
01536     listPtr = (listBoxDef_t*)item->typeData;
01537     if (item->window.flags & WINDOW_HORIZONTAL) {
01538         // check if on left arrow
01539         r.x = item->window.rect.x;
01540         r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
01541         r.h = r.w = SCROLLBAR_SIZE;
01542         if (Rect_ContainsPoint(&r, x, y)) {
01543             return WINDOW_LB_LEFTARROW;
01544         }
01545         // check if on right arrow
01546         r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
01547         if (Rect_ContainsPoint(&r, x, y)) {
01548             return WINDOW_LB_RIGHTARROW;
01549         }
01550         // check if on thumb
01551         thumbstart = Item_ListBox_ThumbPosition(item);
01552         r.x = thumbstart;
01553         if (Rect_ContainsPoint(&r, x, y)) {
01554             return WINDOW_LB_THUMB;
01555         }
01556         r.x = item->window.rect.x + SCROLLBAR_SIZE;
01557         r.w = thumbstart - r.x;
01558         if (Rect_ContainsPoint(&r, x, y)) {
01559             return WINDOW_LB_PGUP;
01560         }
01561         r.x = thumbstart + SCROLLBAR_SIZE;
01562         r.w = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
01563         if (Rect_ContainsPoint(&r, x, y)) {
01564             return WINDOW_LB_PGDN;
01565         }
01566     } else {
01567         r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
01568         r.y = item->window.rect.y;
01569         r.h = r.w = SCROLLBAR_SIZE;
01570         if (Rect_ContainsPoint(&r, x, y)) {
01571             return WINDOW_LB_LEFTARROW;
01572         }
01573         r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
01574         if (Rect_ContainsPoint(&r, x, y)) {
01575             return WINDOW_LB_RIGHTARROW;
01576         }
01577         thumbstart = Item_ListBox_ThumbPosition(item);
01578         r.y = thumbstart;
01579         if (Rect_ContainsPoint(&r, x, y)) {
01580             return WINDOW_LB_THUMB;
01581         }
01582         r.y = item->window.rect.y + SCROLLBAR_SIZE;
01583         r.h = thumbstart - r.y;
01584         if (Rect_ContainsPoint(&r, x, y)) {
01585             return WINDOW_LB_PGUP;
01586         }
01587         r.y = thumbstart + SCROLLBAR_SIZE;
01588         r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
01589         if (Rect_ContainsPoint(&r, x, y)) {
01590             return WINDOW_LB_PGDN;
01591         }
01592     }
01593     return 0;
01594 }
01595 
01596 
01597 void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y) 
01598 {
01599     rectDef_t r;
01600     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
01601         
01602     item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
01603     item->window.flags |= Item_ListBox_OverLB(item, x, y);
01604 
01605     if (item->window.flags & WINDOW_HORIZONTAL) {
01606         if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
01607             // check for selection hit as we have exausted buttons and thumb
01608             if (listPtr->elementStyle == LISTBOX_IMAGE) {
01609                 r.x = item->window.rect.x;
01610                 r.y = item->window.rect.y;
01611                 r.h = item->window.rect.h - SCROLLBAR_SIZE;
01612                 r.w = item->window.rect.w - listPtr->drawPadding;
01613                 if (Rect_ContainsPoint(&r, x, y)) {
01614                     listPtr->cursorPos =  (int)((x - r.x) / listPtr->elementWidth)  + listPtr->startPos;
01615                     if (listPtr->cursorPos >= listPtr->endPos) {
01616                         listPtr->cursorPos = listPtr->endPos;
01617                     }
01618                 }
01619             } else {
01620                 // text hit.. 
01621             }
01622         }
01623     } else if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
01624         r.x = item->window.rect.x;
01625         r.y = item->window.rect.y;
01626         r.w = item->window.rect.w - SCROLLBAR_SIZE;
01627         r.h = item->window.rect.h - listPtr->drawPadding;
01628         if (Rect_ContainsPoint(&r, x, y)) {
01629             listPtr->cursorPos =  (int)((y - 2 - r.y) / listPtr->elementHeight)  + listPtr->startPos;
01630             if (listPtr->cursorPos > listPtr->endPos) {
01631                 listPtr->cursorPos = listPtr->endPos;
01632             }
01633         }
01634     }
01635 }
01636 
01637 void Item_MouseEnter(itemDef_t *item, float x, float y) {
01638     rectDef_t r;
01639     if (item) {
01640         r = item->textRect;
01641         r.y -= r.h;
01642         // in the text rect?
01643 
01644         // items can be enabled and disabled based on cvars
01645         if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
01646             return;
01647         }
01648 
01649         if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
01650             return;
01651         }
01652 
01653         if (Rect_ContainsPoint(&r, x, y)) {
01654             if (!(item->window.flags & WINDOW_MOUSEOVERTEXT)) {
01655                 Item_RunScript(item, item->mouseEnterText);
01656                 item->window.flags |= WINDOW_MOUSEOVERTEXT;
01657             }
01658             if (!(item->window.flags & WINDOW_MOUSEOVER)) {
01659                 Item_RunScript(item, item->mouseEnter);
01660                 item->window.flags |= WINDOW_MOUSEOVER;
01661             }
01662 
01663         } else {
01664             // not in the text rect
01665             if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
01666                 // if we were
01667                 Item_RunScript(item, item->mouseExitText);
01668                 item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
01669             }
01670             if (!(item->window.flags & WINDOW_MOUSEOVER)) {
01671                 Item_RunScript(item, item->mouseEnter);
01672                 item->window.flags |= WINDOW_MOUSEOVER;
01673             }
01674 
01675             if (item->type == ITEM_TYPE_LISTBOX) {
01676                 Item_ListBox_MouseEnter(item, x, y);
01677             }
01678         }
01679     }
01680 }
01681 
01682 void Item_MouseLeave(itemDef_t *item) {
01683   if (item) {
01684     if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
01685       Item_RunScript(item, item->mouseExitText);
01686       item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
01687     }
01688     Item_RunScript(item, item->mouseExit);
01689     item->window.flags &= ~(WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW);
01690   }
01691 }
01692 
01693 itemDef_t *Menu_HitTest(menuDef_t *menu, float x, float y) {
01694   int i;
01695   for (i = 0; i < menu->itemCount; i++) {
01696     if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
01697       return menu->items[i];
01698     }
01699   }
01700   return NULL;
01701 }
01702 
01703 void Item_SetMouseOver(itemDef_t *item, qboolean focus) {
01704   if (item) {
01705     if (focus) {
01706       item->window.flags |= WINDOW_MOUSEOVER;
01707     } else {
01708       item->window.flags &= ~WINDOW_MOUSEOVER;
01709     }
01710   }
01711 }
01712 
01713 
01714 qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) {
01715   if (item && DC->ownerDrawHandleKey) {
01716     return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key);
01717   }
01718   return qfalse;
01719 }
01720 
01721 qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force) {
01722     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
01723     int count = DC->feederCount(item->special);
01724     int max, viewmax;
01725 
01726     if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) {
01727         max = Item_ListBox_MaxScroll(item);
01728         if (item->window.flags & WINDOW_HORIZONTAL) {
01729             viewmax = (item->window.rect.w / listPtr->elementWidth);
01730             if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) 
01731             {
01732                 if (!listPtr->notselectable) {
01733                     listPtr->cursorPos--;
01734                     if (listPtr->cursorPos < 0) {
01735                         listPtr->cursorPos = 0;
01736                     }
01737                     if (listPtr->cursorPos < listPtr->startPos) {
01738                         listPtr->startPos = listPtr->cursorPos;
01739                     }
01740                     if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
01741                         listPtr->startPos = listPtr->cursorPos - viewmax + 1;
01742                     }
01743                     item->cursorPos = listPtr->cursorPos;
01744                     DC->feederSelection(item->special, item->cursorPos);
01745                 }
01746                 else {
01747                     listPtr->startPos--;
01748                     if (listPtr->startPos < 0)
01749                         listPtr->startPos = 0;
01750                 }
01751                 return qtrue;
01752             }
01753             if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) 
01754             {
01755                 if (!listPtr->notselectable) {
01756                     listPtr->cursorPos++;
01757                     if (listPtr->cursorPos < listPtr->startPos) {
01758                         listPtr->startPos = listPtr->cursorPos;
01759                     }
01760                     if (listPtr->cursorPos >= count) {
01761                         listPtr->cursorPos = count-1;
01762                     }
01763                     if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
01764                         listPtr->startPos = listPtr->cursorPos - viewmax + 1;
01765                     }
01766                     item->cursorPos = listPtr->cursorPos;
01767                     DC->feederSelection(item->special, item->cursorPos);
01768                 }
01769                 else {
01770                     listPtr->startPos++;
01771                     if (listPtr->startPos >= count)
01772                         listPtr->startPos = count-1;
01773                 }
01774                 return qtrue;
01775             }
01776         }
01777         else {
01778             viewmax = (item->window.rect.h / listPtr->elementHeight);
01779             if ( key == K_UPARROW || key == K_KP_UPARROW ) 
01780             {
01781                 if (!listPtr->notselectable) {
01782                     listPtr->cursorPos--;
01783                     if (listPtr->cursorPos < 0) {
01784                         listPtr->cursorPos = 0;
01785                     }
01786                     if (listPtr->cursorPos < listPtr->startPos) {
01787                         listPtr->startPos = listPtr->cursorPos;
01788                     }
01789                     if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
01790                         listPtr->startPos = listPtr->cursorPos - viewmax + 1;
01791                     }
01792                     item->cursorPos = listPtr->cursorPos;
01793                     DC->feederSelection(item->special, item->cursorPos);
01794                 }
01795                 else {
01796                     listPtr->startPos--;
01797                     if (listPtr->startPos < 0)
01798                         listPtr->startPos = 0;
01799                 }
01800                 return qtrue;
01801             }
01802             if ( key == K_DOWNARROW || key == K_KP_DOWNARROW ) 
01803             {
01804                 if (!listPtr->notselectable) {
01805                     listPtr->cursorPos++;
01806                     if (listPtr->cursorPos < listPtr->startPos) {
01807                         listPtr->startPos = listPtr->cursorPos;
01808                     }
01809                     if (listPtr->cursorPos >= count) {
01810                         listPtr->cursorPos = count-1;
01811                     }
01812                     if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
01813                         listPtr->startPos = listPtr->cursorPos - viewmax + 1;
01814                     }
01815                     item->cursorPos = listPtr->cursorPos;
01816                     DC->feederSelection(item->special, item->cursorPos);
01817                 }
01818                 else {
01819                     listPtr->startPos++;
01820                     if (listPtr->startPos > max)
01821                         listPtr->startPos = max;
01822                 }
01823                 return qtrue;
01824             }
01825         }
01826         // mouse hit
01827         if (key == K_MOUSE1 || key == K_MOUSE2) {
01828             if (item->window.flags & WINDOW_LB_LEFTARROW) {
01829                 listPtr->startPos--;
01830                 if (listPtr->startPos < 0) {
01831                     listPtr->startPos = 0;
01832                 }
01833             } else if (item->window.flags & WINDOW_LB_RIGHTARROW) {
01834                 // one down
01835                 listPtr->startPos++;
01836                 if (listPtr->startPos > max) {
01837                     listPtr->startPos = max;
01838                 }
01839             } else if (item->window.flags & WINDOW_LB_PGUP) {
01840                 // page up
01841                 listPtr->startPos -= viewmax;
01842                 if (listPtr->startPos < 0) {
01843                     listPtr->startPos = 0;
01844                 }
01845             } else if (item->window.flags & WINDOW_LB_PGDN) {
01846                 // page down
01847                 listPtr->startPos += viewmax;
01848                 if (listPtr->startPos > max) {
01849                     listPtr->startPos = max;
01850                 }
01851             } else if (item->window.flags & WINDOW_LB_THUMB) {
01852                 // Display_SetCaptureItem(item);
01853             } else {
01854                 // select an item
01855                 if (DC->realTime < lastListBoxClickTime && listPtr->doubleClick) {
01856                     Item_RunScript(item, listPtr->doubleClick);
01857                 }
01858                 lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
01859                 if (item->cursorPos != listPtr->cursorPos) {
01860                     item->cursorPos = listPtr->cursorPos;
01861                     DC->feederSelection(item->special, item->cursorPos);
01862                 }
01863             }
01864             return qtrue;
01865         }
01866         if ( key == K_HOME || key == K_KP_HOME) {
01867             // home
01868             listPtr->startPos = 0;
01869             return qtrue;
01870         }
01871         if ( key == K_END || key == K_KP_END) {
01872             // end
01873             listPtr->startPos = max;
01874             return qtrue;
01875         }
01876         if (key == K_PGUP || key == K_KP_PGUP ) {
01877             // page up
01878             if (!listPtr->notselectable) {
01879                 listPtr->cursorPos -= viewmax;
01880                 if (listPtr->cursorPos < 0) {
01881                     listPtr->cursorPos = 0;
01882                 }
01883                 if (listPtr->cursorPos < listPtr->startPos) {
01884                     listPtr->startPos = listPtr->cursorPos;
01885                 }
01886                 if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
01887                     listPtr->startPos = listPtr->cursorPos - viewmax + 1;
01888                 }
01889                 item->cursorPos = listPtr->cursorPos;
01890                 DC->feederSelection(item->special, item->cursorPos);
01891             }
01892             else {
01893                 listPtr->startPos -= viewmax;
01894                 if (listPtr->startPos < 0) {
01895                     listPtr->startPos = 0;
01896                 }
01897             }
01898             return qtrue;
01899         }
01900         if ( key == K_PGDN || key == K_KP_PGDN ) {
01901             // page down
01902             if (!listPtr->notselectable) {
01903                 listPtr->cursorPos += viewmax;
01904                 if (listPtr->cursorPos < listPtr->startPos) {
01905                     listPtr->startPos = listPtr->cursorPos;
01906                 }
01907                 if (listPtr->cursorPos >= count) {
01908                     listPtr->cursorPos = count-1;
01909                 }
01910                 if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
01911                     listPtr->startPos = listPtr->cursorPos - viewmax + 1;
01912                 }
01913                 item->cursorPos = listPtr->cursorPos;
01914                 DC->feederSelection(item->special, item->cursorPos);
01915             }
01916             else {
01917                 listPtr->startPos += viewmax;
01918                 if (listPtr->startPos > max) {
01919                     listPtr->startPos = max;
01920                 }
01921             }
01922             return qtrue;
01923         }
01924     }
01925     return qfalse;
01926 }
01927 
01928 qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) {
01929 
01930   if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
01931         if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
01932         DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar)));
01933           return qtrue;
01934         }
01935   }
01936 
01937   return qfalse;
01938 
01939 }
01940 
01941 int Item_Multi_CountSettings(itemDef_t *item) {
01942     multiDef_t *multiPtr = (multiDef_t*)item->typeData;
01943     if (multiPtr == NULL) {
01944         return 0;
01945     }
01946     return multiPtr->count;
01947 }
01948 
01949 int Item_Multi_FindCvarByValue(itemDef_t *item) {
01950     char buff[1024];
01951     float value = 0;
01952     int i;
01953     multiDef_t *multiPtr = (multiDef_t*)item->typeData;
01954     if (multiPtr) {
01955         if (multiPtr->strDef) {
01956         DC->getCVarString(item->cvar, buff, sizeof(buff));
01957         } else {
01958             value = DC->getCVarValue(item->cvar);
01959         }
01960         for (i = 0; i < multiPtr->count; i++) {
01961             if (multiPtr->strDef) {
01962                 if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
01963                     return i;
01964                 }
01965             } else {
01966                 if (multiPtr->cvarValue[i] == value) {
01967                     return i;
01968                 }
01969             }
01970         }
01971     }
01972     return 0;
01973 }
01974 
01975 const char *Item_Multi_Setting(itemDef_t *item) {
01976     char buff[1024];
01977     float value = 0;
01978     int i;
01979     multiDef_t *multiPtr = (multiDef_t*)item->typeData;
01980     if (multiPtr) {
01981         if (multiPtr->strDef) {
01982         DC->getCVarString(item->cvar, buff, sizeof(buff));
01983         } else {
01984             value = DC->getCVarValue(item->cvar);
01985         }
01986         for (i = 0; i < multiPtr->count; i++) {
01987             if (multiPtr->strDef) {
01988                 if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
01989                     return multiPtr->cvarList[i];
01990                 }
01991             } else {
01992                 if (multiPtr->cvarValue[i] == value) {
01993                     return multiPtr->cvarList[i];
01994                 }
01995             }
01996         }
01997     }
01998     return "";
01999 }
02000 
02001 qboolean Item_Multi_HandleKey(itemDef_t *item, int key) {
02002     multiDef_t *multiPtr = (multiDef_t*)item->typeData;
02003     if (multiPtr) {
02004       if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
02005             if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
02006                 int current = Item_Multi_FindCvarByValue(item) + 1;
02007                 int max = Item_Multi_CountSettings(item);
02008                 if ( current < 0 || current >= max ) {
02009                     current = 0;
02010                 }
02011                 if (multiPtr->strDef) {
02012                     DC->setCVar(item->cvar, multiPtr->cvarStr[current]);
02013                 } else {
02014                     float value = multiPtr->cvarValue[current];
02015                     if (((float)((int) value)) == value) {
02016                         DC->setCVar(item->cvar, va("%i", (int) value ));
02017                     }
02018                     else {
02019                         DC->setCVar(item->cvar, va("%f", value ));
02020                     }
02021                 }
02022                 return qtrue;
02023             }
02024         }
02025     }
02026   return qfalse;
02027 }
02028 
02029 qboolean Item_TextField_HandleKey(itemDef_t *item, int key) {
02030     char buff[1024];
02031     int len;
02032     itemDef_t *newItem = NULL;
02033     editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
02034 
02035     if (item->cvar) {
02036 
02037         memset(buff, 0, sizeof(buff));
02038         DC->getCVarString(item->cvar, buff, sizeof(buff));
02039         len = strlen(buff);
02040         if (editPtr->maxChars && len > editPtr->maxChars) {
02041             len = editPtr->maxChars;
02042         }
02043         if ( key & K_CHAR_FLAG ) {
02044             key &= ~K_CHAR_FLAG;
02045 
02046 
02047             if (key == 'h' - 'a' + 1 )  {   // ctrl-h is backspace
02048                 if ( item->cursorPos > 0 ) {
02049                     memmove( &buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
02050                     item->cursorPos--;
02051                     if (item->cursorPos < editPtr->paintOffset) {
02052                         editPtr->paintOffset--;
02053                     }
02054                 }
02055                 DC->setCVar(item->cvar, buff);
02056                 return qtrue;
02057             }
02058 
02059 
02060             //
02061             // ignore any non printable chars
02062             //
02063             if ( key < 32 || !item->cvar) {
02064                 return qtrue;
02065             }
02066 
02067             if (item->type == ITEM_TYPE_NUMERICFIELD) {
02068                 if (key < '0' || key > '9') {
02069                     return qfalse;
02070                 }
02071             }
02072 
02073             if (!DC->getOverstrikeMode()) {
02074                 if (( len == MAX_EDITFIELD - 1 ) || (editPtr->maxChars && len >= editPtr->maxChars)) {
02075                     return qtrue;
02076                 }
02077                 memmove( &buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos );
02078             } else {
02079                 if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars) {
02080                     return qtrue;
02081                 }
02082             }
02083 
02084             buff[item->cursorPos] = key;
02085 
02086             DC->setCVar(item->cvar, buff);
02087 
02088             if (item->cursorPos < len + 1) {
02089                 item->cursorPos++;
02090                 if (editPtr->maxPaintChars && item->cursorPos > editPtr->maxPaintChars) {
02091                     editPtr->paintOffset++;
02092                 }
02093             }
02094 
02095         } else {
02096 
02097             if ( key == K_DEL || key == K_KP_DEL ) {
02098                 if ( item->cursorPos < len ) {
02099                     memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos);
02100                     DC->setCVar(item->cvar, buff);
02101                 }
02102                 return qtrue;
02103             }
02104 
02105             if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) 
02106             {
02107                 if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) {
02108                     item->cursorPos++;
02109                     editPtr->paintOffset++;
02110                     return qtrue;
02111                 }
02112                 if (item->cursorPos < len) {
02113                     item->cursorPos++;
02114                 } 
02115                 return qtrue;
02116             }
02117 
02118             if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) 
02119             {
02120                 if ( item->cursorPos > 0 ) {
02121                     item->cursorPos--;
02122                 }
02123                 if (item->cursorPos < editPtr->paintOffset) {
02124                     editPtr->paintOffset--;
02125                 }
02126                 return qtrue;
02127             }
02128 
02129             if ( key == K_HOME || key == K_KP_HOME) {// || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
02130                 item->cursorPos = 0;
02131                 editPtr->paintOffset = 0;
02132                 return qtrue;
02133             }
02134 
02135             if ( key == K_END || key == K_KP_END)  {// ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
02136                 item->cursorPos = len;
02137                 if(item->cursorPos > editPtr->maxPaintChars) {
02138                     editPtr->paintOffset = len - editPtr->maxPaintChars;
02139                 }
02140                 return qtrue;
02141             }
02142 
02143             if ( key == K_INS || key == K_KP_INS ) {
02144                 DC->setOverstrikeMode(!DC->getOverstrikeMode());
02145                 return qtrue;
02146             }
02147         }
02148 
02149         if (key == K_TAB || key == K_DOWNARROW || key == K_KP_DOWNARROW) {
02150             newItem = Menu_SetNextCursorItem(item->parent);
02151             if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
02152                 g_editItem = newItem;
02153             }
02154         }
02155 
02156         if (key == K_UPARROW || key == K_KP_UPARROW) {
02157             newItem = Menu_SetPrevCursorItem(item->parent);
02158             if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
02159                 g_editItem = newItem;
02160             }
02161         }
02162 
02163         if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE)  {
02164             return qfalse;
02165         }
02166 
02167         return qtrue;
02168     }
02169     return qfalse;
02170 
02171 }
02172 
02173 static void Scroll_ListBox_AutoFunc(void *p) {
02174     scrollInfo_t *si = (scrollInfo_t*)p;
02175     if (DC->realTime > si->nextScrollTime) { 
02176         // need to scroll which is done by simulating a click to the item
02177         // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
02178         // so it calls it directly
02179         Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
02180         si->nextScrollTime = DC->realTime + si->adjustValue; 
02181     }
02182 
02183     if (DC->realTime > si->nextAdjustTime) {
02184         si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
02185         if (si->adjustValue > SCROLL_TIME_FLOOR) {
02186             si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
02187         }
02188     }
02189 }
02190 
02191 static void Scroll_ListBox_ThumbFunc(void *p) {
02192     scrollInfo_t *si = (scrollInfo_t*)p;
02193     rectDef_t r;
02194     int pos, max;
02195 
02196     listBoxDef_t *listPtr = (listBoxDef_t*)si->item->typeData;
02197     if (si->item->window.flags & WINDOW_HORIZONTAL) {
02198         if (DC->cursorx == si->xStart) {
02199             return;
02200         }
02201         r.x = si->item->window.rect.x + SCROLLBAR_SIZE + 1;
02202         r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_SIZE - 1;
02203         r.h = SCROLLBAR_SIZE;
02204         r.w = si->item->window.rect.w - (SCROLLBAR_SIZE*2) - 2;
02205         max = Item_ListBox_MaxScroll(si->item);
02206         //
02207         pos = (DC->cursorx - r.x - SCROLLBAR_SIZE/2) * max / (r.w - SCROLLBAR_SIZE);
02208         if (pos < 0) {
02209             pos = 0;
02210         }
02211         else if (pos > max) {
02212             pos = max;
02213         }
02214         listPtr->startPos = pos;
02215         si->xStart = DC->cursorx;
02216     }
02217     else if (DC->cursory != si->yStart) {
02218 
02219         r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1;
02220         r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1;
02221         r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2;
02222         r.w = SCROLLBAR_SIZE;
02223         max = Item_ListBox_MaxScroll(si->item);
02224         //
02225         pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE);
02226         if (pos < 0) {
02227             pos = 0;
02228         }
02229         else if (pos > max) {
02230             pos = max;
02231         }
02232         listPtr->startPos = pos;
02233         si->yStart = DC->cursory;
02234     }
02235 
02236     if (DC->realTime > si->nextScrollTime) { 
02237         // need to scroll which is done by simulating a click to the item
02238         // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
02239         // so it calls it directly
02240         Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
02241         si->nextScrollTime = DC->realTime + si->adjustValue; 
02242     }
02243 
02244     if (DC->realTime > si->nextAdjustTime) {
02245         si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
02246         if (si->adjustValue > SCROLL_TIME_FLOOR) {
02247             si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
02248         }
02249     }
02250 }
02251 
02252 static void Scroll_Slider_ThumbFunc(void *p) {
02253     float x, value, cursorx;
02254     scrollInfo_t *si = (scrollInfo_t*)p;
02255     editFieldDef_t *editDef = si->item->typeData;
02256 
02257     if (si->item->text) {
02258         x = si->item->textRect.x + si->item->textRect.w + 8;
02259     } else {
02260         x = si->item->window.rect.x;
02261     }
02262 
02263     cursorx = DC->cursorx;
02264 
02265     if (cursorx < x) {
02266         cursorx = x;
02267     } else if (cursorx > x + SLIDER_WIDTH) {
02268         cursorx = x + SLIDER_WIDTH;
02269     }
02270     value = cursorx - x;
02271     value /= SLIDER_WIDTH;
02272     value *= (editDef->maxVal - editDef->minVal);
02273     value += editDef->minVal;
02274     DC->setCVar(si->item->cvar, va("%f", value));
02275 }
02276 
02277 void Item_StartCapture(itemDef_t *item, int key) {
02278     int flags;
02279     switch (item->type) {
02280     case ITEM_TYPE_EDITFIELD:
02281     case ITEM_TYPE_NUMERICFIELD:
02282 
02283         case ITEM_TYPE_LISTBOX:
02284         {
02285             flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory);
02286             if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) {
02287                 scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
02288                 scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
02289                 scrollInfo.adjustValue = SCROLL_TIME_START;
02290                 scrollInfo.scrollKey = key;
02291                 scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse;
02292                 scrollInfo.item = item;
02293                 captureData = &scrollInfo;
02294                 captureFunc = &Scroll_ListBox_AutoFunc;
02295                 itemCapture = item;
02296             } else if (flags & WINDOW_LB_THUMB) {
02297                 scrollInfo.scrollKey = key;
02298                 scrollInfo.item = item;
02299                 scrollInfo.xStart = DC->cursorx;
02300                 scrollInfo.yStart = DC->cursory;
02301                 captureData = &scrollInfo;
02302                 captureFunc = &Scroll_ListBox_ThumbFunc;
02303                 itemCapture = item;
02304             }
02305             break;
02306         }
02307         case ITEM_TYPE_SLIDER:
02308         {
02309             flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory);
02310             if (flags & WINDOW_LB_THUMB) {
02311                 scrollInfo.scrollKey = key;
02312                 scrollInfo.item = item;
02313                 scrollInfo.xStart = DC->cursorx;
02314                 scrollInfo.yStart = DC->cursory;
02315                 captureData = &scrollInfo;
02316                 captureFunc = &Scroll_Slider_ThumbFunc;
02317                 itemCapture = item;
02318             }
02319             break;
02320         }
02321     }
02322 }
02323 
02324 void Item_StopCapture(itemDef_t *item) {
02325 
02326 }
02327 
02328 qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) {
02329     float x, value, width, work;
02330 
02331     //DC->Print("slider handle key\n");
02332     if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
02333         if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
02334             editFieldDef_t *editDef = item->typeData;
02335             if (editDef) {
02336                 rectDef_t testRect;
02337                 width = SLIDER_WIDTH;
02338                 if (item->text) {
02339                     x = item->textRect.x + item->textRect.w + 8;
02340                 } else {
02341                     x = item->window.rect.x;
02342                 }
02343 
02344                 testRect = item->window.rect;
02345                 testRect.x = x;
02346                 value = (float)SLIDER_THUMB_WIDTH / 2;
02347                 testRect.x -= value;
02348                 //DC->Print("slider x: %f\n", testRect.x);
02349                 testRect.w = (SLIDER_WIDTH + (float)SLIDER_THUMB_WIDTH / 2);
02350                 //DC->Print("slider w: %f\n", testRect.w);
02351                 if (Rect_ContainsPoint(&testRect, DC->cursorx, DC->cursory)) {
02352                     work = DC->cursorx - x;
02353                     value = work / width;
02354                     value *= (editDef->maxVal - editDef->minVal);
02355                     // vm fuckage
02356                     // value = (((float)(DC->cursorx - x)/ SLIDER_WIDTH) * (editDef->maxVal - editDef->minVal));
02357                     value += editDef->minVal;
02358                     DC->setCVar(item->cvar, va("%f", value));
02359                     return qtrue;
02360                 }
02361             }
02362         }
02363     }
02364     DC->Print("slider handle key exit\n");
02365     return qfalse;
02366 }
02367 
02368 
02369 qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) {
02370 
02371     if (itemCapture) {
02372         Item_StopCapture(itemCapture);
02373         itemCapture = NULL;
02374         captureFunc = NULL;
02375         captureData = NULL;
02376     } else {
02377       // bk001206 - parentheses
02378         if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
02379             Item_StartCapture(item, key);
02380         }
02381     }
02382 
02383     if (!down) {
02384         return qfalse;
02385     }
02386 
02387   switch (item->type) {
02388     case ITEM_TYPE_BUTTON:
02389       return qfalse;
02390       break;
02391     case ITEM_TYPE_RADIOBUTTON:
02392       return qfalse;
02393       break;
02394     case ITEM_TYPE_CHECKBOX:
02395       return qfalse;
02396       break;
02397     case ITEM_TYPE_EDITFIELD:
02398     case ITEM_TYPE_NUMERICFIELD:
02399       //return Item_TextField_HandleKey(item, key);
02400       return qfalse;
02401       break;
02402     case ITEM_TYPE_COMBO:
02403       return qfalse;
02404       break;
02405     case ITEM_TYPE_LISTBOX:
02406       return Item_ListBox_HandleKey(item, key, down, qfalse);
02407       break;
02408     case ITEM_TYPE_YESNO:
02409       return Item_YesNo_HandleKey(item, key);
02410       break;
02411     case ITEM_TYPE_MULTI:
02412       return Item_Multi_HandleKey(item, key);
02413       break;
02414     case ITEM_TYPE_OWNERDRAW:
02415       return Item_OwnerDraw_HandleKey(item, key);
02416       break;
02417     case ITEM_TYPE_BIND:
02418             return Item_Bind_HandleKey(item, key, down);
02419       break;
02420     case ITEM_TYPE_SLIDER:
02421       return Item_Slider_HandleKey(item, key, down);
02422       break;
02423     //case ITEM_TYPE_IMAGE:
02424     //  Item_Image_Paint(item);
02425     //  break;
02426     default:
02427       return qfalse;
02428       break;
02429   }
02430 
02431   //return qfalse;
02432 }
02433 
02434 void Item_Action(itemDef_t *item) {
02435   if (item) {
02436     Item_RunScript(item, item->action);
02437   }
02438 }
02439 
02440 itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu) {
02441   qboolean wrapped = qfalse;
02442     int oldCursor = menu->cursorItem;
02443   
02444   if (menu->cursorItem < 0) {
02445     menu->cursorItem = menu->itemCount-1;
02446     wrapped = qtrue;
02447   } 
02448 
02449   while (menu->cursorItem > -1) {
02450     
02451     menu->cursorItem--;
02452     if (menu->cursorItem < 0 && !wrapped) {
02453       wrapped = qtrue;
02454       menu->cursorItem = menu->itemCount -1;
02455     }
02456 
02457         if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
02458             Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
02459       return menu->items[menu->cursorItem];
02460     }
02461   }
02462     menu->cursorItem = oldCursor;
02463     return NULL;
02464 
02465 }
02466 
02467 itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu) {
02468 
02469   qboolean wrapped = qfalse;
02470     int oldCursor = menu->cursorItem;
02471 
02472 
02473   if (menu->cursorItem == -1) {
02474     menu->cursorItem = 0;
02475     wrapped = qtrue;
02476   }
02477 
02478   while (menu->cursorItem < menu->itemCount) {
02479 
02480     menu->cursorItem++;
02481     if (menu->cursorItem >= menu->itemCount && !wrapped) {
02482       wrapped = qtrue;
02483       menu->cursorItem = 0;
02484     }
02485         if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
02486             Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
02487       return menu->items[menu->cursorItem];
02488     }
02489     
02490   }
02491 
02492     menu->cursorItem = oldCursor;
02493     return NULL;
02494 }
02495 
02496 static void Window_CloseCinematic(windowDef_t *window) {
02497     if (window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0) {
02498         DC->stopCinematic(window->cinematic);
02499         window->cinematic = -1;
02500     }
02501 }
02502 
02503 static void Menu_CloseCinematics(menuDef_t *menu) {
02504     if (menu) {
02505         int i;
02506         Window_CloseCinematic(&menu->window);
02507       for (i = 0; i < menu->itemCount; i++) {
02508           Window_CloseCinematic(&menu->items[i]->window);
02509             if (menu->items[i]->type == ITEM_TYPE_OWNERDRAW) {
02510                 DC->stopCinematic(0-menu->items[i]->window.ownerDraw);
02511             }
02512       }
02513     }
02514 }
02515 
02516 static void Display_CloseCinematics() {
02517     int i;
02518     for (i = 0; i < menuCount; i++) {
02519         Menu_CloseCinematics(&Menus[i]);
02520     }
02521 }
02522 
02523 void  Menus_Activate(menuDef_t *menu) {
02524     menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
02525     if (menu->onOpen) {
02526         itemDef_t item;
02527         item.parent = menu;
02528         Item_RunScript(&item, menu->onOpen);
02529     }
02530 
02531     if (menu->soundName && *menu->soundName) {
02532 //      DC->stopBackgroundTrack();                  // you don't want to do this since it will reset s_rawend
02533         DC->startBackgroundTrack(menu->soundName, menu->soundName);
02534     }
02535 
02536     Display_CloseCinematics();
02537 
02538 }
02539 
02540 int Display_VisibleMenuCount() {
02541     int i, count;
02542     count = 0;
02543     for (i = 0; i < menuCount; i++) {
02544         if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE)) {
02545             count++;
02546         }
02547     }
02548     return count;
02549 }
02550 
02551 void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down) {
02552     if (menu) {
02553         int i;
02554         // basically the behaviour we are looking for is if there are windows in the stack.. see if 
02555         // the cursor is within any of them.. if not close them otherwise activate them and pass the 
02556         // key on.. force a mouse move to activate focus and script stuff 
02557         if (down && menu->window.flags & WINDOW_OOB_CLICK) {
02558             Menu_RunCloseScript(menu);
02559             menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
02560         }
02561 
02562         for (i = 0; i < menuCount; i++) {
02563             if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory)) {
02564                 Menu_RunCloseScript(menu);
02565                 menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
02566                 Menus_Activate(&Menus[i]);
02567                 Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory);
02568                 Menu_HandleKey(&Menus[i], key, down);
02569             }
02570         }
02571 
02572         if (Display_VisibleMenuCount() == 0) {
02573             if (DC->Pause) {
02574                 DC->Pause(qfalse);
02575             }
02576         }
02577         Display_CloseCinematics();
02578     }
02579 }
02580 
02581 static rectDef_t *Item_CorrectedTextRect(itemDef_t *item) {
02582     static rectDef_t rect;
02583     memset(&rect, 0, sizeof(rectDef_t));
02584     if (item) {
02585         rect = item->textRect;
02586         if (rect.w) {
02587             rect.y -= rect.h;
02588         }
02589     }
02590     return &rect;
02591 }
02592 
02593 void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) {
02594     int i;
02595     itemDef_t *item = NULL;
02596     qboolean inHandler = qfalse;
02597 
02598     if (inHandler) {
02599         return;
02600     }
02601 
02602     inHandler = qtrue;
02603     if (g_waitingForKey && down) {
02604         Item_Bind_HandleKey(g_bindItem, key, down);
02605         inHandler = qfalse;
02606         return;
02607     }
02608 
02609     if (g_editingField && down) {
02610         if (!Item_TextField_HandleKey(g_editItem, key)) {
02611             g_editingField = qfalse;
02612             g_editItem = NULL;
02613             inHandler = qfalse;
02614             return;
02615         } else if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) {
02616             g_editingField = qfalse;
02617             g_editItem = NULL;
02618             Display_MouseMove(NULL, DC->cursorx, DC->cursory);
02619         } else if (key == K_TAB || key == K_UPARROW || key == K_DOWNARROW) {
02620             return;
02621         }
02622     }
02623 
02624     if (menu == NULL) {
02625         inHandler = qfalse;
02626         return;
02627     }
02628 
02629         // see if the mouse is within the window bounds and if so is this a mouse click
02630     if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) {
02631         static qboolean inHandleKey = qfalse;
02632         // bk001206 - parentheses
02633         if (!inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
02634             inHandleKey = qtrue;
02635             Menus_HandleOOBClick(menu, key, down);
02636             inHandleKey = qfalse;
02637             inHandler = qfalse;
02638             return;
02639         }
02640     }
02641 
02642     // get the item with focus
02643     for (i = 0; i < menu->itemCount; i++) {
02644         if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
02645             item = menu->items[i];
02646         }
02647     }
02648 
02649     if (item != NULL) {
02650         if (Item_HandleKey(item, key, down)) {
02651             Item_Action(item);
02652             inHandler = qfalse;
02653             return;
02654         }
02655     }
02656 
02657     if (!down) {
02658         inHandler = qfalse;
02659         return;
02660     }
02661 
02662     // default handling
02663     switch ( key ) {
02664 
02665         case K_F11:
02666             if (DC->getCVarValue("developer")) {
02667                 debugMode ^= 1;
02668             }
02669             break;
02670 
02671         case K_F12:
02672             if (DC->getCVarValue("developer")) {
02673                 DC->executeText(EXEC_APPEND, "screenshot\n");
02674             }
02675             break;
02676         case K_KP_UPARROW:
02677         case K_UPARROW:
02678             Menu_SetPrevCursorItem(menu);
02679             break;
02680 
02681         case K_ESCAPE:
02682             if (!g_waitingForKey && menu->onESC) {
02683                 itemDef_t it;
02684             it.parent = menu;
02685             Item_RunScript(&it, menu->onESC);
02686             }
02687             break;
02688         case K_TAB:
02689         case K_KP_DOWNARROW:
02690         case K_DOWNARROW:
02691             Menu_SetNextCursorItem(menu);
02692             break;
02693 
02694         case K_MOUSE1:
02695         case K_MOUSE2:
02696             if (item) {
02697                 if (item->type == ITEM_TYPE_TEXT) {
02698                     if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory)) {
02699                         Item_Action(item);
02700                     }
02701                 } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
02702                     if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
02703                         item->cursorPos = 0;
02704                         g_editingField = qtrue;
02705                         g_editItem = item;
02706                         DC->setOverstrikeMode(qtrue);
02707                     }
02708                 } else {
02709                     if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
02710                         Item_Action(item);
02711                     }
02712                 }
02713             }
02714             break;
02715 
02716         case K_JOY1:
02717         case K_JOY2:
02718         case K_JOY3:
02719         case K_JOY4:
02720         case K_AUX1:
02721         case K_AUX2:
02722         case K_AUX3:
02723         case K_AUX4:
02724         case K_AUX5:
02725         case K_AUX6:
02726         case K_AUX7:
02727         case K_AUX8:
02728         case K_AUX9:
02729         case K_AUX10:
02730         case K_AUX11:
02731         case K_AUX12:
02732         case K_AUX13:
02733         case K_AUX14:
02734         case K_AUX15:
02735         case K_AUX16:
02736             break;
02737         case K_KP_ENTER:
02738         case K_ENTER:
02739             if (item) {
02740                 if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
02741                     item->cursorPos = 0;
02742                     g_editingField = qtrue;
02743                     g_editItem = item;
02744                     DC->setOverstrikeMode(qtrue);
02745                 } else {
02746                         Item_Action(item);
02747                 }
02748             }
02749             break;
02750     }
02751     inHandler = qfalse;
02752 }
02753 
02754 void ToWindowCoords(float *x, float *y, windowDef_t *window) {
02755     if (window->border != 0) {
02756         *x += window->borderSize;
02757         *y += window->borderSize;
02758     } 
02759     *x += window->rect.x;
02760     *y += window->rect.y;
02761 }
02762 
02763 void Rect_ToWindowCoords(rectDef_t *rect, windowDef_t *window) {
02764     ToWindowCoords(&rect->x, &rect->y, window);
02765 }
02766 
02767 void Item_SetTextExtents(itemDef_t *item, int *width, int *height, const char *text) {
02768     const char *textPtr = (text) ? text : item->text;
02769 
02770     if (textPtr == NULL ) {
02771         return;
02772     }
02773 
02774     *width = item->textRect.w;
02775     *height = item->textRect.h;
02776 
02777     // keeps us from computing the widths and heights more than once
02778     if (*width == 0 || (item->type == ITEM_TYPE_OWNERDRAW && item->textalignment == ITEM_ALIGN_CENTER)) {
02779         int originalWidth = DC->textWidth(item->text, item->textscale, 0);
02780 
02781         if (item->type == ITEM_TYPE_OWNERDRAW && (item->textalignment == ITEM_ALIGN_CENTER || item->textalignment == ITEM_ALIGN_RIGHT)) {
02782             originalWidth += DC->ownerDrawWidth(item->window.ownerDraw, item->textscale);
02783         } else if (item->type == ITEM_TYPE_EDITFIELD && item->textalignment == ITEM_ALIGN_CENTER && item->cvar) {
02784             char buff[256];
02785             DC->getCVarString(item->cvar, buff, 256);
02786             originalWidth += DC->textWidth(buff, item->textscale, 0);
02787         }
02788 
02789         *width = DC->textWidth(textPtr, item->textscale, 0);
02790         *height = DC->textHeight(textPtr, item->textscale, 0);
02791         item->textRect.w = *width;
02792         item->textRect.h = *height;
02793         item->textRect.x = item->textalignx;
02794         item->textRect.y = item->textaligny;
02795         if (item->textalignment == ITEM_ALIGN_RIGHT) {
02796             item->textRect.x = item->textalignx - originalWidth;
02797         } else if (item->textalignment == ITEM_ALIGN_CENTER) {
02798             item->textRect.x = item->textalignx - originalWidth / 2;
02799         }
02800 
02801         ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
02802     }
02803 }
02804 
02805 void Item_TextColor(itemDef_t *item, vec4_t *newColor) {
02806     vec4_t lowLight;
02807     menuDef_t *parent = (menuDef_t*)item->parent;
02808 
02809     Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
02810 
02811     if (item->window.flags & WINDOW_HASFOCUS) {
02812         lowLight[0] = 0.8 * parent->focusColor[0]; 
02813         lowLight[1] = 0.8 * parent->focusColor[1]; 
02814         lowLight[2] = 0.8 * parent->focusColor[2]; 
02815         lowLight[3] = 0.8 * parent->focusColor[3]; 
02816         LerpColor(parent->focusColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
02817     } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
02818         lowLight[0] = 0.8 * item->window.foreColor[0]; 
02819         lowLight[1] = 0.8 * item->window.foreColor[1]; 
02820         lowLight[2] = 0.8 * item->window.foreColor[2]; 
02821         lowLight[3] = 0.8 * item->window.foreColor[3]; 
02822         LerpColor(item->window.foreColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
02823     } else {
02824         memcpy(newColor, &item->window.foreColor, sizeof(vec4_t));
02825         // items can be enabled and disabled based on cvars
02826     }
02827 
02828     if (item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
02829         if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
02830             memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
02831         }
02832     }
02833 }
02834 
02835 void Item_Text_AutoWrapped_Paint(itemDef_t *item) {
02836     char text[1024];
02837     const char *p, *textPtr, *newLinePtr;
02838     char buff[1024];
02839     int width, height, len, textWidth, newLine, newLineWidth;
02840     float y;
02841     vec4_t color;
02842 
02843     textWidth = 0;
02844     newLinePtr = NULL;
02845 
02846     if (item->text == NULL) {
02847         if (item->cvar == NULL) {
02848             return;
02849         }
02850         else {
02851             DC->getCVarString(item->cvar, text, sizeof(text));
02852             textPtr = text;
02853         }
02854     }
02855     else {
02856         textPtr = item->text;
02857     }
02858     if (*textPtr == '\0') {
02859         return;
02860     }
02861     Item_TextColor(item, &color);
02862     Item_SetTextExtents(item, &width, &height, textPtr);
02863 
02864     y = item->textaligny;
02865     len = 0;
02866     buff[0] = '\0';
02867     newLine = 0;
02868     newLineWidth = 0;
02869     p = textPtr;
02870     while (p) {
02871         if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\0') {
02872             newLine = len;
02873             newLinePtr = p+1;
02874             newLineWidth = textWidth;
02875         }
02876         textWidth = DC->textWidth(buff, item->textscale, 0);
02877         if ( (newLine && textWidth > item->window.rect.w) || *p == '\n' || *p == '\0') {
02878             if (len) {
02879                 if (item->textalignment == ITEM_ALIGN_LEFT) {
02880                     item->textRect.x = item->textalignx;
02881                 } else if (item->textalignment == ITEM_ALIGN_RIGHT) {
02882                     item->textRect.x = item->textalignx - newLineWidth;
02883                 } else if (item->textalignment == ITEM_ALIGN_CENTER) {
02884                     item->textRect.x = item->textalignx - newLineWidth / 2;
02885                 }
02886                 item->textRect.y = y;
02887                 ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
02888                 //
02889                 buff[newLine] = '\0';
02890                 DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, buff, 0, 0, item->textStyle);
02891             }
02892             if (*p == '\0') {
02893                 break;
02894             }
02895             //
02896             y += height + 5;
02897             p = newLinePtr;
02898             len = 0;
02899             newLine = 0;
02900             newLineWidth = 0;
02901             continue;
02902         }
02903         buff[len++] = *p++;
02904         buff[len] = '\0';
02905     }
02906 }
02907 
02908 void Item_Text_Wrapped_Paint(itemDef_t *item) {
02909     char text[1024];
02910     const char *p, *start, *textPtr;
02911     char buff[1024];
02912     int width, height;
02913     float x, y;
02914     vec4_t color;
02915 
02916     // now paint the text and/or any optional images
02917     // default to left
02918 
02919     if (item->text == NULL) {
02920         if (item->cvar == NULL) {
02921             return;
02922         }
02923         else {
02924             DC->getCVarString(item->cvar, text, sizeof(text));
02925             textPtr = text;
02926         }
02927     }
02928     else {
02929         textPtr = item->text;
02930     }
02931     if (*textPtr == '\0') {
02932         return;
02933     }
02934 
02935     Item_TextColor(item, &color);
02936     Item_SetTextExtents(item, &width, &height, textPtr);
02937 
02938     x = item->textRect.x;
02939     y = item->textRect.y;
02940     start = textPtr;
02941     p = strchr(textPtr, '\r');
02942     while (p && *p) {
02943         strncpy(buff, start, p-start+1);
02944         buff[p-start] = '\0';
02945         DC->drawText(x, y, item->textscale, color, buff, 0, 0, item->textStyle);
02946         y += height + 5;
02947         start += p - start + 1;
02948         p = strchr(p+1, '\r');
02949     }
02950     DC->drawText(x, y, item->textscale, color, start, 0, 0, item->textStyle);
02951 }
02952 
02953 void Item_Text_Paint(itemDef_t *item) {
02954     char text[1024];
02955     const char *textPtr;
02956     int height, width;
02957     vec4_t color;
02958 
02959     if (item->window.flags & WINDOW_WRAPPED) {
02960         Item_Text_Wrapped_Paint(item);
02961         return;
02962     }
02963     if (item->window.flags & WINDOW_AUTOWRAPPED) {
02964         Item_Text_AutoWrapped_Paint(item);
02965         return;
02966     }
02967 
02968     if (item->text == NULL) {
02969         if (item->cvar == NULL) {
02970             return;
02971         }
02972         else {
02973             DC->getCVarString(item->cvar, text, sizeof(text));
02974             textPtr = text;
02975         }
02976     }
02977     else {
02978         textPtr = item->text;
02979     }
02980 
02981     // this needs to go here as it sets extents for cvar types as well
02982     Item_SetTextExtents(item, &width, &height, textPtr);
02983 
02984     if (*textPtr == '\0') {
02985         return;
02986     }
02987 
02988 
02989     Item_TextColor(item, &color);
02990 
02991     //FIXME: this is a fucking mess
02992 /*
02993     adjust = 0;
02994     if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
02995         adjust = 0.5;
02996     }
02997 
02998     if (item->textStyle == ITEM_TEXTSTYLE_SHADOWED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
02999         Fade(&item->window.flags, &DC->Assets.shadowColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
03000         DC->drawText(item->textRect.x + DC->Assets.shadowX, item->textRect.y + DC->Assets.shadowY, item->textscale, DC->Assets.shadowColor, textPtr, adjust);
03001     }
03002 */
03003 
03004 
03005 //  if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
03006 //      Fade(&item->window.flags, &item->window.outlineColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
03007 //      /*
03008 //      Text_Paint(item->textRect.x-1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
03009 //      Text_Paint(item->textRect.x, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
03010 //      Text_Paint(item->textRect.x+1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
03011 //      Text_Paint(item->textRect.x-1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
03012 //      Text_Paint(item->textRect.x+1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
03013 //      Text_Paint(item->textRect.x-1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
03014 //      Text_Paint(item->textRect.x, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
03015 //      Text_Paint(item->textRect.x+1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
03016 //      */
03017 //      DC->drawText(item->textRect.x - 1, item->textRect.y + 1, item->textscale * 1.02, item->window.outlineColor, textPtr, adjust);
03018 //  }
03019 
03020     DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, 0, item->textStyle);
03021 }
03022 
03023 
03024 
03025 //float         trap_Cvar_VariableValue( const char *var_name );
03026 //void          trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
03027 
03028 void Item_TextField_Paint(itemDef_t *item) {
03029     char buff[1024];
03030     vec4_t newColor, lowLight;
03031     int offset;
03032     menuDef_t *parent = (menuDef_t*)item->parent;
03033     editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
03034 
03035     Item_Text_Paint(item);
03036 
03037     buff[0] = '\0';
03038 
03039     if (item->cvar) {
03040         DC->getCVarString(item->cvar, buff, sizeof(buff));
03041     } 
03042 
03043     parent = (menuDef_t*)item->parent;
03044 
03045     if (item->window.flags & WINDOW_HASFOCUS) {
03046         lowLight[0] = 0.8 * parent->focusColor[0]; 
03047         lowLight[1] = 0.8 * parent->focusColor[1]; 
03048         lowLight[2] = 0.8 * parent->focusColor[2]; 
03049         lowLight[3] = 0.8 * parent->focusColor[3]; 
03050         LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
03051     } else {
03052         memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
03053     }
03054 
03055     offset = (item->text && *item->text) ? 8 : 0;
03056     if (item->window.flags & WINDOW_HASFOCUS && g_editingField) {
03057         char cursor = DC->getOverstrikeMode() ? '_' : '|';
03058         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);
03059     } else {
03060         DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle);
03061     }
03062 
03063 }
03064 
03065 void Item_YesNo_Paint(itemDef_t *item) {
03066     vec4_t newColor, lowLight;
03067     float value;
03068     menuDef_t *parent = (menuDef_t*)item->parent;
03069 
03070     value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
03071 
03072     if (item->window.flags & WINDOW_HASFOCUS) {
03073         lowLight[0] = 0.8 * parent->focusColor[0]; 
03074         lowLight[1] = 0.8 * parent->focusColor[1]; 
03075         lowLight[2] = 0.8 * parent->focusColor[2]; 
03076         lowLight[3] = 0.8 * parent->focusColor[3]; 
03077         LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
03078     } else {
03079         memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
03080     }
03081 
03082     if (item->text) {
03083         Item_Text_Paint(item);
03084         DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
03085     } else {
03086         DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
03087     }
03088 }
03089 
03090 void Item_Multi_Paint(itemDef_t *item) {
03091     vec4_t newColor, lowLight;
03092     const char *text = "";
03093     menuDef_t *parent = (menuDef_t*)item->parent;
03094 
03095     if (item->window.flags & WINDOW_HASFOCUS) {
03096         lowLight[0] = 0.8 * parent->focusColor[0]; 
03097         lowLight[1] = 0.8 * parent->focusColor[1]; 
03098         lowLight[2] = 0.8 * parent->focusColor[2]; 
03099         lowLight[3] = 0.8 * parent->focusColor[3]; 
03100         LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
03101     } else {
03102         memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
03103     }
03104 
03105     text = Item_Multi_Setting(item);
03106 
03107     if (item->text) {
03108         Item_Text_Paint(item);
03109         DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
03110     } else {
03111         DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
03112     }
03113 }
03114 
03115 
03116 typedef struct {
03117     char    *command;
03118     int     id;
03119     int     defaultbind1;
03120     int     defaultbind2;
03121     int     bind1;
03122     int     bind2;
03123 } bind_t;
03124 
03125 typedef struct
03126 {
03127     char*   name;
03128     float   defaultvalue;
03129     float   value;  
03130 } configcvar_t;
03131 
03132 
03133 static bind_t g_bindings[] = 
03134 {
03135     {"+scores",          K_TAB,             -1,     -1, -1},
03136     {"+button2",         K_ENTER,           -1,     -1, -1},
03137     {"+speed",           K_SHIFT,           -1,     -1, -1},
03138     {"+forward",         K_UPARROW,     -1,     -1, -1},
03139     {"+back",            K_DOWNARROW,   -1,     -1, -1},
03140     {"+moveleft",    ',',                   -1,     -1, -1},
03141     {"+moveright",   '.',                   -1,     -1, -1},
03142     {"+moveup",          K_SPACE,           -1,     -1, -1},
03143     {"+movedown",        'c',                   -1,     -1, -1},
03144     {"+left",            K_LEFTARROW,   -1,     -1, -1},
03145     {"+right",           K_RIGHTARROW,  -1,     -1, -1},
03146     {"+strafe",          K_ALT,             -1,     -1, -1},
03147     {"+lookup",          K_PGDN,                -1,     -1, -1},
03148     {"+lookdown",    K_DEL,             -1,     -1, -1},
03149     {"+mlook",           '/',                   -1,     -1, -1},
03150     {"centerview",   K_END,             -1,     -1, -1},
03151     {"+zoom",            -1,                        -1,     -1, -1},
03152     {"weapon 1",         '1',                   -1,     -1, -1},
03153     {"weapon 2",         '2',                   -1,     -1, -1},
03154     {"weapon 3",         '3',                   -1,     -1, -1},
03155     {"weapon 4",         '4',                   -1,     -1, -1},
03156     {"weapon 5",         '5',                   -1,     -1, -1},
03157     {"weapon 6",         '6',                   -1,     -1, -1},
03158     {"weapon 7",         '7',                   -1,     -1, -1},
03159     {"weapon 8",         '8',                   -1,     -1, -1},
03160     {"weapon 9",         '9',                   -1,     -1, -1},
03161     {"weapon 10",        '0',                   -1,     -1, -1},
03162     {"weapon 11",        -1,                    -1,     -1, -1},
03163     {"weapon 12",        -1,                    -1,     -1, -1},
03164     {"weapon 13",        -1,                    -1,     -1, -1},
03165     {"+attack",          K_CTRL,                -1,     -1, -1},
03166     {"weapprev",         '[',                   -1,     -1, -1},
03167     {"weapnext",         ']',                   -1,     -1, -1},
03168     {"+button3",         K_MOUSE3,          -1,     -1, -1},
03169     {"+button4",         K_MOUSE4,          -1,     -1, -1},
03170     {"prevTeamMember", 'w',                 -1,     -1, -1},
03171     {"nextTeamMember", 'r',                 -1,     -1, -1},
03172     {"nextOrder", 't',                  -1,     -1, -1},
03173     {"confirmOrder", 'y',                   -1,     -1, -1},
03174     {"denyOrder", 'n',                  -1,     -1, -1},
03175     {"taskOffense", 'o',                    -1,     -1, -1},
03176     {"taskDefense", 'd',                    -1,     -1, -1},
03177     {"taskPatrol", 'p',                 -1,     -1, -1},
03178     {"taskCamp", 'c',                   -1,     -1, -1},
03179     {"taskFollow", 'f',                 -1,     -1, -1},
03180     {"taskRetrieve", 'v',                   -1,     -1, -1},
03181     {"taskEscort", 'e',                 -1,     -1, -1},
03182     {"taskOwnFlag", 'i',                    -1,     -1, -1},
03183     {"taskSuicide", 'k',                    -1,     -1, -1},
03184     {"tauntKillInsult", K_F1,           -1,     -1, -1},
03185     {"tauntPraise", K_F2,           -1,     -1, -1},
03186     {"tauntTaunt", K_F3,            -1,     -1, -1},
03187     {"tauntDeathInsult", K_F4,          -1,     -1, -1},
03188     {"tauntGauntlet", K_F5,         -1,     -1, -1},
03189     {"scoresUp", K_KP_PGUP,         -1,     -1, -1},
03190     {"scoresDown", K_KP_PGDN,           -1,     -1, -1},
03191     // bk001205 - this one below was:  '-1' 
03192     {"messagemode",  -1,                    -1,     -1, -1},
03193     {"messagemode2", -1,                        -1,     -1, -1},
03194     {"messagemode3", -1,                        -1,     -1, -1},
03195     {"messagemode4", -1,                        -1,     -1, -1}
03196 };
03197 
03198 
03199 static const int g_bindCount = sizeof(g_bindings) / sizeof(bind_t);
03200 
03201 #ifndef MISSIONPACK // bk001206
03202 static configcvar_t g_configcvars[] =
03203 {
03204     {"cl_run",          0,                  0},
03205     {"m_pitch",         0,                  0},
03206     {"cg_autoswitch",   0,                  0},
03207     {"sensitivity",     0,                  0},
03208     {"in_joystick",     0,                  0},
03209     {"joy_threshold",   0,                  0},
03210     {"m_filter",        0,                  0},
03211     {"cl_freelook",     0,                  0},
03212     {NULL,              0,                  0}
03213 };
03214 #endif
03215 
03216 /*
03217 =================
03218 Controls_GetKeyAssignment
03219 =================
03220 */
03221 static void Controls_GetKeyAssignment (char *command, int *twokeys)
03222 {
03223     int     count;
03224     int     j;
03225     char    b[256];
03226 
03227     twokeys[0] = twokeys[1] = -1;
03228     count = 0;
03229 
03230     for ( j = 0; j < 256; j++ )
03231     {
03232         DC->getBindingBuf( j, b, 256 );
03233         if ( *b == 0 ) {
03234             continue;
03235         }
03236         if ( !Q_stricmp( b, command ) ) {
03237             twokeys[count] = j;
03238             count++;
03239             if (count == 2) {
03240                 break;
03241             }
03242         }
03243     }
03244 }
03245 
03246 /*
03247 =================
03248 Controls_GetConfig
03249 =================
03250 */
03251 void Controls_GetConfig( void )
03252 {
03253     int     i;
03254     int     twokeys[2];
03255 
03256     // iterate each command, get its numeric binding
03257     for (i=0; i < g_bindCount; i++)
03258     {
03259 
03260         Controls_GetKeyAssignment(g_bindings[i].command, twokeys);
03261 
03262         g_bindings[i].bind1 = twokeys[0];
03263         g_bindings[i].bind2 = twokeys[1];
03264     }
03265 
03266     //s_controls.invertmouse.curvalue  = DC->getCVarValue( "m_pitch" ) < 0;
03267     //s_controls.smoothmouse.curvalue  = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
03268     //s_controls.alwaysrun.curvalue    = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
03269     //s_controls.autoswitch.curvalue   = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) );
03270     //s_controls.sensitivity.curvalue  = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
03271     //s_controls.joyenable.curvalue    = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
03272     //s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05, 0.75, Controls_GetCvarValue( "joy_threshold" ) );
03273     //s_controls.freelook.curvalue     = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
03274 }
03275 
03276 /*
03277 =================
03278 Controls_SetConfig
03279 =================
03280 */
03281 void Controls_SetConfig(qboolean restart)
03282 {
03283     int     i;
03284 
03285     // iterate each command, get its numeric binding
03286     for (i=0; i < g_bindCount; i++)
03287     {
03288 
03289         if (g_bindings[i].bind1 != -1)
03290         {   
03291             DC->setBinding( g_bindings[i].bind1, g_bindings[i].command );
03292 
03293             if (g_bindings[i].bind2 != -1)
03294                 DC->setBinding( g_bindings[i].bind2, g_bindings[i].command );
03295         }
03296     }
03297 
03298     //if ( s_controls.invertmouse.curvalue )
03299     //  DC->setCVar("m_pitch", va("%f),-fabs( DC->getCVarValue( "m_pitch" ) ) );
03300     //else
03301     //  trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
03302 
03303     //trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
03304     //trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
03305     //trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
03306     //trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
03307     //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
03308     //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
03309     //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
03310     DC->executeText(EXEC_APPEND, "in_restart\n");
03311     //trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
03312 }
03313 
03314 /*
03315 =================
03316 Controls_SetDefaults
03317 =================
03318 */
03319 void Controls_SetDefaults( void )
03320 {
03321     int i;
03322 
03323     // iterate each command, set its default binding
03324   for (i=0; i < g_bindCount; i++)
03325     {
03326         g_bindings[i].bind1 = g_bindings[i].defaultbind1;
03327         g_bindings[i].bind2 = g_bindings[i].defaultbind2;
03328     }
03329 
03330     //s_controls.invertmouse.curvalue  = Controls_GetCvarDefault( "m_pitch" ) < 0;
03331     //s_controls.smoothmouse.curvalue  = Controls_GetCvarDefault( "m_filter" );
03332     //s_controls.alwaysrun.curvalue    = Controls_GetCvarDefault( "cl_run" );
03333     //s_controls.autoswitch.curvalue   = Controls_GetCvarDefault( "cg_autoswitch" );
03334     //s_controls.sensitivity.curvalue  = Controls_GetCvarDefault( "sensitivity" );
03335     //s_controls.joyenable.curvalue    = Controls_GetCvarDefault( "in_joystick" );
03336     //s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
03337     //s_controls.freelook.curvalue     = Controls_GetCvarDefault( "cl_freelook" );
03338 }
03339 
03340 int BindingIDFromName(const char *name) {
03341     int i;
03342   for (i=0; i < g_bindCount; i++)
03343     {
03344         if (Q_stricmp(name, g_bindings[i].command) == 0) {
03345             return i;
03346         }
03347     }
03348     return -1;
03349 }
03350 
03351 char g_nameBind1[32];
03352 char g_nameBind2[32];
03353 
03354 void BindingFromName(const char *cvar) {
03355     int i, b1, b2;
03356 
03357     // iterate each command, set its default binding
03358     for (i=0; i < g_bindCount; i++)
03359     {
03360         if (Q_stricmp(cvar, g_bindings[i].command) == 0) {
03361             b1 = g_bindings[i].bind1;
03362             if (b1 == -1) {
03363                 break;
03364             }
03365                 DC->keynumToStringBuf( b1, g_nameBind1, 32 );
03366                 Q_strupr(g_nameBind1);
03367 
03368                 b2 = g_bindings[i].bind2;
03369                 if (b2 != -1)
03370                 {
03371                     DC->keynumToStringBuf( b2, g_nameBind2, 32 );
03372                     Q_strupr(g_nameBind2);
03373                     strcat( g_nameBind1, " or " );
03374                     strcat( g_nameBind1, g_nameBind2 );
03375                 }
03376             return;
03377         }
03378     }
03379     strcpy(g_nameBind1, "???");
03380 }
03381 
03382 void Item_Slider_Paint(itemDef_t *item) {
03383     vec4_t newColor, lowLight;
03384     float x, y, value;
03385     menuDef_t *parent = (menuDef_t*)item->parent;
03386 
03387     value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
03388 
03389     if (item->window.flags & WINDOW_HASFOCUS) {
03390         lowLight[0] = 0.8 * parent->focusColor[0]; 
03391         lowLight[1] = 0.8 * parent->focusColor[1]; 
03392         lowLight[2] = 0.8 * parent->focusColor[2]; 
03393         lowLight[3] = 0.8 * parent->focusColor[3]; 
03394         LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
03395     } else {
03396         memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
03397     }
03398 
03399     y = item->window.rect.y;
03400     if (item->text) {
03401         Item_Text_Paint(item);
03402         x = item->textRect.x + item->textRect.w + 8;
03403     } else {
03404         x = item->window.rect.x;
03405     }
03406     DC->setColor(newColor);
03407     DC->drawHandlePic( x, y, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar );
03408 
03409     x = Item_Slider_ThumbPosition(item);
03410     DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y - 2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb );
03411 
03412 }
03413 
03414 void Item_Bind_Paint(itemDef_t *item) {
03415     vec4_t newColor, lowLight;
03416     float value;
03417     int maxChars = 0;
03418     menuDef_t *parent = (menuDef_t*)item->parent;
03419     editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
03420     if (editPtr) {
03421         maxChars = editPtr->maxPaintChars;
03422     }
03423 
03424     value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
03425 
03426     if (item->window.flags & WINDOW_HASFOCUS) {
03427         if (g_bindItem == item) {
03428             lowLight[0] = 0.8f * 1.0f;
03429             lowLight[1] = 0.8f * 0.0f;
03430             lowLight[2] = 0.8f * 0.0f;
03431             lowLight[3] = 0.8f * 1.0f;
03432         } else {
03433             lowLight[0] = 0.8f * parent->focusColor[0]; 
03434             lowLight[1] = 0.8f * parent->focusColor[1]; 
03435             lowLight[2] = 0.8f * parent->focusColor[2]; 
03436             lowLight[3] = 0.8f * parent->focusColor[3]; 
03437         }
03438         LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
03439     } else {
03440         memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
03441     }
03442 
03443     if (item->text) {
03444         Item_Text_Paint(item);
03445         BindingFromName(item->cvar);
03446         DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, 0, maxChars, item->textStyle);
03447     } else {
03448         DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "FIXME" : "FIXME", 0, maxChars, item->textStyle);
03449     }
03450 }
03451 
03452 qboolean Display_KeyBindPending() {
03453     return g_waitingForKey;
03454 }
03455 
03456 qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) {
03457     int         id;
03458     int         i;
03459 
03460     if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey)
03461     {
03462         if (down && (key == K_MOUSE1 || key == K_ENTER)) {
03463             g_waitingForKey = qtrue;
03464             g_bindItem = item;
03465         }
03466         return qtrue;
03467     }
03468     else
03469     {
03470         if (!g_waitingForKey || g_bindItem == NULL) {
03471             return qtrue;
03472         }
03473 
03474         if (key & K_CHAR_FLAG) {
03475             return qtrue;
03476         }
03477 
03478         switch (key)
03479         {
03480             case K_ESCAPE:
03481                 g_waitingForKey = qfalse;
03482                 return qtrue;
03483     
03484             case K_BACKSPACE:
03485                 id = BindingIDFromName(item->cvar);
03486                 if (id != -1) {
03487                     g_bindings[id].bind1 = -1;
03488                     g_bindings[id].bind2 = -1;
03489                 }
03490                 Controls_SetConfig(qtrue);
03491                 g_waitingForKey = qfalse;
03492                 g_bindItem = NULL;
03493                 return qtrue;
03494 
03495             case '`':
03496                 return qtrue;
03497         }
03498     }
03499 
03500     if (key != -1)
03501     {
03502 
03503         for (i=0; i < g_bindCount; i++)
03504         {
03505 
03506             if (g_bindings[i].bind2 == key) {
03507                 g_bindings[i].bind2 = -1;
03508             }
03509 
03510             if (g_bindings[i].bind1 == key)
03511             {
03512                 g_bindings[i].bind1 = g_bindings[i].bind2;
03513                 g_bindings[i].bind2 = -1;
03514             }
03515         }
03516     }
03517 
03518 
03519     id = BindingIDFromName(item->cvar);
03520 
03521     if (id != -1) {
03522         if (key == -1) {
03523             if( g_bindings[id].bind1 != -1 ) {
03524                 DC->setBinding( g_bindings[id].bind1, "" );
03525                 g_bindings[id].bind1 = -1;
03526             }
03527             if( g_bindings[id].bind2 != -1 ) {
03528                 DC->setBinding( g_bindings[id].bind2, "" );
03529                 g_bindings[id].bind2 = -1;
03530             }
03531         }
03532         else if (g_bindings[id].bind1 == -1) {
03533             g_bindings[id].bind1 = key;
03534         }
03535         else if (g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1) {
03536             g_bindings[id].bind2 = key;
03537         }
03538         else {
03539             DC->setBinding( g_bindings[id].bind1, "" );
03540             DC->setBinding( g_bindings[id].bind2, "" );
03541             g_bindings[id].bind1 = key;
03542             g_bindings[id].bind2 = -1;
03543         }                       
03544     }
03545 
03546     Controls_SetConfig(qtrue);  
03547     g_waitingForKey = qfalse;
03548 
03549     return qtrue;
03550 }
03551 
03552 
03553 
03554 void AdjustFrom640(float *x, float *y, float *w, float *h) {
03555     //*x = *x * DC->scale + DC->bias;
03556     *x *= DC->xscale;
03557     *y *= DC->yscale;
03558     *w *= DC->xscale;
03559     *h *= DC->yscale;
03560 }
03561 
03562 void Item_Model_Paint(itemDef_t *item) {
03563     float x, y, w, h;
03564     refdef_t refdef;
03565     refEntity_t     ent;
03566     vec3_t          mins, maxs, origin;
03567     vec3_t          angles;
03568     modelDef_t *modelPtr = (modelDef_t*)item->typeData;
03569 
03570     if (modelPtr == NULL) {
03571         return;
03572     }
03573 
03574     // setup the refdef
03575     memset( &refdef, 0, sizeof( refdef ) );
03576     refdef.rdflags = RDF_NOWORLDMODEL;
03577     AxisClear( refdef.viewaxis );
03578     x = item->window.rect.x+1;
03579     y = item->window.rect.y+1;
03580     w = item->window.rect.w-2;
03581     h = item->window.rect.h-2;
03582 
03583     AdjustFrom640( &x, &y, &w, &h );
03584 
03585     refdef.x = x;
03586     refdef.y = y;
03587     refdef.width = w;
03588     refdef.height = h;
03589 
03590     DC->modelBounds( item->asset, mins, maxs );
03591 
03592     origin[2] = -0.5 * ( mins[2] + maxs[2] );
03593     origin[1] = 0.5 * ( mins[1] + maxs[1] );
03594 
03595     // calculate distance so the model nearly fills the box
03596     if (qtrue) {
03597         float len = 0.5 * ( maxs[2] - mins[2] );        
03598         origin[0] = len / 0.268;    // len / tan( fov/2 )
03599         //origin[0] = len / tan(w/2);
03600     } else {
03601         origin[0] = item->textscale;
03602     }
03603     refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w;
03604     refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h;
03605 
03606     //refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
03607     //xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
03608     //refdef.fov_y = atan2( refdef.height, xx );
03609     //refdef.fov_y *= ( 360 / M_PI );
03610 
03611     DC->clearScene();
03612 
03613     refdef.time = DC->realTime;
03614 
03615     // add the model
03616 
03617     memset( &ent, 0, sizeof(ent) );
03618 
03619     //adjust = 5.0 * sin( (float)uis.realtime / 500 );
03620     //adjust = 360 % (int)((float)uis.realtime / 1000);
03621     //VectorSet( angles, 0, 0, 1 );
03622 
03623     // use item storage to track
03624     if (modelPtr->rotationSpeed) {
03625         if (DC->realTime > item->window.nextTime) {
03626             item->window.nextTime = DC->realTime + modelPtr->rotationSpeed;
03627             modelPtr->angle = (int)(modelPtr->angle + 1) % 360;
03628         }
03629     }
03630     VectorSet( angles, 0, modelPtr->angle, 0 );
03631     AnglesToAxis( angles, ent.axis );
03632 
03633     ent.hModel = item->asset;
03634     VectorCopy( origin, ent.origin );
03635     VectorCopy( origin, ent.lightingOrigin );
03636     ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
03637     VectorCopy( ent.origin, ent.oldorigin );
03638 
03639     DC->addRefEntityToScene( &ent );
03640     DC->renderScene( &refdef );
03641 
03642 }
03643 
03644 
03645 void Item_Image_Paint(itemDef_t *item) {
03646     if (item == NULL) {
03647         return;
03648     }
03649     DC->drawHandlePic(item->window.rect.x+1, item->window.rect.y+1, item->window.rect.w-2, item->window.rect.h-2, item->asset);
03650 }
03651 
03652 void Item_ListBox_Paint(itemDef_t *item) {
03653     float x, y, size, count, i, thumb;
03654     qhandle_t image;
03655     qhandle_t optionalImage;
03656     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
03657 
03658     // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction
03659     // elements are enumerated from the DC and either text or image handles are acquired from the DC as well
03660     // textscale is used to size the text, textalignx and textaligny are used to size image elements
03661     // there is no clipping available so only the last completely visible item is painted
03662     count = DC->feederCount(item->special);
03663     // default is vertical if horizontal flag is not here
03664     if (item->window.flags & WINDOW_HORIZONTAL) {
03665         // draw scrollbar in bottom of the window
03666         // bar
03667         x = item->window.rect.x + 1;
03668         y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE - 1;
03669         DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft);
03670         x += SCROLLBAR_SIZE - 1;
03671         size = item->window.rect.w - (SCROLLBAR_SIZE * 2);
03672         DC->drawHandlePic(x, y, size+1, SCROLLBAR_SIZE, DC->Assets.scrollBar);
03673         x += size - 1;
03674         DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowRight);
03675         // thumb
03676         thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
03677         if (thumb > x - SCROLLBAR_SIZE - 1) {
03678             thumb = x - SCROLLBAR_SIZE - 1;
03679         }
03680         DC->drawHandlePic(thumb, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
03681         //
03682         listPtr->endPos = listPtr->startPos;
03683         size = item->window.rect.w - 2;
03684         // items
03685         // size contains max available space
03686         if (listPtr->elementStyle == LISTBOX_IMAGE) {
03687             // fit = 0;
03688             x = item->window.rect.x + 1;
03689             y = item->window.rect.y + 1;
03690             for (i = listPtr->startPos; i < count; i++) {
03691                 // always draw at least one
03692                 // which may overdraw the box if it is too small for the element
03693                 image = DC->feederItemImage(item->special, i);
03694                 if (image) {
03695                     DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
03696                 }
03697 
03698                 if (i == item->cursorPos) {
03699                     DC->drawRect(x, y, listPtr->elementWidth-1, listPtr->elementHeight-1, item->window.borderSize, item->window.borderColor);
03700                 }
03701 
03702                 size -= listPtr->elementWidth;
03703                 if (size < listPtr->elementWidth) {
03704                     listPtr->drawPadding = size; //listPtr->elementWidth - size;
03705                     break;
03706                 }
03707                 x += listPtr->elementWidth;
03708                 listPtr->endPos++;
03709                 // fit++;
03710             }
03711         } else {
03712             //
03713         }
03714     } else {
03715         // draw scrollbar to right side of the window
03716         x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1;
03717         y = item->window.rect.y + 1;
03718         DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp);
03719         y += SCROLLBAR_SIZE - 1;
03720 
03721         listPtr->endPos = listPtr->startPos;
03722         size = item->window.rect.h - (SCROLLBAR_SIZE * 2);
03723         DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar);
03724         y += size - 1;
03725         DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown);
03726         // thumb
03727         thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
03728         if (thumb > y - SCROLLBAR_SIZE - 1) {
03729             thumb = y - SCROLLBAR_SIZE - 1;
03730         }
03731         DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
03732 
03733         // adjust size for item painting
03734         size = item->window.rect.h - 2;
03735         if (listPtr->elementStyle == LISTBOX_IMAGE) {
03736             // fit = 0;
03737             x = item->window.rect.x + 1;
03738             y = item->window.rect.y + 1;
03739             for (i = listPtr->startPos; i < count; i++) {
03740                 // always draw at least one
03741                 // which may overdraw the box if it is too small for the element
03742                 image = DC->feederItemImage(item->special, i);
03743                 if (image) {
03744                     DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
03745                 }
03746 
03747                 if (i == item->cursorPos) {
03748                     DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.borderColor);
03749                 }
03750 
03751                 listPtr->endPos++;
03752                 size -= listPtr->elementWidth;
03753                 if (size < listPtr->elementHeight) {
03754                     listPtr->drawPadding = listPtr->elementHeight - size;
03755                     break;
03756                 }
03757                 y += listPtr->elementHeight;
03758                 // fit++;
03759             }
03760         } else {
03761             x = item->window.rect.x + 1;
03762             y = item->window.rect.y + 1;
03763             for (i = listPtr->startPos; i < count; i++) {
03764                 const char *text;
03765                 // always draw at least one
03766                 // which may overdraw the box if it is too small for the element
03767 
03768                 if (listPtr->numColumns > 0) {
03769                     int j;
03770                     for (j = 0; j < listPtr->numColumns; j++) {
03771                         text = DC->feederItemText(item->special, i, j, &optionalImage);
03772                         if (optionalImage >= 0) {
03773                             DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
03774                         } else if (text) {
03775                             DC->drawText(x + 4 + listPtr->columnInfo[j].pos, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, listPtr->columnInfo[j].maxChars, item->textStyle);
03776                         }
03777                     }
03778                 } else {
03779                     text = DC->feederItemText(item->special, i, 0, &optionalImage);
03780                     if (optionalImage >= 0) {
03781                         //DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
03782                     } else if (text) {
03783                         DC->drawText(x + 4, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, 0, item->textStyle);
03784                     }
03785                 }
03786 
03787                 if (i == item->cursorPos) {
03788                     DC->fillRect(x + 2, y + 2, item->window.rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight, item->window.outlineColor);
03789                 }
03790 
03791                 size -= listPtr->elementHeight;
03792                 if (size < listPtr->elementHeight) {
03793                     listPtr->drawPadding = listPtr->elementHeight - size;
03794                     break;
03795                 }
03796                 listPtr->endPos++;
03797                 y += listPtr->elementHeight;
03798                 // fit++;
03799             }
03800         }
03801     }
03802 }
03803 
03804 
03805 void Item_OwnerDraw_Paint(itemDef_t *item) {
03806   menuDef_t *parent;
03807 
03808     if (item == NULL) {
03809         return;
03810     }
03811   parent = (menuDef_t*)item->parent;
03812 
03813     if (DC->ownerDrawItem) {
03814         vec4_t color, lowLight;
03815         menuDef_t *parent = (menuDef_t*)item->parent;
03816         Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
03817         memcpy(&color, &item->window.foreColor, sizeof(color));
03818         if (item->numColors > 0 && DC->getValue) {
03819             // if the value is within one of the ranges then set color to that, otherwise leave at default
03820             int i;
03821             float f = DC->getValue(item->window.ownerDraw);
03822             for (i = 0; i < item->numColors; i++) {
03823                 if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high) {
03824                     memcpy(&color, &item->colorRanges[i].color, sizeof(color));
03825                     break;
03826                 }
03827             }
03828         }
03829 
03830         if (item->window.flags & WINDOW_HASFOCUS) {
03831             lowLight[0] = 0.8 * parent->focusColor[0]; 
03832             lowLight[1] = 0.8 * parent->focusColor[1]; 
03833             lowLight[2] = 0.8 * parent->focusColor[2]; 
03834             lowLight[3] = 0.8 * parent->focusColor[3]; 
03835             LerpColor(parent->focusColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
03836         } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
03837             lowLight[0] = 0.8 * item->window.foreColor[0]; 
03838             lowLight[1] = 0.8 * item->window.foreColor[1]; 
03839             lowLight[2] = 0.8 * item->window.foreColor[2]; 
03840             lowLight[3] = 0.8 * item->window.foreColor[3]; 
03841             LerpColor(item->window.foreColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
03842         }
03843 
03844         if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
03845           memcpy(color, parent->disableColor, sizeof(vec4_t)); // bk001207 - FIXME: Com_Memcpy
03846         }
03847     
03848         if (item->text) {
03849             Item_Text_Paint(item);
03850                 if (item->text[0]) {
03851                     // +8 is an offset kludge to properly align owner draw items that have text combined with them
03852                     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 );
03853                 } else {
03854                     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 );
03855                 }
03856             } else {
03857             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 );
03858         }
03859     }
03860 }
03861 
03862 
03863 void Item_Paint(itemDef_t *item) {
03864   vec4_t red;
03865   menuDef_t *parent = (menuDef_t*)item->parent;
03866   red[0] = red[3] = 1;
03867   red[1] = red[2] = 0;
03868 
03869   if (item == NULL) {
03870     return;
03871   }
03872 
03873   if (item->window.flags & WINDOW_ORBITING) {
03874     if (DC->realTime > item->window.nextTime) {
03875       float rx, ry, a, c, s, w, h;
03876       
03877       item->window.nextTime = DC->realTime + item->window.offsetTime;
03878       // translate
03879       w = item->window.rectClient.w / 2;
03880       h = item->window.rectClient.h / 2;
03881       rx = item->window.rectClient.x + w - item->window.rectEffects.x;
03882       ry = item->window.rectClient.y + h - item->window.rectEffects.y;
03883       a = 3 * M_PI / 180;
03884       c = cos(a);
03885       s = sin(a);
03886       item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w;
03887       item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h;
03888       Item_UpdatePosition(item);
03889 
03890     }
03891   }
03892 
03893 
03894   if (item->window.flags & WINDOW_INTRANSITION) {
03895     if (DC->realTime > item->window.nextTime) {
03896       int done = 0;
03897       item->window.nextTime = DC->realTime + item->window.offsetTime;
03898             // transition the x,y
03899             if (item->window.rectClient.x == item->window.rectEffects.x) {
03900                 done++;
03901             } else {
03902                 if (item->window.rectClient.x < item->window.rectEffects.x) {
03903                     item->window.rectClient.x += item->window.rectEffects2.x;
03904                     if (item->window.rectClient.x > item->window.rectEffects.x) {
03905                         item->window.rectClient.x = item->window.rectEffects.x;
03906                         done++;
03907                     }
03908                 } else {
03909                     item->window.rectClient.x -= item->window.rectEffects2.x;
03910                     if (item->window.rectClient.x < item->window.rectEffects.x) {
03911                         item->window.rectClient.x = item->window.rectEffects.x;
03912                         done++;
03913                     }
03914                 }
03915             }
03916             if (item->window.rectClient.y == item->window.rectEffects.y) {
03917                 done++;
03918             } else {
03919                 if (item->window.rectClient.y < item->window.rectEffects.y) {
03920                     item->window.rectClient.y += item->window.rectEffects2.y;
03921                     if (item->window.rectClient.y > item->window.rectEffects.y) {
03922                         item->window.rectClient.y = item->window.rectEffects.y;
03923                         done++;
03924                     }
03925                 } else {
03926                     item->window.rectClient.y -= item->window.rectEffects2.y;
03927                     if (item->window.rectClient.y < item->window.rectEffects.y) {
03928                         item->window.rectClient.y = item->window.rectEffects.y;
03929                         done++;
03930                     }
03931                 }
03932             }
03933             if (item->window.rectClient.w == item->window.rectEffects.w) {
03934                 done++;
03935             } else {
03936                 if (item->window.rectClient.w < item->window.rectEffects.w) {
03937                     item->window.rectClient.w += item->window.rectEffects2.w;
03938                     if (item->window.rectClient.w > item->window.rectEffects.w) {
03939                         item->window.rectClient.w = item->window.rectEffects.w;
03940                         done++;
03941                     }
03942                 } else {
03943                     item->window.rectClient.w -= item->window.rectEffects2.w;
03944                     if (item->window.rectClient.w < item->window.rectEffects.w) {
03945                         item->window.rectClient.w = item->window.rectEffects.w;
03946                         done++;
03947                     }
03948                 }
03949             }
03950             if (item->window.rectClient.h == item->window.rectEffects.h) {
03951                 done++;
03952             } else {
03953                 if (item->window.rectClient.h < item->window.rectEffects.h) {
03954                     item->window.rectClient.h += item->window.rectEffects2.h;
03955                     if (item->window.rectClient.h > item->window.rectEffects.h) {
03956                         item->window.rectClient.h = item->window.rectEffects.h;
03957                         done++;
03958                     }
03959                 } else {
03960                     item->window.rectClient.h -= item->window.rectEffects2.h;
03961                     if (item->window.rectClient.h < item->window.rectEffects.h) {
03962                         item->window.rectClient.h = item->window.rectEffects.h;
03963                         done++;
03964                     }
03965                 }
03966             }
03967 
03968       Item_UpdatePosition(item);
03969 
03970       if (done == 4) {
03971         item->window.flags &= ~WINDOW_INTRANSITION;
03972       }
03973 
03974     }
03975   }
03976 
03977     if (item->window.ownerDrawFlags && DC->ownerDrawVisible) {
03978         if (!DC->ownerDrawVisible(item->window.ownerDrawFlags)) {
03979             item->window.flags &= ~WINDOW_VISIBLE;
03980         } else {
03981             item->window.flags |= WINDOW_VISIBLE;
03982         }
03983     }
03984 
03985     if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE)) {
03986         if (!Item_EnableShowViaCvar(item, CVAR_SHOW)) {
03987             return;
03988         }
03989     }
03990 
03991   if (item->window.flags & WINDOW_TIMEDVISIBLE) {
03992 
03993     }
03994 
03995   if (!(item->window.flags & WINDOW_VISIBLE)) {
03996     return;
03997   }
03998 
03999   // paint the rect first.. 
04000   Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle);
04001 
04002   if (debugMode) {
04003         vec4_t color;
04004         rectDef_t *r = Item_CorrectedTextRect(item);
04005     color[1] = color[3] = 1;
04006     color[0] = color[2] = 0;
04007     DC->drawRect(r->x, r->y, r->w, r->h, 1, color);
04008   }
04009 
04010   //DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red);
04011 
04012   switch (item->type) {
04013     case ITEM_TYPE_OWNERDRAW:
04014       Item_OwnerDraw_Paint(item);
04015       break;
04016     case ITEM_TYPE_TEXT:
04017     case ITEM_TYPE_BUTTON:
04018       Item_Text_Paint(item);
04019       break;
04020     case ITEM_TYPE_RADIOBUTTON:
04021       break;
04022     case ITEM_TYPE_CHECKBOX:
04023       break;
04024     case ITEM_TYPE_EDITFIELD:
04025     case ITEM_TYPE_NUMERICFIELD:
04026       Item_TextField_Paint(item);
04027       break;
04028     case ITEM_TYPE_COMBO:
04029       break;
04030     case ITEM_TYPE_LISTBOX:
04031       Item_ListBox_Paint(item);
04032       break;
04033     //case ITEM_TYPE_IMAGE:
04034     //  Item_Image_Paint(item);
04035     //  break;
04036     case ITEM_TYPE_MODEL:
04037       Item_Model_Paint(item);
04038       break;
04039     case ITEM_TYPE_YESNO:
04040       Item_YesNo_Paint(item);
04041       break;
04042     case ITEM_TYPE_MULTI:
04043       Item_Multi_Paint(item);
04044       break;
04045     case ITEM_TYPE_BIND:
04046       Item_Bind_Paint(item);
04047       break;
04048     case ITEM_TYPE_SLIDER:
04049       Item_Slider_Paint(item);
04050       break;
04051     default:
04052       break;
04053   }
04054 
04055 }
04056 
04057 void Menu_Init(menuDef_t *menu) {
04058     memset(menu, 0, sizeof(menuDef_t));
04059     menu->cursorItem = -1;
04060     menu->fadeAmount = DC->Assets.fadeAmount;
04061     menu->fadeClamp = DC->Assets.fadeClamp;
04062     menu->fadeCycle = DC->Assets.fadeCycle;
04063     Window_Init(&menu->window);
04064 }
04065 
04066 itemDef_t *Menu_GetFocusedItem(menuDef_t *menu) {
04067   int i;
04068   if (menu) {
04069     for (i = 0; i < menu->itemCount; i++) {
04070       if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
04071         return menu->items[i];
04072       }
04073     }
04074   }
04075   return NULL;
04076 }
04077 
04078 menuDef_t *Menu_GetFocused() {
04079   int i;
04080   for (i = 0; i < menuCount; i++) {
04081     if (Menus[i].window.flags & WINDOW_HASFOCUS && Menus[i].window.flags & WINDOW_VISIBLE) {
04082       return &Menus[i];
04083     }
04084   }
04085   return NULL;
04086 }
04087 
04088 void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down) {
04089     if (menu) {
04090         int i;
04091     for (i = 0; i < menu->itemCount; i++) {
04092             if (menu->items[i]->special == feeder) {
04093                 Item_ListBox_HandleKey(menu->items[i], (down) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue);
04094                 return;
04095             }
04096         }
04097     }
04098 }
04099 
04100 
04101 
04102 void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name) {
04103     if (menu == NULL) {
04104         if (name == NULL) {
04105             menu = Menu_GetFocused();
04106         } else {
04107             menu = Menus_FindByName(name);
04108         }
04109     }
04110 
04111     if (menu) {
04112         int i;
04113     for (i = 0; i < menu->itemCount; i++) {
04114             if (menu->items[i]->special == feeder) {
04115                 if (index == 0) {
04116                     listBoxDef_t *listPtr = (listBoxDef_t*)menu->items[i]->typeData;
04117                     listPtr->cursorPos = 0;
04118                     listPtr->startPos = 0;
04119                 }
04120                 menu->items[i]->cursorPos = index;
04121                 DC->feederSelection(menu->items[i]->special, menu->items[i]->cursorPos);
04122                 return;
04123             }
04124         }
04125     }
04126 }
04127 
04128 qboolean Menus_AnyFullScreenVisible() {
04129   int i;
04130   for (i = 0; i < menuCount; i++) {
04131     if (Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen) {
04132             return qtrue;
04133     }
04134   }
04135   return qfalse;
04136 }
04137 
04138 menuDef_t *Menus_ActivateByName(const char *p) {
04139   int i;
04140   menuDef_t *m = NULL;
04141     menuDef_t *focus = Menu_GetFocused();
04142   for (i = 0; i < menuCount; i++) {
04143     if (Q_stricmp(Menus[i].window.name, p) == 0) {
04144         m = &Menus[i];
04145             Menus_Activate(m);
04146             if (openMenuCount < MAX_OPEN_MENUS && focus != NULL) {
04147                 menuStack[openMenuCount++] = focus;
04148             }
04149     } else {
04150       Menus[i].window.flags &= ~WINDOW_HASFOCUS;
04151     }
04152   }
04153     Display_CloseCinematics();
04154   return m;
04155 }
04156 
04157 
04158 void Item_Init(itemDef_t *item) {
04159     memset(item, 0, sizeof(itemDef_t));
04160     item->textscale = 0.55f;
04161     Window_Init(&item->window);
04162 }
04163 
04164 void Menu_HandleMouseMove(menuDef_t *menu, float x, float y) {
04165   int i, pass;
04166   qboolean focusSet = qfalse;
04167 
04168   itemDef_t *overItem;
04169   if (menu == NULL) {
04170     return;
04171   }
04172 
04173   if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
04174     return;
04175   }
04176 
04177     if (itemCapture) {
04178         //Item_MouseMove(itemCapture, x, y);
04179         return;
04180     }
04181 
04182     if (g_waitingForKey || g_editingField) {
04183         return;
04184     }
04185 
04186   // FIXME: this is the whole issue of focus vs. mouse over.. 
04187   // need a better overall solution as i don't like going through everything twice
04188   for (pass = 0; pass < 2; pass++) {
04189     for (i = 0; i < menu->itemCount; i++) {
04190       // turn off focus each item
04191       // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
04192 
04193       if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
04194         continue;
04195       }
04196 
04197             // items can be enabled and disabled based on cvars
04198             if (menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE)) {
04199                 continue;
04200             }
04201 
04202             if (menu->items[i]->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_SHOW)) {
04203                 continue;
04204             }
04205 
04206 
04207 
04208       if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
04209                 if (pass == 1) {
04210                     overItem = menu->items[i];
04211                     if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
04212                         if (!Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
04213                             continue;
04214                         }
04215                     }
04216                     // if we are over an item
04217                     if (IsVisible(overItem->window.flags)) {
04218                         // different one
04219                         Item_MouseEnter(overItem, x, y);
04220                         // Item_SetMouseOver(overItem, qtrue);
04221 
04222                         // if item is not a decoration see if it can take focus
04223                         if (!focusSet) {
04224                             focusSet = Item_SetFocus(overItem, x, y);
04225                         }
04226                     }
04227                 }
04228       } else if (menu->items[i]->window.flags & WINDOW_MOUSEOVER) {
04229           Item_MouseLeave(menu->items[i]);
04230           Item_SetMouseOver(menu->items[i], qfalse);
04231       }
04232     }
04233   }
04234 
04235 }
04236 
04237 void Menu_Paint(menuDef_t *menu, qboolean forcePaint) {
04238     int i;
04239 
04240     if (menu == NULL) {
04241         return;
04242     }
04243 
04244     if (!(menu->window.flags & WINDOW_VISIBLE) &&  !forcePaint) {
04245         return;
04246     }
04247 
04248     if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags)) {
04249         return;
04250     }
04251     
04252     if (forcePaint) {
04253         menu->window.flags |= WINDOW_FORCED;
04254     }
04255 
04256     // draw the background if necessary
04257     if (menu->fullScreen) {
04258         // implies a background shader
04259         // FIXME: make sure we have a default shader if fullscreen is set with no background
04260         DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background );
04261     } else if (menu->window.background) {
04262         // this allows a background shader without being full screen
04263         //UI_DrawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader);
04264     }
04265 
04266     // paint the background and or border
04267     Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle );
04268 
04269     for (i = 0; i < menu->itemCount; i++) {
04270         Item_Paint(menu->items[i]);
04271     }
04272 
04273     if (debugMode) {
04274         vec4_t color;
04275         color[0] = color[2] = color[3] = 1;
04276         color[1] = 0;
04277         DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color);
04278     }
04279 }
04280 
04281 /*
04282 ===============
04283 Item_ValidateTypeData
04284 ===============
04285 */
04286 void Item_ValidateTypeData(itemDef_t *item) {
04287     if (item->typeData) {
04288         return;
04289     }
04290 
04291     if (item->type == ITEM_TYPE_LISTBOX) {
04292         item->typeData = UI_Alloc(sizeof(listBoxDef_t));
04293         memset(item->typeData, 0, sizeof(listBoxDef_t));
04294     } 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) {
04295         item->typeData = UI_Alloc(sizeof(editFieldDef_t));
04296         memset(item->typeData, 0, sizeof(editFieldDef_t));
04297         if (item->type == ITEM_TYPE_EDITFIELD) {
04298             if (!((editFieldDef_t *) item->typeData)->maxPaintChars) {
04299                 ((editFieldDef_t *) item->typeData)->maxPaintChars = MAX_EDITFIELD;
04300             }
04301         }
04302     } else if (item->type == ITEM_TYPE_MULTI) {
04303         item->typeData = UI_Alloc(sizeof(multiDef_t));
04304     } else if (item->type == ITEM_TYPE_MODEL) {
04305         item->typeData = UI_Alloc(sizeof(modelDef_t));
04306     }
04307 }
04308 
04309 /*
04310 ===============
04311 Keyword Hash
04312 ===============
04313 */
04314 
04315 #define KEYWORDHASH_SIZE    512
04316 
04317 typedef struct keywordHash_s
04318 {
04319     char *keyword;
04320     qboolean (*func)(itemDef_t *item, int handle);
04321     struct keywordHash_s *next;
04322 } keywordHash_t;
04323 
04324 int KeywordHash_Key(char *keyword) {
04325     int register hash, i;
04326 
04327     hash = 0;
04328     for (i = 0; keyword[i] != '\0'; i++) {
04329         if (keyword[i] >= 'A' && keyword[i] <= 'Z')
04330             hash += (keyword[i] + ('a' - 'A')) * (119 + i);
04331         else
04332             hash += keyword[i] * (119 + i);
04333     }
04334     hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (KEYWORDHASH_SIZE-1);
04335     return hash;
04336 }
04337 
04338 void KeywordHash_Add(keywordHash_t *table[], keywordHash_t *key) {
04339     int hash;
04340 
04341     hash = KeywordHash_Key(key->keyword);
04342 /*
04343     if (table[hash]) {
04344         int collision = qtrue;
04345     }
04346 */
04347     key->next = table[hash];
04348     table[hash] = key;
04349 }
04350 
04351 keywordHash_t *KeywordHash_Find(keywordHash_t *table[], char *keyword)
04352 {
04353     keywordHash_t *key;
04354     int hash;
04355 
04356     hash = KeywordHash_Key(keyword);
04357     for (key = table[hash]; key; key = key->next) {
04358         if (!Q_stricmp(key->keyword, keyword))
04359             return key;
04360     }
04361     return NULL;
04362 }
04363 
04364 /*
04365 ===============
04366 Item Keyword Parse functions
04367 ===============
04368 */
04369 
04370 // name <string>
04371 qboolean ItemParse_name( itemDef_t *item, int handle ) {
04372     if (!PC_String_Parse(handle, &item->window.name)) {
04373         return qfalse;
04374     }
04375     return qtrue;
04376 }
04377 
04378 // name <string>
04379 qboolean ItemParse_focusSound( itemDef_t *item, int handle ) {
04380     const char *temp;
04381     if (!PC_String_Parse(handle, &temp)) {
04382         return qfalse;
04383     }
04384     item->focusSound = DC->registerSound(temp, qfalse);
04385     return qtrue;
04386 }
04387 
04388 
04389 // text <string>
04390 qboolean ItemParse_text( itemDef_t *item, int handle ) {
04391     if (!PC_String_Parse(handle, &item->text)) {
04392         return qfalse;
04393     }
04394     return qtrue;
04395 }
04396 
04397 // group <string>
04398 qboolean ItemParse_group( itemDef_t *item, int handle ) {
04399     if (!PC_String_Parse(handle, &item->window.group)) {
04400         return qfalse;
04401     }
04402     return qtrue;
04403 }
04404 
04405 // asset_model <string>
04406 qboolean ItemParse_asset_model( itemDef_t *item, int handle ) {
04407     const char *temp;
04408     modelDef_t *modelPtr;
04409     Item_ValidateTypeData(item);
04410     modelPtr = (modelDef_t*)item->typeData;
04411 
04412     if (!PC_String_Parse(handle, &temp)) {
04413         return qfalse;
04414     }
04415     item->asset = DC->registerModel(temp);
04416     modelPtr->angle = rand() % 360;
04417     return qtrue;
04418 }
04419 
04420 // asset_shader <string>
04421 qboolean ItemParse_asset_shader( itemDef_t *item, int handle ) {
04422     const char *temp;
04423 
04424     if (!PC_String_Parse(handle, &temp)) {
04425         return qfalse;
04426     }
04427     item->asset = DC->registerShaderNoMip(temp);
04428     return qtrue;
04429 }
04430 
04431 // model_origin <number> <number> <number>
04432 qboolean ItemParse_model_origin( itemDef_t *item, int handle ) {
04433     modelDef_t *modelPtr;
04434     Item_ValidateTypeData(item);
04435     modelPtr = (modelDef_t*)item->typeData;
04436 
04437     if (PC_Float_Parse(handle, &modelPtr->origin[0])) {
04438         if (PC_Float_Parse(handle, &modelPtr->origin[1])) {
04439             if (PC_Float_Parse(handle, &modelPtr->origin[2])) {
04440                 return qtrue;
04441             }
04442         }
04443     }
04444     return qfalse;
04445 }
04446 
04447 // model_fovx <number>
04448 qboolean ItemParse_model_fovx( itemDef_t *item, int handle ) {
04449     modelDef_t *modelPtr;
04450     Item_ValidateTypeData(item);
04451     modelPtr = (modelDef_t*)item->typeData;
04452 
04453     if (!PC_Float_Parse(handle, &modelPtr->fov_x)) {
04454         return qfalse;
04455     }
04456     return qtrue;
04457 }
04458 
04459 // model_fovy <number>
04460 qboolean ItemParse_model_fovy( itemDef_t *item, int handle ) {
04461     modelDef_t *modelPtr;
04462     Item_ValidateTypeData(item);
04463     modelPtr = (modelDef_t*)item->typeData;
04464 
04465     if (!PC_Float_Parse(handle, &modelPtr->fov_y)) {
04466         return qfalse;
04467     }
04468     return qtrue;
04469 }
04470 
04471 // model_rotation <integer>
04472 qboolean ItemParse_model_rotation( itemDef_t *item, int handle ) {
04473     modelDef_t *modelPtr;
04474     Item_ValidateTypeData(item);
04475     modelPtr = (modelDef_t*)item->typeData;
04476 
04477     if (!PC_Int_Parse(handle, &modelPtr->rotationSpeed)) {
04478         return qfalse;
04479     }
04480     return qtrue;
04481 }
04482 
04483 // model_angle <integer>
04484 qboolean ItemParse_model_angle( itemDef_t *item, int handle ) {
04485     modelDef_t *modelPtr;
04486     Item_ValidateTypeData(item);
04487     modelPtr = (modelDef_t*)item->typeData;
04488 
04489     if (!PC_Int_Parse(handle, &modelPtr->angle)) {
04490         return qfalse;
04491     }
04492     return qtrue;
04493 }
04494 
04495 // rect <rectangle>
04496 qboolean ItemParse_rect( itemDef_t *item, int handle ) {
04497     if (!PC_Rect_Parse(handle, &item->window.rectClient)) {
04498         return qfalse;
04499     }
04500     return qtrue;
04501 }
04502 
04503 // style <integer>
04504 qboolean ItemParse_style( itemDef_t *item, int handle ) {
04505     if (!PC_Int_Parse(handle, &item->window.style)) {
04506         return qfalse;
04507     }
04508     return qtrue;
04509 }
04510 
04511 // decoration
04512 qboolean ItemParse_decoration( itemDef_t *item, int handle ) {
04513     item->window.flags |= WINDOW_DECORATION;
04514     return qtrue;
04515 }
04516 
04517 // notselectable
04518 qboolean ItemParse_notselectable( itemDef_t *item, int handle ) {
04519     listBoxDef_t *listPtr;
04520     Item_ValidateTypeData(item);
04521     listPtr = (listBoxDef_t*)item->typeData;
04522     if (item->type == ITEM_TYPE_LISTBOX && listPtr) {
04523         listPtr->notselectable = qtrue;
04524     }
04525     return qtrue;
04526 }
04527 
04528 // manually wrapped
04529 qboolean ItemParse_wrapped( itemDef_t *item, int handle ) {
04530     item->window.flags |= WINDOW_WRAPPED;
04531     return qtrue;
04532 }
04533 
04534 // auto wrapped
04535 qboolean ItemParse_autowrapped( itemDef_t *item, int handle ) {
04536     item->window.flags |= WINDOW_AUTOWRAPPED;
04537     return qtrue;
04538 }
04539 
04540 
04541 // horizontalscroll
04542 qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) {
04543     item->window.flags |= WINDOW_HORIZONTAL;
04544     return qtrue;
04545 }
04546 
04547 // type <integer>
04548 qboolean ItemParse_type( itemDef_t *item, int handle ) {
04549     if (!PC_Int_Parse(handle, &item->type)) {
04550         return qfalse;
04551     }
04552     Item_ValidateTypeData(item);
04553     return qtrue;
04554 }
04555 
04556 // elementwidth, used for listbox image elements
04557 // uses textalignx for storage
04558 qboolean ItemParse_elementwidth( itemDef_t *item, int handle ) {
04559     listBoxDef_t *listPtr;
04560 
04561     Item_ValidateTypeData(item);
04562     listPtr = (listBoxDef_t*)item->typeData;
04563     if (!PC_Float_Parse(handle, &listPtr->elementWidth)) {
04564         return qfalse;
04565     }
04566     return qtrue;
04567 }
04568 
04569 // elementheight, used for listbox image elements
04570 // uses textaligny for storage
04571 qboolean ItemParse_elementheight( itemDef_t *item, int handle ) {
04572     listBoxDef_t *listPtr;
04573 
04574     Item_ValidateTypeData(item);
04575     listPtr = (listBoxDef_t*)item->typeData;
04576     if (!PC_Float_Parse(handle, &listPtr->elementHeight)) {
04577         return qfalse;
04578     }
04579     return qtrue;
04580 }
04581 
04582 // feeder <float>
04583 qboolean ItemParse_feeder( itemDef_t *item, int handle ) {
04584     if (!PC_Float_Parse(handle, &item->special)) {
04585         return qfalse;
04586     }
04587     return qtrue;
04588 }
04589 
04590 // elementtype, used to specify what type of elements a listbox contains
04591 // uses textstyle for storage
04592 qboolean ItemParse_elementtype( itemDef_t *item, int handle ) {
04593     listBoxDef_t *listPtr;
04594 
04595     Item_ValidateTypeData(item);
04596     if (!item->typeData)
04597         return qfalse;
04598     listPtr = (listBoxDef_t*)item->typeData;
04599     if (!PC_Int_Parse(handle, &listPtr->elementStyle)) {
04600         return qfalse;
04601     }
04602     return qtrue;
04603 }
04604 
04605 // columns sets a number of columns and an x pos and width per.. 
04606 qboolean ItemParse_columns( itemDef_t *item, int handle ) {
04607     int num, i;
04608     listBoxDef_t *listPtr;
04609 
04610     Item_ValidateTypeData(item);
04611     if (!item->typeData)
04612         return qfalse;
04613     listPtr = (listBoxDef_t*)item->typeData;
04614     if (PC_Int_Parse(handle, &num)) {
04615         if (num > MAX_LB_COLUMNS) {
04616             num = MAX_LB_COLUMNS;
04617         }
04618         listPtr->numColumns = num;
04619         for (i = 0; i < num; i++) {
04620             int pos, width, maxChars;
04621 
04622             if (PC_Int_Parse(handle, &pos) && PC_Int_Parse(handle, &width) && PC_Int_Parse(handle, &maxChars)) {
04623                 listPtr->columnInfo[i].pos = pos;
04624                 listPtr->columnInfo[i].width = width;
04625                 listPtr->columnInfo[i].maxChars = maxChars;
04626             } else {
04627                 return qfalse;
04628             }
04629         }
04630     } else {
04631         return qfalse;
04632     }
04633     return qtrue;
04634 }
04635 
04636 qboolean ItemParse_border( itemDef_t *item, int handle ) {
04637     if (!PC_Int_Parse(handle, &item->window.border)) {
04638         return qfalse;
04639     }
04640     return qtrue;
04641 }
04642 
04643 qboolean ItemParse_bordersize( itemDef_t *item, int handle ) {
04644     if (!PC_Float_Parse(handle, &item->window.borderSize)) {
04645         return qfalse;
04646     }
04647     return qtrue;
04648 }
04649 
04650 qboolean ItemParse_visible( itemDef_t *item, int handle ) {
04651     int i;
04652 
04653     if (!PC_Int_Parse(handle, &i)) {
04654         return qfalse;
04655     }
04656     if (i) {
04657         item->window.flags |= WINDOW_VISIBLE;
04658     }
04659     return qtrue;
04660 }
04661 
04662 qboolean ItemParse_ownerdraw( itemDef_t *item, int handle ) {
04663     if (!PC_Int_Parse(handle, &item->window.ownerDraw)) {
04664         return qfalse;
04665     }
04666     item->type = ITEM_TYPE_OWNERDRAW;
04667     return qtrue;
04668 }
04669 
04670 qboolean ItemParse_align( itemDef_t *item, int handle ) {
04671     if (!PC_Int_Parse(handle, &item->alignment)) {
04672         return qfalse;
04673     }
04674     return qtrue;
04675 }
04676 
04677 qboolean ItemParse_textalign( itemDef_t *item, int handle ) {
04678     if (!PC_Int_Parse(handle, &item->textalignment)) {
04679         return qfalse;
04680     }
04681     return qtrue;
04682 }
04683 
04684 qboolean ItemParse_textalignx( itemDef_t *item, int handle ) {
04685     if (!PC_Float_Parse(handle, &item->textalignx)) {
04686         return qfalse;
04687     }
04688     return qtrue;
04689 }
04690 
04691 qboolean ItemParse_textaligny( itemDef_t *item, int handle ) {
04692     if (!PC_Float_Parse(handle, &item->textaligny)) {
04693         return qfalse;
04694     }
04695     return qtrue;
04696 }
04697 
04698 qboolean ItemParse_textscale( itemDef_t *item, int handle ) {
04699     if (!PC_Float_Parse(handle, &item->textscale)) {
04700         return qfalse;
04701     }
04702     return qtrue;
04703 }
04704 
04705 qboolean ItemParse_textstyle( itemDef_t *item, int handle ) {
04706     if (!PC_Int_Parse(handle, &item->textStyle)) {
04707         return qfalse;
04708     }
04709     return qtrue;
04710 }
04711 
04712 qboolean ItemParse_backcolor( itemDef_t *item, int handle ) {
04713     int i;
04714     float f;
04715 
04716     for (i = 0; i < 4; i++) {
04717         if (!PC_Float_Parse(handle, &f)) {
04718             return qfalse;
04719         }
04720         item->window.backColor[i]  = f;
04721     }
04722     return qtrue;
04723 }
04724 
04725 qboolean ItemParse_forecolor( itemDef_t *item, int handle ) {
04726     int i;
04727     float f;
04728 
04729     for (i = 0; i < 4; i++) {
04730         if (!PC_Float_Parse(handle, &f)) {
04731             return qfalse;
04732         }
04733         item->window.foreColor[i]  = f;
04734         item->window.flags |= WINDOW_FORECOLORSET;
04735     }
04736     return qtrue;
04737 }
04738 
04739 qboolean ItemParse_bordercolor( itemDef_t *item, int handle ) {
04740     int i;
04741     float f;
04742 
04743     for (i = 0; i < 4; i++) {
04744         if (!PC_Float_Parse(handle, &f)) {
04745             return qfalse;
04746         }
04747         item->window.borderColor[i]  = f;
04748     }
04749     return qtrue;
04750 }
04751 
04752 qboolean ItemParse_outlinecolor( itemDef_t *item, int handle ) {
04753     if (!PC_Color_Parse(handle, &item->window.outlineColor)){
04754         return qfalse;
04755     }
04756     return qtrue;
04757 }
04758 
04759 qboolean ItemParse_background( itemDef_t *item, int handle ) {
04760     const char *temp;
04761 
04762     if (!PC_String_Parse(handle, &temp)) {
04763         return qfalse;
04764     }
04765     item->window.background = DC->registerShaderNoMip(temp);
04766     return qtrue;
04767 }
04768 
04769 qboolean ItemParse_cinematic( itemDef_t *item, int handle ) {
04770     if (!PC_String_Parse(handle, &item->window.cinematicName)) {
04771         return qfalse;
04772     }
04773     return qtrue;
04774 }
04775 
04776 qboolean ItemParse_doubleClick( itemDef_t *item, int handle ) {
04777     listBoxDef_t *listPtr;
04778 
04779     Item_ValidateTypeData(item);
04780     if (!item->typeData) {
04781         return qfalse;
04782     }
04783 
04784     listPtr = (listBoxDef_t*)item->typeData;
04785 
04786     if (!PC_Script_Parse(handle, &listPtr->doubleClick)) {
04787         return qfalse;
04788     }
04789     return qtrue;
04790 }
04791 
04792 qboolean ItemParse_onFocus( itemDef_t *item, int handle ) {
04793     if (!PC_Script_Parse(handle, &item->onFocus)) {
04794         return qfalse;
04795     }
04796     return qtrue;
04797 }
04798 
04799 qboolean ItemParse_leaveFocus( itemDef_t *item, int handle ) {
04800     if (!PC_Script_Parse(handle, &item->leaveFocus)) {
04801         return qfalse;
04802     }
04803     return qtrue;
04804 }
04805 
04806 qboolean ItemParse_mouseEnter( itemDef_t *item, int handle ) {
04807     if (!PC_Script_Parse(handle, &item->mouseEnter)) {
04808         return qfalse;
04809     }
04810     return qtrue;
04811 }
04812 
04813 qboolean ItemParse_mouseExit( itemDef_t *item, int handle ) {
04814     if (!PC_Script_Parse(handle, &item->mouseExit)) {
04815         return qfalse;
04816     }
04817     return qtrue;
04818 }
04819 
04820 qboolean ItemParse_mouseEnterText( itemDef_t *item, int handle ) {
04821     if (!PC_Script_Parse(handle, &item->mouseEnterText)) {
04822         return qfalse;
04823     }
04824     return qtrue;
04825 }
04826 
04827 qboolean ItemParse_mouseExitText( itemDef_t *item, int handle ) {
04828     if (!PC_Script_Parse(handle, &item->mouseExitText)) {
04829         return qfalse;
04830     }
04831     return qtrue;
04832 }
04833 
04834 qboolean ItemParse_action( itemDef_t *item, int handle ) {
04835     if (!PC_Script_Parse(handle, &item->action)) {
04836         return qfalse;
04837     }
04838     return qtrue;
04839 }
04840 
04841 qboolean ItemParse_special( itemDef_t *item, int handle ) {
04842     if (!PC_Float_Parse(handle, &item->special)) {
04843         return qfalse;
04844     }
04845     return qtrue;
04846 }
04847 
04848 qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) {
04849     if (!PC_String_Parse(handle, &item->cvarTest)) {
04850         return qfalse;
04851     }
04852     return qtrue;
04853 }
04854 
04855 qboolean ItemParse_cvar( itemDef_t *item, int handle ) {
04856     editFieldDef_t *editPtr;
04857 
04858     Item_ValidateTypeData(item);
04859     if (!PC_String_Parse(handle, &item->cvar)) {
04860         return qfalse;
04861     }
04862     if (item->typeData) {
04863         editPtr = (editFieldDef_t*)item->typeData;
04864         editPtr->minVal = -1;
04865         editPtr->maxVal = -1;
04866         editPtr->defVal = -1;
04867     }
04868     return qtrue;
04869 }
04870 
04871 qboolean ItemParse_maxChars( itemDef_t *item, int handle ) {
04872     editFieldDef_t *editPtr;
04873     int maxChars;
04874 
04875     Item_ValidateTypeData(item);
04876     if (!item->typeData)
04877         return qfalse;
04878 
04879     if (!PC_Int_Parse(handle, &maxChars)) {
04880         return qfalse;
04881     }
04882     editPtr = (editFieldDef_t*)item->typeData;
04883     editPtr->maxChars = maxChars;
04884     return qtrue;
04885 }
04886 
04887 qboolean ItemParse_maxPaintChars( itemDef_t *item, int handle ) {
04888     editFieldDef_t *editPtr;
04889     int maxChars;
04890 
04891     Item_ValidateTypeData(item);
04892     if (!item->typeData)
04893         return qfalse;
04894 
04895     if (!PC_Int_Parse(handle, &maxChars)) {
04896         return qfalse;
04897     }
04898     editPtr = (editFieldDef_t*)item->typeData;
04899     editPtr->maxPaintChars = maxChars;
04900     return qtrue;
04901 }
04902 
04903 
04904 
04905 qboolean ItemParse_cvarFloat( itemDef_t *item, int handle ) {
04906     editFieldDef_t *editPtr;
04907 
04908     Item_ValidateTypeData(item);
04909     if (!item->typeData)
04910         return qfalse;
04911     editPtr = (editFieldDef_t*)item->typeData;
04912     if (PC_String_Parse(handle, &item->cvar) &&
04913         PC_Float_Parse(handle, &editPtr->defVal) &&
04914         PC_Float_Parse(handle, &editPtr->minVal) &&
04915         PC_Float_Parse(handle, &editPtr->maxVal)) {
04916         return qtrue;
04917     }
04918     return qfalse;
04919 }
04920 
04921 qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) {
04922     pc_token_t token;
04923     multiDef_t *multiPtr;
04924     int pass;
04925     
04926     Item_ValidateTypeData(item);
04927     if (!item->typeData)
04928         return qfalse;
04929     multiPtr = (multiDef_t*)item->typeData;
04930     multiPtr->count = 0;
04931     multiPtr->strDef = qtrue;
04932 
04933     if (!trap_PC_ReadToken(handle, &token))
04934         return qfalse;
04935     if (*token.string != '{') {
04936         return qfalse;
04937     }
04938 
04939     pass = 0;
04940     while ( 1 ) {
04941         if (!trap_PC_ReadToken(handle, &token)) {
04942             PC_SourceError(handle, "end of file inside menu item\n");
04943             return qfalse;
04944         }
04945 
04946         if (*token.string == '}') {
04947             return qtrue;
04948         }
04949 
04950         if (*token.string == ',' || *token.string == ';') {
04951             continue;
04952         }
04953 
04954         if (pass == 0) {
04955             multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
04956             pass = 1;
04957         } else {
04958             multiPtr->cvarStr[multiPtr->count] = String_Alloc(token.string);
04959             pass = 0;
04960             multiPtr->count++;
04961             if (multiPtr->count >= MAX_MULTI_CVARS) {
04962                 return qfalse;
04963             }
04964         }
04965 
04966     }
04967     return qfalse;  // bk001205 - LCC missing return value
04968 }
04969 
04970 qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) {
04971     pc_token_t token;
04972     multiDef_t *multiPtr;
04973     
04974     Item_ValidateTypeData(item);
04975     if (!item->typeData)
04976         return qfalse;
04977     multiPtr = (multiDef_t*)item->typeData;
04978     multiPtr->count = 0;
04979     multiPtr->strDef = qfalse;
04980 
04981     if (!trap_PC_ReadToken(handle, &token))
04982         return qfalse;
04983     if (*token.string != '{') {
04984         return qfalse;
04985     }
04986 
04987     while ( 1 ) {
04988         if (!trap_PC_ReadToken(handle, &token)) {
04989             PC_SourceError(handle, "end of file inside menu item\n");
04990             return qfalse;
04991         }
04992 
04993         if (*token.string == '}') {
04994             return qtrue;
04995         }
04996 
04997         if (*token.string == ',' || *token.string == ';') {
04998             continue;
04999         }
05000 
05001         multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
05002         if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count])) {
05003             return qfalse;
05004         }
05005 
05006         multiPtr->count++;
05007         if (multiPtr->count >= MAX_MULTI_CVARS) {
05008             return qfalse;
05009         }
05010 
05011     }
05012     return qfalse;  // bk001205 - LCC missing return value
05013 }
05014 
05015 
05016 
05017 qboolean ItemParse_addColorRange( itemDef_t *item, int handle ) {
05018     colorRangeDef_t color;
05019 
05020     if (PC_Float_Parse(handle, &color.low) &&
05021         PC_Float_Parse(handle, &color.high) &&
05022         PC_Color_Parse(handle, &color.color) ) {
05023         if (item->numColors < MAX_COLOR_RANGES) {
05024             memcpy(&item->colorRanges[item->numColors], &color, sizeof(color));
05025             item->numColors++;
05026         }
05027         return qtrue;
05028     }
05029     return qfalse;
05030 }
05031 
05032 qboolean ItemParse_ownerdrawFlag( itemDef_t *item, int handle ) {
05033     int i;
05034     if (!PC_Int_Parse(handle, &i)) {
05035         return qfalse;
05036     }
05037     item->window.ownerDrawFlags |= i;
05038     return qtrue;
05039 }
05040 
05041 qboolean ItemParse_enableCvar( itemDef_t *item, int handle ) {
05042     if (PC_Script_Parse(handle, &item->enableCvar)) {
05043         item->cvarFlags = CVAR_ENABLE;
05044         return qtrue;
05045     }
05046     return qfalse;
05047 }
05048 
05049 qboolean ItemParse_disableCvar( itemDef_t *item, int handle ) {
05050     if (PC_Script_Parse(handle, &item->enableCvar)) {
05051         item->cvarFlags = CVAR_DISABLE;
05052         return qtrue;
05053     }
05054     return qfalse;
05055 }
05056 
05057 qboolean ItemParse_showCvar( itemDef_t *item, int handle ) {
05058     if (PC_Script_Parse(handle, &item->enableCvar)) {
05059         item->cvarFlags = CVAR_SHOW;
05060         return qtrue;
05061     }
05062     return qfalse;
05063 }
05064 
05065 qboolean ItemParse_hideCvar( itemDef_t *item, int handle ) {
05066     if (PC_Script_Parse(handle, &item->enableCvar)) {
05067         item->cvarFlags = CVAR_HIDE;
05068         return qtrue;
05069     }
05070     return qfalse;
05071 }
05072 
05073 
05074 keywordHash_t itemParseKeywords[] = {
05075     {"name", ItemParse_name, NULL},
05076     {"text", ItemParse_text, NULL},
05077     {"group", ItemParse_group, NULL},
05078     {"asset_model", ItemParse_asset_model, NULL},
05079     {"asset_shader", ItemParse_asset_shader, NULL},
05080     {"model_origin", ItemParse_model_origin, NULL},
05081     {"model_fovx", ItemParse_model_fovx, NULL},
05082     {"model_fovy", ItemParse_model_fovy, NULL},
05083     {"model_rotation", ItemParse_model_rotation, NULL},
05084     {"model_angle", ItemParse_model_angle, NULL},
05085     {"rect", ItemParse_rect, NULL},
05086     {"style", ItemParse_style, NULL},
05087     {"decoration", ItemParse_decoration, NULL},
05088     {"notselectable", ItemParse_notselectable, NULL},
05089     {"wrapped", ItemParse_wrapped, NULL},
05090     {"autowrapped", ItemParse_autowrapped, NULL},
05091     {"horizontalscroll", ItemParse_horizontalscroll, NULL},
05092     {"type", ItemParse_type, NULL},
05093     {"elementwidth", ItemParse_elementwidth, NULL},
05094     {"elementheight", ItemParse_elementheight, NULL},
05095     {"feeder", ItemParse_feeder, NULL},
05096     {"elementtype", ItemParse_elementtype, NULL},
05097     {"columns", ItemParse_columns, NULL},
05098     {"border", ItemParse_border, NULL},
05099     {"bordersize", ItemParse_bordersize, NULL},
05100     {"visible", ItemParse_visible, NULL},
05101     {"ownerdraw", ItemParse_ownerdraw, NULL},
05102     {"align", ItemParse_align, NULL},
05103     {"textalign", ItemParse_textalign, NULL},
05104     {"textalignx", ItemParse_textalignx, NULL},
05105     {"textaligny", ItemParse_textaligny, NULL},
05106     {"textscale", ItemParse_textscale, NULL},
05107     {"textstyle", ItemParse_textstyle, NULL},
05108     {"backcolor", ItemParse_backcolor, NULL},
05109     {"forecolor", ItemParse_forecolor, NULL},
05110     {"bordercolor", ItemParse_bordercolor, NULL},
05111     {"outlinecolor", ItemParse_outlinecolor, NULL},
05112     {"background", ItemParse_background, NULL},
05113     {"onFocus", ItemParse_onFocus, NULL},
05114     {"leaveFocus", ItemParse_leaveFocus, NULL},
05115     {"mouseEnter", ItemParse_mouseEnter, NULL},
05116     {"mouseExit", ItemParse_mouseExit, NULL},
05117     {"mouseEnterText", ItemParse_mouseEnterText, NULL},
05118     {"mouseExitText", ItemParse_mouseExitText, NULL},
05119     {"action", ItemParse_action, NULL},
05120     {"special", ItemParse_special, NULL},
05121     {"cvar", ItemParse_cvar, NULL},
05122     {"maxChars", ItemParse_maxChars, NULL},
05123     {"maxPaintChars", ItemParse_maxPaintChars, NULL},
05124     {"focusSound", ItemParse_focusSound, NULL},
05125     {"cvarFloat", ItemParse_cvarFloat, NULL},
05126     {"cvarStrList", ItemParse_cvarStrList, NULL},
05127     {"cvarFloatList", ItemParse_cvarFloatList, NULL},
05128     {"addColorRange", ItemParse_addColorRange, NULL},
05129     {"ownerdrawFlag", ItemParse_ownerdrawFlag, NULL},
05130     {"enableCvar", ItemParse_enableCvar, NULL},
05131     {"cvarTest", ItemParse_cvarTest, NULL},
05132     {"disableCvar", ItemParse_disableCvar, NULL},
05133     {"showCvar", ItemParse_showCvar, NULL},
05134     {"hideCvar", ItemParse_hideCvar, NULL},
05135     {"cinematic", ItemParse_cinematic, NULL},
05136     {"doubleclick", ItemParse_doubleClick, NULL},
05137     {NULL, NULL, NULL}
05138 };
05139 
05140 keywordHash_t *itemParseKeywordHash[KEYWORDHASH_SIZE];
05141 
05142 /*
05143 ===============
05144 Item_SetupKeywordHash
05145 ===============
05146 */
05147 void Item_SetupKeywordHash(void) {
05148     int i;
05149 
05150     memset(itemParseKeywordHash, 0, sizeof(itemParseKeywordHash));
05151     for (i = 0; itemParseKeywords[i].keyword; i++) {
05152         KeywordHash_Add(itemParseKeywordHash, &itemParseKeywords[i]);
05153     }
05154 }
05155 
05156 /*
05157 ===============
05158 Item_Parse
05159 ===============
05160 */
05161 qboolean Item_Parse(int handle, itemDef_t *item) {
05162     pc_token_t token;
05163     keywordHash_t *key;
05164 
05165 
05166     if (!trap_PC_ReadToken(handle, &token))
05167         return qfalse;
05168     if (*token.string != '{') {
05169         return qfalse;
05170     }
05171     while ( 1 ) {
05172         if (!trap_PC_ReadToken(handle, &token)) {
05173             PC_SourceError(handle, "end of file inside menu item\n");
05174             return qfalse;
05175         }
05176 
05177         if (*token.string == '}') {
05178             return qtrue;
05179         }
05180 
05181         key = KeywordHash_Find(itemParseKeywordHash, token.string);
05182         if (!key) {
05183             PC_SourceError(handle, "unknown menu item keyword %s", token.string);
05184             continue;
05185         }
05186         if ( !key->func(item, handle) ) {
05187             PC_SourceError(handle, "couldn't parse menu item keyword %s", token.string);
05188             return qfalse;
05189         }
05190     }
05191     return qfalse;  // bk001205 - LCC missing return value
05192 }
05193 
05194 
05195 // Item_InitControls
05196 // init's special control types
05197 void Item_InitControls(itemDef_t *item) {
05198     if (item == NULL) {
05199         return;
05200     }
05201     if (item->type == ITEM_TYPE_LISTBOX) {
05202         listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
05203         item->cursorPos = 0;
05204         if (listPtr) {
05205             listPtr->cursorPos = 0;
05206             listPtr->startPos = 0;
05207             listPtr->endPos = 0;
05208             listPtr->cursorPos = 0;
05209         }
05210     }
05211 }
05212 
05213 /*
05214 ===============
05215 Menu Keyword Parse functions
05216 ===============
05217 */
05218 
05219 qboolean MenuParse_font( itemDef_t *item, int handle ) {
05220     menuDef_t *menu = (menuDef_t*)item;
05221     if (!PC_String_Parse(handle, &menu->font)) {
05222         return qfalse;
05223     }
05224     if (!DC->Assets.fontRegistered) {
05225         DC->registerFont(menu->font, 48, &DC->Assets.textFont);
05226         DC->Assets.fontRegistered = qtrue;
05227     }
05228     return qtrue;
05229 }
05230 
05231 qboolean MenuParse_name( itemDef_t *item, int handle ) {
05232     menuDef_t *menu = (menuDef_t*)item;
05233     if (!PC_String_Parse(handle, &menu->window.name)) {
05234         return qfalse;
05235     }
05236     if (Q_stricmp(menu->window.name, "main") == 0) {
05237         // default main as having focus
05238         //menu->window.flags |= WINDOW_HASFOCUS;
05239     }
05240     return qtrue;
05241 }
05242 
05243 qboolean MenuParse_fullscreen( itemDef_t *item, int handle ) {
05244     menuDef_t *menu = (menuDef_t*)item;
05245     if (!PC_Int_Parse(handle, (int*) &menu->fullScreen)) { // bk001206 - cast qboolean
05246         return qfalse;
05247     }
05248     return qtrue;
05249 }
05250 
05251 qboolean MenuParse_rect( itemDef_t *item, int handle ) {
05252     menuDef_t *menu = (menuDef_t*)item;
05253     if (!PC_Rect_Parse(handle, &menu->window.rect)) {
05254         return qfalse;
05255     }
05256     return qtrue;
05257 }
05258 
05259 qboolean MenuParse_style( itemDef_t *item, int handle ) {
05260     menuDef_t *menu = (menuDef_t*)item;
05261     if (!PC_Int_Parse(handle, &menu->window.style)) {
05262         return qfalse;
05263     }
05264     return qtrue;
05265 }
05266 
05267 qboolean MenuParse_visible( itemDef_t *item, int handle ) {
05268     int i;
05269     menuDef_t *menu = (menuDef_t*)item;
05270 
05271     if (!PC_Int_Parse(handle, &i)) {
05272         return qfalse;
05273     }
05274     if (i) {
05275         menu->window.flags |= WINDOW_VISIBLE;
05276     }
05277     return qtrue;
05278 }
05279 
05280 qboolean MenuParse_onOpen( itemDef_t *item, int handle ) {
05281     menuDef_t *menu = (menuDef_t*)item;
05282     if (!PC_Script_Parse(handle, &menu->onOpen)) {
05283         return qfalse;
05284     }
05285     return qtrue;
05286 }
05287 
05288 qboolean MenuParse_onClose( itemDef_t *item, int handle ) {
05289     menuDef_t *menu = (menuDef_t*)item;
05290     if (!PC_Script_Parse(handle, &menu->onClose)) {
05291         return qfalse;
05292     }
05293     return qtrue;
05294 }
05295 
05296 qboolean MenuParse_onESC( itemDef_t *item, int handle ) {
05297     menuDef_t *menu = (menuDef_t*)item;
05298     if (!PC_Script_Parse(handle, &menu->onESC)) {
05299         return qfalse;
05300     }
05301     return qtrue;
05302 }
05303 
05304 
05305 
05306 qboolean MenuParse_border( itemDef_t *item, int handle ) {
05307     menuDef_t *menu = (menuDef_t*)item;
05308     if (!PC_Int_Parse(handle, &menu->window.border)) {
05309         return qfalse;
05310     }
05311     return qtrue;
05312 }
05313 
05314 qboolean MenuParse_borderSize( itemDef_t *item, int handle ) {
05315     menuDef_t *menu = (menuDef_t*)item;
05316     if (!PC_Float_Parse(handle, &menu->window.borderSize)) {
05317         return qfalse;
05318     }
05319     return qtrue;
05320 }
05321 
05322 qboolean MenuParse_backcolor( itemDef_t *item, int handle ) {
05323     int i;
05324     float f;
05325     menuDef_t *menu = (menuDef_t*)item;
05326 
05327     for (i = 0; i < 4; i++) {
05328         if (!PC_Float_Parse(handle, &f)) {
05329             return qfalse;
05330         }
05331         menu->window.backColor[i]  = f;
05332     }
05333     return qtrue;
05334 }
05335 
05336 qboolean MenuParse_forecolor( itemDef_t *item, int handle ) {
05337     int i;
05338     float f;
05339     menuDef_t *menu = (menuDef_t*)item;
05340 
05341     for (i = 0; i < 4; i++) {
05342         if (!PC_Float_Parse(handle, &f)) {
05343             return qfalse;
05344         }
05345         menu->window.foreColor[i]  = f;
05346         menu->window.flags |= WINDOW_FORECOLORSET;
05347     }
05348     return qtrue;
05349 }
05350 
05351 qboolean MenuParse_bordercolor( itemDef_t *item, int handle ) {
05352     int i;
05353     float f;
05354     menuDef_t *menu = (menuDef_t*)item;
05355 
05356     for (i = 0; i < 4; i++) {
05357         if (!PC_Float_Parse(handle, &f)) {
05358             return qfalse;
05359         }
05360         menu->window.borderColor[i]  = f;
05361     }
05362     return qtrue;
05363 }
05364 
05365 qboolean MenuParse_focuscolor( itemDef_t *item, int handle ) {
05366     int i;
05367     float f;
05368     menuDef_t *menu = (menuDef_t*)item;
05369 
05370     for (i = 0; i < 4; i++) {
05371         if (!PC_Float_Parse(handle, &f)) {
05372             return qfalse;
05373         }
05374         menu->focusColor[i]  = f;
05375     }
05376     return qtrue;
05377 }
05378 
05379 qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) {
05380     int i;
05381     float f;
05382     menuDef_t *menu = (menuDef_t*)item;
05383     for (i = 0; i < 4; i++) {
05384         if (!PC_Float_Parse(handle, &f)) {
05385             return qfalse;
05386         }
05387         menu->disableColor[i]  = f;
05388     }
05389     return qtrue;
05390 }
05391 
05392 
05393 qboolean MenuParse_outlinecolor( itemDef_t *item, int handle ) {
05394     menuDef_t *menu = (menuDef_t*)item;
05395     if (!PC_Color_Parse(handle, &menu->window.outlineColor)){
05396         return qfalse;
05397     }
05398     return qtrue;
05399 }
05400 
05401 qboolean MenuParse_background( itemDef_t *item, int handle ) {
05402     const char *buff;
05403     menuDef_t *menu = (menuDef_t*)item;
05404 
05405     if (!PC_String_Parse(handle, &buff)) {
05406         return qfalse;
05407     }
05408     menu->window.background = DC->registerShaderNoMip(buff);
05409     return qtrue;
05410 }
05411 
05412 qboolean MenuParse_cinematic( itemDef_t *item, int handle ) {
05413     menuDef_t *menu = (menuDef_t*)item;
05414 
05415     if (!PC_String_Parse(handle, &menu->window.cinematicName)) {
05416         return qfalse;
05417     }
05418     return qtrue;
05419 }
05420 
05421 qboolean MenuParse_ownerdrawFlag( itemDef_t *item, int handle ) {
05422     int i;
05423     menuDef_t *menu = (menuDef_t*)item;
05424 
05425     if (!PC_Int_Parse(handle, &i)) {
05426         return qfalse;
05427     }
05428     menu->window.ownerDrawFlags |= i;
05429     return qtrue;
05430 }
05431 
05432 qboolean MenuParse_ownerdraw( itemDef_t *item, int handle ) {
05433     menuDef_t *menu = (menuDef_t*)item;
05434 
05435     if (!PC_Int_Parse(handle, &menu->window.ownerDraw)) {
05436         return qfalse;
05437     }
05438     return qtrue;
05439 }
05440 
05441 
05442 // decoration
05443 qboolean MenuParse_popup( itemDef_t *item, int handle ) {
05444     menuDef_t *menu = (menuDef_t*)item;
05445     menu->window.flags |= WINDOW_POPUP;
05446     return qtrue;
05447 }
05448 
05449 
05450 qboolean MenuParse_outOfBounds( itemDef_t *item, int handle ) {
05451     menuDef_t *menu = (menuDef_t*)item;
05452 
05453     menu->window.flags |= WINDOW_OOB_CLICK;
05454     return qtrue;
05455 }
05456 
05457 qboolean MenuParse_soundLoop( itemDef_t *item, int handle ) {
05458     menuDef_t *menu = (menuDef_t*)item;
05459 
05460     if (!PC_String_Parse(handle, &menu->soundName)) {
05461         return qfalse;
05462     }
05463     return qtrue;
05464 }
05465 
05466 qboolean MenuParse_fadeClamp( itemDef_t *item, int handle ) {
05467     menuDef_t *menu = (menuDef_t*)item;
05468 
05469     if (!PC_Float_Parse(handle, &menu->fadeClamp)) {
05470         return qfalse;
05471     }
05472     return qtrue;
05473 }
05474 
05475 qboolean MenuParse_fadeAmount( itemDef_t *item, int handle ) {
05476     menuDef_t *menu = (menuDef_t*)item;
05477 
05478     if (!PC_Float_Parse(handle, &menu->fadeAmount)) {
05479         return qfalse;
05480     }
05481     return qtrue;
05482 }
05483 
05484 
05485 qboolean MenuParse_fadeCycle( itemDef_t *item, int handle ) {
05486     menuDef_t *menu = (menuDef_t*)item;
05487 
05488     if (!PC_Int_Parse(handle, &menu->fadeCycle)) {
05489         return qfalse;
05490     }
05491     return qtrue;
05492 }
05493 
05494 
05495 qboolean MenuParse_itemDef( itemDef_t *item, int handle ) {
05496     menuDef_t *menu = (menuDef_t*)item;
05497     if (menu->itemCount < MAX_MENUITEMS) {
05498         menu->items[menu->itemCount] = UI_Alloc(sizeof(itemDef_t));
05499         Item_Init(menu->items[menu->itemCount]);
05500         if (!Item_Parse(handle, menu->items[menu->itemCount])) {
05501             return qfalse;
05502         }
05503         Item_InitControls(menu->items[menu->itemCount]);
05504         menu->items[menu->itemCount++]->parent = menu;
05505     }
05506     return qtrue;
05507 }
05508 
05509 keywordHash_t menuParseKeywords[] = {
05510     {"font", MenuParse_font, NULL},
05511     {"name", MenuParse_name, NULL},
05512     {"fullscreen", MenuParse_fullscreen, NULL},
05513     {"rect", MenuParse_rect, NULL},
05514     {"style", MenuParse_style, NULL},
05515     {"visible", MenuParse_visible, NULL},
05516     {"onOpen", MenuParse_onOpen, NULL},
05517     {"onClose", MenuParse_onClose, NULL},
05518     {"onESC", MenuParse_onESC, NULL},
05519     {"border", MenuParse_border, NULL},
05520     {"borderSize", MenuParse_borderSize, NULL},
05521     {"backcolor", MenuParse_backcolor, NULL},
05522     {"forecolor", MenuParse_forecolor, NULL},
05523     {"bordercolor", MenuParse_bordercolor, NULL},
05524     {"focuscolor", MenuParse_focuscolor, NULL},
05525     {"disablecolor", MenuParse_disablecolor, NULL},
05526     {"outlinecolor", MenuParse_outlinecolor, NULL},
05527     {"background", MenuParse_background, NULL},
05528     {"ownerdraw", MenuParse_ownerdraw, NULL},
05529     {"ownerdrawFlag", MenuParse_ownerdrawFlag, NULL},
05530     {"outOfBoundsClick", MenuParse_outOfBounds, NULL},
05531     {"soundLoop", MenuParse_soundLoop, NULL},
05532     {"itemDef", MenuParse_itemDef, NULL},
05533     {"cinematic", MenuParse_cinematic, NULL},
05534     {"popup", MenuParse_popup, NULL},
05535     {"fadeClamp", MenuParse_fadeClamp, NULL},
05536     {"fadeCycle", MenuParse_fadeCycle, NULL},
05537     {"fadeAmount", MenuParse_fadeAmount, NULL},
05538     {NULL, NULL, NULL}
05539 };
05540 
05541 keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE];
05542 
05543 /*
05544 ===============
05545 Menu_SetupKeywordHash
05546 ===============
05547 */
05548 void Menu_SetupKeywordHash(void) {
05549     int i;
05550 
05551     memset(menuParseKeywordHash, 0, sizeof(menuParseKeywordHash));
05552     for (i = 0; menuParseKeywords[i].keyword; i++) {
05553         KeywordHash_Add(menuParseKeywordHash, &menuParseKeywords[i]);
05554     }
05555 }
05556 
05557 /*
05558 ===============
05559 Menu_Parse
05560 ===============
05561 */
05562 qboolean Menu_Parse(int handle, menuDef_t *menu) {
05563     pc_token_t token;
05564     keywordHash_t *key;
05565 
05566     if (!trap_PC_ReadToken(handle, &token))
05567         return qfalse;
05568     if (*token.string != '{') {
05569         return qfalse;
05570     }
05571     
05572     while ( 1 ) {
05573 
05574         memset(&token, 0, sizeof(pc_token_t));
05575         if (!trap_PC_ReadToken(handle, &token)) {
05576             PC_SourceError(handle, "end of file inside menu\n");
05577             return qfalse;
05578         }
05579 
05580         if (*token.string == '}') {
05581             return qtrue;
05582         }
05583 
05584         key = KeywordHash_Find(menuParseKeywordHash, token.string);
05585         if (!key) {
05586             PC_SourceError(handle, "unknown menu keyword %s", token.string);
05587             continue;
05588         }
05589         if ( !key->func((itemDef_t*)menu, handle) ) {
05590             PC_SourceError(handle, "couldn't parse menu keyword %s", token.string);
05591             return qfalse;
05592         }
05593     }
05594     return qfalse;  // bk001205 - LCC missing return value
05595 }
05596 
05597 /*
05598 ===============
05599 Menu_New
05600 ===============
05601 */
05602 void Menu_New(int handle) {
05603     menuDef_t *menu = &Menus[menuCount];
05604 
05605     if (menuCount < MAX_MENUS) {
05606         Menu_Init(menu);
05607         if (Menu_Parse(handle, menu)) {
05608             Menu_PostParse(menu);
05609             menuCount++;
05610         }
05611     }
05612 }
05613 
05614 int Menu_Count() {
05615     return menuCount;
05616 }
05617 
05618 void Menu_PaintAll() {
05619     int i;
05620     if (captureFunc) {
05621         captureFunc(captureData);
05622     }
05623 
05624     for (i = 0; i < Menu_Count(); i++) {
05625         Menu_Paint(&Menus[i], qfalse);
05626     }
05627 
05628     if (debugMode) {
05629         vec4_t v = {1, 1, 1, 1};
05630         DC->drawText(5, 25, .5, v, va("fps: %f", DC->FPS), 0, 0, 0);
05631     }
05632 }
05633 
05634 void Menu_Reset() {
05635     menuCount = 0;
05636 }
05637 
05638 displayContextDef_t *Display_GetContext() {
05639     return DC;
05640 }
05641  
05642 #ifndef MISSIONPACK // bk001206
05643 static float captureX;
05644 static float captureY;
05645 #endif
05646 
05647 void *Display_CaptureItem(int x, int y) {
05648     int i;
05649 
05650     for (i = 0; i < menuCount; i++) {
05651         // turn off focus each item
05652         // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
05653         if (Rect_ContainsPoint(&Menus[i].window.rect, x, y)) {
05654             return &Menus[i];
05655         }
05656     }
05657     return NULL;
05658 }
05659 
05660 
05661 // FIXME: 
05662 qboolean Display_MouseMove(void *p, int x, int y) {
05663     int i;
05664     menuDef_t *menu = p;
05665 
05666     if (menu == NULL) {
05667     menu = Menu_GetFocused();
05668         if (menu) {
05669             if (menu->window.flags & WINDOW_POPUP) {
05670                 Menu_HandleMouseMove(menu, x, y);
05671                 return qtrue;
05672             }
05673         }
05674         for (i = 0; i < menuCount; i++) {
05675             Menu_HandleMouseMove(&Menus[i], x, y);
05676         }
05677     } else {
05678         menu->window.rect.x += x;
05679         menu->window.rect.y += y;
05680         Menu_UpdatePosition(menu);
05681     }
05682     return qtrue;
05683 
05684 }
05685 
05686 int Display_CursorType(int x, int y) {
05687     int i;
05688     for (i = 0; i < menuCount; i++) {
05689         rectDef_t r2;
05690         r2.x = Menus[i].window.rect.x - 3;
05691         r2.y = Menus[i].window.rect.y - 3;
05692         r2.w = r2.h = 7;
05693         if (Rect_ContainsPoint(&r2, x, y)) {
05694             return CURSOR_SIZER;
05695         }
05696     }
05697     return CURSOR_ARROW;
05698 }
05699 
05700 
05701 void Display_HandleKey(int key, qboolean down, int x, int y) {
05702     menuDef_t *menu = Display_CaptureItem(x, y);
05703     if (menu == NULL) {  
05704         menu = Menu_GetFocused();
05705     }
05706     if (menu) {
05707         Menu_HandleKey(menu, key, down );
05708     }
05709 }
05710 
05711 static void Window_CacheContents(windowDef_t *window) {
05712     if (window) {
05713         if (window->cinematicName) {
05714             int cin = DC->playCinematic(window->cinematicName, 0, 0, 0, 0);
05715             DC->stopCinematic(cin);
05716         }
05717     }
05718 }
05719 
05720 
05721 static void Item_CacheContents(itemDef_t *item) {
05722     if (item) {
05723         Window_CacheContents(&item->window);
05724     }
05725 
05726 }
05727 
05728 static void Menu_CacheContents(menuDef_t *menu) {
05729     if (menu) {
05730         int i;
05731         Window_CacheContents(&menu->window);
05732         for (i = 0; i < menu->itemCount; i++) {
05733             Item_CacheContents(menu->items[i]);
05734         }
05735 
05736         if (menu->soundName && *menu->soundName) {
05737             DC->registerSound(menu->soundName, qfalse);
05738         }
05739     }
05740 
05741 }
05742 
05743 void Display_CacheAll() {
05744     int i;
05745     for (i = 0; i < menuCount; i++) {
05746         Menu_CacheContents(&Menus[i]);
05747     }
05748 }
05749 
05750 
05751 static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y) {
05752     if (menu && menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)) {
05753         if (Rect_ContainsPoint(&menu->window.rect, x, y)) {
05754             int i;
05755             for (i = 0; i < menu->itemCount; i++) {
05756                 // turn off focus each item
05757                 // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
05758 
05759                 if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
05760                     continue;
05761                 }
05762 
05763                 if (menu->items[i]->window.flags & WINDOW_DECORATION) {
05764                     continue;
05765                 }
05766 
05767                 if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
05768                     itemDef_t *overItem = menu->items[i];
05769                     if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
05770                         if (Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
05771                             return qtrue;
05772                         } else {
05773                             continue;
05774                         }
05775                     } else {
05776                         return qtrue;
05777                     }
05778                 }
05779             }
05780 
05781         }
05782     }
05783     return qfalse;
05784 }
05785 

Generated on Thu Aug 25 12:38:02 2005 for Quake III Arena by  doxygen 1.3.9.1