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,