1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2000-2006 Tim Angus
5 
6 This file is part of Tremulous.
7 
8 Tremulous is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12 
13 Tremulous is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Tremulous; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 ===========================================================================
22 */
23 
24 #include "ui_shared.h"
25 
26 #define SCROLL_TIME_START         500
27 #define SCROLL_TIME_ADJUST        150
28 #define SCROLL_TIME_ADJUSTOFFSET  40
29 #define SCROLL_TIME_FLOOR         20
30 
31 typedef struct scrollInfo_s {
32   int nextScrollTime;
33   int nextAdjustTime;
34   int adjustValue;
35   int scrollKey;
36   float xStart;
37   float yStart;
38   itemDef_t *item;
39   qboolean scrollDir;
40 } scrollInfo_t;
41 
42 static scrollInfo_t scrollInfo;
43 
44 //TA: hack to prevent compiler warnings
voidFunction(void * var)45 void voidFunction( void *var ) { return; }
voidFunction2(itemDef_t * var1,int var2)46 qboolean voidFunction2( itemDef_t *var1, int var2 ) { return qfalse; }
47 
48 static void (*captureFunc) (void *p) = voidFunction;
49 static void *captureData = NULL;
50 static itemDef_t *itemCapture = NULL;   // item that has the mouse captured ( if any )
51 
52 displayContextDef_t *DC = NULL;
53 
54 static qboolean g_waitingForKey = qfalse;
55 static qboolean g_editingField = qfalse;
56 
57 static itemDef_t *g_bindItem = NULL;
58 static itemDef_t *g_editItem = NULL;
59 
60 menuDef_t Menus[MAX_MENUS];      // defined menus
61 int menuCount = 0;               // how many
62 
63 menuDef_t *menuStack[MAX_OPEN_MENUS];
64 int openMenuCount = 0;
65 
66 static qboolean debugMode = qfalse;
67 
68 #define DOUBLE_CLICK_DELAY 300
69 static int lastListBoxClickTime = 0;
70 
71 void Item_RunScript(itemDef_t *item, const char *s);
72 void Item_SetupKeywordHash(void);
73 void Menu_SetupKeywordHash(void);
74 int BindingIDFromName(const char *name);
75 qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down);
76 itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu);
77 itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu);
78 static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y);
79 
80 #ifdef CGAME
81 #define MEM_POOL_SIZE  128 * 1024
82 #else
83 #define MEM_POOL_SIZE  1024 * 1024
84 #endif
85 
86 //TA: hacked variable name to avoid conflict with new cgame Alloc
87 static char   UI_memoryPool[MEM_POOL_SIZE];
88 static int    allocPoint, outOfMemory;
89 
90 /*
91 ===============
92 UI_Alloc
93 ===============
94 */
UI_Alloc(int size)95 void *UI_Alloc( int size )
96 {
97   char  *p;
98 
99   if( allocPoint + size > MEM_POOL_SIZE )
100   {
101     outOfMemory = qtrue;
102 
103     if( DC->Print )
104       DC->Print( "UI_Alloc: Failure. Out of memory!\n" );
105     //DC->trap_Print(S_COLOR_YELLOW"WARNING: UI Out of Memory!\n");
106     return NULL;
107   }
108 
109   p = &UI_memoryPool[ allocPoint ];
110 
111   allocPoint += ( size + 15 ) & ~15;
112 
113   return p;
114 }
115 
116 /*
117 ===============
118 UI_InitMemory
119 ===============
120 */
UI_InitMemory(void)121 void UI_InitMemory( void )
122 {
123   allocPoint = 0;
124   outOfMemory = qfalse;
125 }
126 
UI_OutOfMemory()127 qboolean UI_OutOfMemory( )
128 {
129   return outOfMemory;
130 }
131 
132 
133 
134 
135 
136 #define HASH_TABLE_SIZE 2048
137 /*
138 ================
139 return a hash value for the string
140 ================
141 */
hashForString(const char * str)142 static long hashForString(const char *str) {
143   int   i;
144   long  hash;
145   char  letter;
146 
147   hash = 0;
148   i = 0;
149   while (str[i] != '\0') {
150     letter = tolower(str[i]);
151     hash+=(long)(letter)*(i+119);
152     i++;
153   }
154   hash &= (HASH_TABLE_SIZE-1);
155   return hash;
156 }
157 
158 typedef struct stringDef_s {
159   struct stringDef_s *next;
160   const char *str;
161 } stringDef_t;
162 
163 static int strPoolIndex = 0;
164 static char strPool[STRING_POOL_SIZE];
165 
166 static int strHandleCount = 0;
167 static stringDef_t *strHandle[HASH_TABLE_SIZE];
168 
169 
String_Alloc(const char * p)170 const char *String_Alloc(const char *p) {
171   int len;
172   long hash;
173   stringDef_t *str, *last;
174   static const char *staticNULL = "";
175 
176   if (p == NULL) {
177     return NULL;
178   }
179 
180   if (*p == 0) {
181     return staticNULL;
182   }
183 
184   hash = hashForString(p);
185 
186   str = strHandle[hash];
187   while (str) {
188     if (strcmp(p, str->str) == 0) {
189       return str->str;
190     }
191     str = str->next;
192   }
193 
194   len = strlen(p);
195   if (len + strPoolIndex + 1 < STRING_POOL_SIZE) {
196     int ph = strPoolIndex;
197     strcpy(&strPool[strPoolIndex], p);
198     strPoolIndex += len + 1;
199 
200     str = strHandle[hash];
201     last = str;
202     while (str && str->next) {
203       last = str;
204       str = str->next;
205     }
206 
207     str  = UI_Alloc(sizeof(stringDef_t));
208     str->next = NULL;
209     str->str = &strPool[ph];
210     if (last) {
211       last->next = str;
212     } else {
213       strHandle[hash] = str;
214     }
215     return &strPool[ph];
216   }
217   return NULL;
218 }
219 
String_Report(void)220 void String_Report( void ) {
221   float f;
222   Com_Printf("Memory/String Pool Info\n");
223   Com_Printf("----------------\n");
224   f = strPoolIndex;
225   f /= STRING_POOL_SIZE;
226   f *= 100;
227   Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE);
228   f = allocPoint;
229   f /= MEM_POOL_SIZE;
230   f *= 100;
231   Com_Printf("Memory Pool is %.1f%% full, %i bytes out of %i used.\n", f, allocPoint, MEM_POOL_SIZE);
232 }
233 
234 /*
235 =================
236 String_Init
237 =================
238 */
String_Init(void)239 void String_Init( void )
240 {
241   int i;
242   for( i = 0; i < HASH_TABLE_SIZE; i++ )
243     strHandle[ i ] = 0;
244 
245   strHandleCount = 0;
246   strPoolIndex = 0;
247   menuCount = 0;
248   openMenuCount = 0;
249   UI_InitMemory( );
250   Item_SetupKeywordHash( );
251   Menu_SetupKeywordHash( );
252 
253   if( DC && DC->getBindingBuf )
254     Controls_GetConfig( );
255 }
256 
257 /*
258 =================
259 PC_SourceWarning
260 =================
261 */
PC_SourceWarning(int handle,char * format,...)262 void PC_SourceWarning(int handle, char *format, ...) {
263   int line;
264   char filename[128];
265   va_list argptr;
266   static char string[4096];
267 
268   va_start (argptr, format);
269   vsprintf (string, format, argptr);
270   va_end (argptr);
271 
272   filename[0] = '\0';
273   line = 0;
274   trap_PC_SourceFileAndLine(handle, filename, &line);
275 
276   Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string);
277 }
278 
279 /*
280 =================
281 PC_SourceError
282 =================
283 */
PC_SourceError(int handle,char * format,...)284 void PC_SourceError(int handle, char *format, ...) {
285   int line;
286   char filename[128];
287   va_list argptr;
288   static char string[4096];
289 
290   va_start (argptr, format);
291   vsprintf (string, format, argptr);
292   va_end (argptr);
293 
294   filename[0] = '\0';
295   line = 0;
296   trap_PC_SourceFileAndLine(handle, filename, &line);
297 
298   Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string);
299 }
300 
301 /*
302 =================
303 LerpColor
304 =================
305 */
LerpColor(vec4_t a,vec4_t b,vec4_t c,float t)306 void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
307 {
308   int i;
309 
310   // lerp and clamp each component
311   for (i=0; i<4; i++)
312   {
313     c[i] = a[i] + t*(b[i]-a[i]);
314     if (c[i] < 0)
315       c[i] = 0;
316     else if (c[i] > 1.0)
317       c[i] = 1.0;
318   }
319 }
320 
321 /*
322 =================
323 Float_Parse
324 =================
325 */
Float_Parse(char ** p,float * f)326 qboolean Float_Parse(char **p, float *f) {
327   char  *token;
328   token = COM_ParseExt(p, qfalse);
329   if (token && token[0] != 0) {
330     *f = atof(token);
331     return qtrue;
332   } else {
333     return qfalse;
334   }
335 }
336 
337 /*
338 =================
339 PC_Float_Parse
340 =================
341 */
PC_Float_Parse(int handle,float * f)342 qboolean PC_Float_Parse(int handle, float *f) {
343   pc_token_t token;
344   int negative = qfalse;
345 
346   if (!trap_PC_ReadToken(handle, &token))
347     return qfalse;
348   if (token.string[0] == '-') {
349     if (!trap_PC_ReadToken(handle, &token))
350       return qfalse;
351     negative = qtrue;
352   }
353   if (token.type != TT_NUMBER) {
354     PC_SourceError(handle, "expected float but found %s\n", token.string);
355     return qfalse;
356   }
357   if (negative)
358     *f = -token.floatvalue;
359   else
360     *f = token.floatvalue;
361   return qtrue;
362 }
363 
364 /*
365 =================
366 Color_Parse
367 =================
368 */
Color_Parse(char ** p,vec4_t * c)369 qboolean Color_Parse(char **p, vec4_t *c) {
370   int i;
371   float f;
372 
373   for (i = 0; i < 4; i++) {
374     if (!Float_Parse(p, &f)) {
375       return qfalse;
376     }
377     (*c)[i] = f;
378   }
379   return qtrue;
380 }
381 
382 /*
383 =================
384 PC_Color_Parse
385 =================
386 */
PC_Color_Parse(int handle,vec4_t * c)387 qboolean PC_Color_Parse(int handle, vec4_t *c) {
388   int i;
389   float f;
390 
391   for (i = 0; i < 4; i++) {
392     if (!PC_Float_Parse(handle, &f)) {
393       return qfalse;
394     }
395     (*c)[i] = f;
396   }
397   return qtrue;
398 }
399 
400 /*
401 =================
402 Int_Parse
403 =================
404 */
Int_Parse(char ** p,int * i)405 qboolean Int_Parse(char **p, int *i) {
406   char  *token;
407   token = COM_ParseExt(p, qfalse);
408 
409   if (token && token[0] != 0) {
410     *i = atoi(token);
411     return qtrue;
412   } else {
413     return qfalse;
414   }
415 }
416 
417 /*
418 =================
419 PC_Int_Parse
420 =================
421 */
PC_Int_Parse(int handle,int * i)422 qboolean PC_Int_Parse(int handle, int *i) {
423   pc_token_t token;
424   int negative = qfalse;
425 
426   if (!trap_PC_ReadToken(handle, &token))
427     return qfalse;
428   if (token.string[0] == '-') {
429     if (!trap_PC_ReadToken(handle, &token))
430       return qfalse;
431     negative = qtrue;
432   }
433   if (token.type != TT_NUMBER) {
434     PC_SourceError(handle, "expected integer but found %s\n", token.string);
435     return qfalse;
436   }
437   *i = token.intvalue;
438   if (negative)
439     *i = - *i;
440   return qtrue;
441 }
442 
443 /*
444 =================
445 Rect_Parse
446 =================
447 */
Rect_Parse(char ** p,rectDef_t * r)448 qboolean Rect_Parse(char **p, rectDef_t *r) {
449   if (Float_Parse(p, &r->x)) {
450     if (Float_Parse(p, &r->y)) {
451       if (Float_Parse(p, &r->w)) {
452         if (Float_Parse(p, &r->h)) {
453           return qtrue;
454         }
455       }
456     }
457   }
458   return qfalse;
459 }
460 
461 /*
462 =================
463 PC_Rect_Parse
464 =================
465 */
PC_Rect_Parse(int handle,rectDef_t * r)466 qboolean PC_Rect_Parse(int handle, rectDef_t *r) {
467   if (PC_Float_Parse(handle, &r->x)) {
468     if (PC_Float_Parse(handle, &r->y)) {
469       if (PC_Float_Parse(handle, &r->w)) {
470         if (PC_Float_Parse(handle, &r->h)) {
471           return qtrue;
472         }
473       }
474     }
475   }
476   return qfalse;
477 }
478 
479 /*
480 =================
481 String_Parse
482 =================
483 */
String_Parse(char ** p,const char ** out)484 qboolean String_Parse(char **p, const char **out) {
485   char *token;
486 
487   token = COM_ParseExt(p, qfalse);
488   if (token && token[0] != 0) {
489     *(out) = String_Alloc(token);
490     return qtrue;
491   }
492   return qfalse;
493 }
494 
495 /*
496 =================
497 PC_String_Parse
498 =================
499 */
PC_String_Parse(int handle,const char ** out)500 qboolean PC_String_Parse(int handle, const char **out) {
501   pc_token_t token;
502 
503   if (!trap_PC_ReadToken(handle, &token))
504     return qfalse;
505 
506   *(out) = String_Alloc(token.string);
507     return qtrue;
508 }
509 
510 /*
511 =================
512 PC_Script_Parse
513 =================
514 */
PC_Script_Parse(int handle,const char ** out)515 qboolean PC_Script_Parse(int handle, const char **out) {
516   char script[1024];
517   pc_token_t token;
518 
519   memset(script, 0, sizeof(script));
520   // scripts start with { and have ; separated command lists.. commands are command, arg..
521   // basically we want everything between the { } as it will be interpreted at run time
522 
523   if (!trap_PC_ReadToken(handle, &token))
524     return qfalse;
525   if (Q_stricmp(token.string, "{") != 0) {
526       return qfalse;
527   }
528 
529   while ( 1 ) {
530     if (!trap_PC_ReadToken(handle, &token))
531       return qfalse;
532 
533     if (Q_stricmp(token.string, "}") == 0) {
534       *out = String_Alloc(script);
535       return qtrue;
536     }
537 
538     if (token.string[1] != '\0') {
539       Q_strcat(script, 1024, va("\"%s\"", token.string));
540     } else {
541       Q_strcat(script, 1024, token.string);
542     }
543     Q_strcat(script, 1024, " ");
544   }
545   return qfalse;  // bk001105 - LCC   missing return value
546 }
547 
548 // display, window, menu, item code
549 //
550 
551 /*
552 ==================
553 Init_Display
554 
555 Initializes the display with a structure to all the drawing routines
556 ==================
557 */
Init_Display(displayContextDef_t * dc)558 void Init_Display( displayContextDef_t *dc )
559 {
560   DC = dc;
561 }
562 
563 
564 
565 // type and style painting
566 
GradientBar_Paint(rectDef_t * rect,vec4_t color)567 void GradientBar_Paint( rectDef_t *rect, vec4_t color )
568 {
569   // gradient bar takes two paints
570   DC->setColor( color );
571   DC->drawHandlePic( rect->x, rect->y, rect->w, rect->h, DC->Assets.gradientBar );
572   DC->setColor( NULL );
573 }
574 
575 
576 /*
577 ==================
578 Window_Init
579 
580 Initializes a window structure ( windowDef_t ) with defaults
581 
582 ==================
583 */
Window_Init(Window * w)584 void Window_Init(Window *w) {
585   memset(w, 0, sizeof(windowDef_t));
586   w->borderSize = 1;
587   w->foreColor[0] = w->foreColor[1] = w->foreColor[2] = w->foreColor[3] = 1.0;
588   w->cinematic = -1;
589 }
590 
Fade(int * flags,float * f,float clamp,int * nextTime,int offsetTime,qboolean bFlags,float fadeAmount)591 void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount) {
592   if (*flags & (WINDOW_FADINGOUT | WINDOW_FADINGIN)) {
593     if (DC->realTime > *nextTime) {
594       *nextTime = DC->realTime + offsetTime;
595       if (*flags & WINDOW_FADINGOUT) {
596         *f -= fadeAmount;
597         if (bFlags && *f <= 0.0) {
598           *flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE);
599         }
600       } else {
601         *f += fadeAmount;
602         if (*f >= clamp) {
603           *f = clamp;
604           if (bFlags) {
605             *flags &= ~WINDOW_FADINGIN;
606           }
607         }
608       }
609     }
610   }
611 }
612 
613 
614 
Window_Paint(Window * w,float fadeAmount,float fadeClamp,float fadeCycle)615 void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle) {
616   //float bordersize = 0;
617   vec4_t color;
618   rectDef_t fillRect = w->rect;
619 
620 
621   if (debugMode) {
622     color[0] = color[1] = color[2] = color[3] = 1;
623     DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, 1, color);
624   }
625 
626   if (w == NULL || (w->style == 0 && w->border == 0)) {
627     return;
628   }
629 
630   if (w->border != 0) {
631     fillRect.x += w->borderSize;
632     fillRect.y += w->borderSize;
633     fillRect.w -= w->borderSize + 1;
634     fillRect.h -= w->borderSize + 1;
635   }
636 
637   if (w->style == WINDOW_STYLE_FILLED) {
638     // box, but possible a shader that needs filled
639     if (w->background) {
640       Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount);
641       DC->setColor(w->backColor);
642       DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
643       DC->setColor(NULL);
644     } else {
645       DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor);
646     }
647   } else if (w->style == WINDOW_STYLE_GRADIENT) {
648     GradientBar_Paint(&fillRect, w->backColor);
649     // gradient bar
650   } else if (w->style == WINDOW_STYLE_SHADER) {
651     if (w->flags & WINDOW_FORECOLORSET) {
652       DC->setColor(w->foreColor);
653     }
654     DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
655     DC->setColor(NULL);
656   } else if (w->style == WINDOW_STYLE_TEAMCOLOR) {
657     if (DC->getTeamColor) {
658       DC->getTeamColor(&color);
659       DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, color);
660     }
661   } else if (w->style == WINDOW_STYLE_CINEMATIC) {
662     if (w->cinematic == -1) {
663       w->cinematic = DC->playCinematic(w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
664       if (w->cinematic == -1) {
665         w->cinematic = -2;
666       }
667     }
668     if (w->cinematic >= 0) {
669       DC->runCinematicFrame(w->cinematic);
670       DC->drawCinematic(w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
671     }
672   }
673 
674   if (w->border == WINDOW_BORDER_FULL) {
675     // full
676     // HACK HACK HACK
677     if (w->style == WINDOW_STYLE_TEAMCOLOR) {
678       if (color[0] > 0) {
679         // red
680         color[0] = 1;
681         color[1] = color[2] = .5;
682 
683       } else {
684         color[2] = 1;
685         color[0] = color[1] = .5;
686       }
687       color[3] = 1;
688       DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, color);
689     } else {
690       DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor);
691     }
692   } else if (w->border == WINDOW_BORDER_HORZ) {
693     // top/bottom
694     DC->setColor(w->borderColor);
695     DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
696     DC->setColor( NULL );
697   } else if (w->border == WINDOW_BORDER_VERT) {
698     // left right
699     DC->setColor(w->borderColor);
700     DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
701     DC->setColor( NULL );
702   } else if (w->border == WINDOW_BORDER_KCGRADIENT) {
703     // this is just two gradient bars along each horz edge
704     rectDef_t r = w->rect;
705     r.h = w->borderSize;
706     GradientBar_Paint(&r, w->borderColor);
707     r.y = w->rect.y + w->rect.h - 1;
708     GradientBar_Paint(&r, w->borderColor);
709   }
710 
711 }
712 
713 
Item_SetScreenCoords(itemDef_t * item,float x,float y)714 void Item_SetScreenCoords(itemDef_t *item, float x, float y) {
715 
716   if (item == NULL) {
717     return;
718   }
719 
720   if (item->window.border != 0) {
721     x += item->window.borderSize;
722     y += item->window.borderSize;
723   }
724 
725   item->window.rect.x = x + item->window.rectClient.x;
726   item->window.rect.y = y + item->window.rectClient.y;
727   item->window.rect.w = item->window.rectClient.w;
728   item->window.rect.h = item->window.rectClient.h;
729 
730   // force the text rects to recompute
731   item->textRect.w = 0;
732   item->textRect.h = 0;
733 }
734 
735 // FIXME: consolidate this with nearby stuff
Item_UpdatePosition(itemDef_t * item)736 void Item_UpdatePosition(itemDef_t *item) {
737   float x, y;
738   menuDef_t *menu;
739 
740   if (item == NULL || item->parent == NULL) {
741     return;
742   }
743 
744   menu = item->parent;
745 
746   x = menu->window.rect.x;
747   y = menu->window.rect.y;
748 
749   if (menu->window.border != 0) {
750     x += menu->window.borderSize;
751     y += menu->window.borderSize;
752   }
753 
754   Item_SetScreenCoords(item, x, y);
755 
756 }
757 
758 // menus
Menu_UpdatePosition(menuDef_t * menu)759 void Menu_UpdatePosition(menuDef_t *menu) {
760   int i;
761   float x, y;
762 
763   if (menu == NULL) {
764     return;
765   }
766 
767   x = menu->window.rect.x;
768   y = menu->window.rect.y;
769   if (menu->window.border != 0) {
770     x += menu->window.borderSize;
771     y += menu->window.borderSize;
772   }
773 
774   for (i = 0; i < menu->itemCount; i++) {
775     Item_SetScreenCoords(menu->items[i], x, y);
776   }
777 }
778 
Menu_PostParse(menuDef_t * menu)779 void Menu_PostParse(menuDef_t *menu) {
780   if (menu == NULL) {
781     return;
782   }
783   if (menu->fullScreen) {
784     menu->window.rect.x = 0;
785     menu->window.rect.y = 0;
786     menu->window.rect.w = 640;
787     menu->window.rect.h = 480;
788   }
789   Menu_UpdatePosition(menu);
790 }
791 
Menu_ClearFocus(menuDef_t * menu)792 itemDef_t *Menu_ClearFocus(menuDef_t *menu) {
793   int i;
794   itemDef_t *ret = NULL;
795 
796   if (menu == NULL) {
797     return NULL;
798   }
799 
800   for (i = 0; i < menu->itemCount; i++) {
801     if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
802       ret = menu->items[i];
803     }
804     menu->items[i]->window.flags &= ~WINDOW_HASFOCUS;
805     if (menu->items[i]->leaveFocus) {
806       Item_RunScript(menu->items[i], menu->items[i]->leaveFocus);
807     }
808   }
809 
810   return ret;
811 }
812 
IsVisible(int flags)813 qboolean IsVisible(int flags) {
814   return (flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT));
815 }
816 
Rect_ContainsPoint(rectDef_t * rect,float x,float y)817 qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) {
818   if (rect) {
819     if (x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h) {
820       return qtrue;
821     }
822   }
823   return qfalse;
824 }
825 
Menu_ItemsMatchingGroup(menuDef_t * menu,const char * name)826 int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name) {
827   int i;
828   int count = 0;
829   for (i = 0; i < menu->itemCount; i++) {
830     if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
831       count++;
832     }
833   }
834   return count;
835 }
836 
Menu_GetMatchingItemByNumber(menuDef_t * menu,int index,const char * name)837 itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name) {
838   int i;
839   int count = 0;
840   for (i = 0; i < menu->itemCount; i++) {
841     if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
842       if (count == index) {
843         return menu->items[i];
844       }
845       count++;
846     }
847   }
848   return NULL;
849 }
850 
851 
852 
Script_SetColor(itemDef_t * item,char ** args)853 void Script_SetColor(itemDef_t *item, char **args) {
854   const char *name;
855   int i;
856   float f;
857   vec4_t *out;
858   // expecting type of color to set and 4 args for the color
859   if (String_Parse(args, &name)) {
860       out = NULL;
861       if (Q_stricmp(name, "backcolor") == 0) {
862         out = &item->window.backColor;
863         item->window.flags |= WINDOW_BACKCOLORSET;
864       } else if (Q_stricmp(name, "forecolor") == 0) {
865         out = &item->window.foreColor;
866         item->window.flags |= WINDOW_FORECOLORSET;
867       } else if (Q_stricmp(name, "bordercolor") == 0) {
868         out = &item->window.borderColor;
869       }
870 
871       if (out) {
872         for (i = 0; i < 4; i++) {
873           if (!Float_Parse(args, &f)) {
874             return;
875           }
876           (*out)[i] = f;
877         }
878       }
879   }
880 }
881 
Script_SetAsset(itemDef_t * item,char ** args)882 void Script_SetAsset(itemDef_t *item, char **args) {
883   const char *name;
884   // expecting name to set asset to
885   if (String_Parse(args, &name)) {
886     // check for a model
887     if (item->type == ITEM_TYPE_MODEL) {
888     }
889   }
890 }
891 
Script_SetBackground(itemDef_t * item,char ** args)892 void Script_SetBackground(itemDef_t *item, char **args) {
893   const char *name;
894   // expecting name to set asset to
895   if (String_Parse(args, &name)) {
896     item->window.background = DC->registerShaderNoMip(name);
897   }
898 }
899 
900 
901 
902 
Menu_FindItemByName(menuDef_t * menu,const char * p)903 itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) {
904   int i;
905   if (menu == NULL || p == NULL) {
906     return NULL;
907   }
908 
909   for (i = 0; i < menu->itemCount; i++) {
910     if (Q_stricmp(p, menu->items[i]->window.name) == 0) {
911       return menu->items[i];
912     }
913   }
914 
915   return NULL;
916 }
917 
Script_SetTeamColor(itemDef_t * item,char ** args)918 void Script_SetTeamColor(itemDef_t *item, char **args) {
919   if (DC->getTeamColor) {
920     int i;
921     vec4_t color;
922     DC->getTeamColor(&color);
923     for (i = 0; i < 4; i++) {
924       item->window.backColor[i] = color[i];
925     }
926   }
927 }
928 
Script_SetItemColor(itemDef_t * item,char ** args)929 void Script_SetItemColor(itemDef_t *item, char **args) {
930   const char *itemname;
931   const char *name;
932   vec4_t color;
933   int i;
934   vec4_t *out;
935   // expecting type of color to set and 4 args for the color
936   if (String_Parse(args, &itemname) && String_Parse(args, &name)) {
937     itemDef_t *item2;
938     int j;
939     int count = Menu_ItemsMatchingGroup(item->parent, itemname);
940 
941     if (!Color_Parse(args, &color)) {
942       return;
943     }
944 
945     for (j = 0; j < count; j++) {
946       item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname);
947       if (item2 != NULL) {
948         out = NULL;
949         if (Q_stricmp(name, "backcolor") == 0) {
950           out = &item2->window.backColor;
951         } else if (Q_stricmp(name, "forecolor") == 0) {
952           out = &item2->window.foreColor;
953           item2->window.flags |= WINDOW_FORECOLORSET;
954         } else if (Q_stricmp(name, "bordercolor") == 0) {
955           out = &item2->window.borderColor;
956         }
957 
958         if (out) {
959           for (i = 0; i < 4; i++) {
960             (*out)[i] = color[i];
961           }
962         }
963       }
964     }
965   }
966 }
967 
968 
Menu_ShowItemByName(menuDef_t * menu,const char * p,qboolean bShow)969 void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow) {
970   itemDef_t *item;
971   int i;
972   int count = Menu_ItemsMatchingGroup(menu, p);
973   for (i = 0; i < count; i++) {
974     item = Menu_GetMatchingItemByNumber(menu, i, p);
975     if (item != NULL) {
976       if (bShow) {
977         item->window.flags |= WINDOW_VISIBLE;
978       } else {
979         item->window.flags &= ~WINDOW_VISIBLE;
980         // stop cinematics playing in the window
981         if (item->window.cinematic >= 0) {
982           DC->stopCinematic(item->window.cinematic);
983           item->window.cinematic = -1;
984         }
985       }
986     }
987   }
988 }
989 
Menu_FadeItemByName(menuDef_t * menu,const char * p,qboolean fadeOut)990 void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut) {
991   itemDef_t *item;
992   int i;
993   int count = Menu_ItemsMatchingGroup(menu, p);
994   for (i = 0; i < count; i++) {
995     item = Menu_GetMatchingItemByNumber(menu, i, p);
996     if (item != NULL) {
997       if (fadeOut) {
998         item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE);
999         item->window.flags &= ~WINDOW_FADINGIN;
1000       } else {
1001         item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN);
1002         item->window.flags &= ~WINDOW_FADINGOUT;
1003       }
1004     }
1005   }
1006 }
1007 
Menus_FindByName(const char * p)1008 menuDef_t *Menus_FindByName(const char *p) {
1009   int i;
1010   for (i = 0; i < menuCount; i++) {
1011     if (Q_stricmp(Menus[i].window.name, p) == 0) {
1012       return &Menus[i];
1013     }
1014   }
1015   return NULL;
1016 }
1017 
Menus_ShowByName(const char * p)1018 void Menus_ShowByName(const char *p) {
1019   menuDef_t *menu = Menus_FindByName(p);
1020   if (menu) {
1021     Menus_Activate(menu);
1022   }
1023 }
1024 
Menus_OpenByName(const char * p)1025 void Menus_OpenByName(const char *p) {
1026   Menus_ActivateByName(p);
1027 }
1028 
Menu_RunCloseScript(menuDef_t * menu)1029 static void Menu_RunCloseScript(menuDef_t *menu) {
1030   if (menu && menu->window.flags & WINDOW_VISIBLE && menu->onClose) {
1031     itemDef_t item;
1032     item.parent = menu;
1033     Item_RunScript(&item, menu->onClose);
1034   }
1035 }
1036 
Menus_CloseByName(const char * p)1037 void Menus_CloseByName(const char *p) {
1038   menuDef_t *menu = Menus_FindByName(p);
1039   if (menu != NULL) {
1040     Menu_RunCloseScript(menu);
1041     menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS);
1042   }
1043 }
1044 
Menus_CloseAll(void)1045 void Menus_CloseAll( void ) {
1046   int i;
1047   for (i = 0; i < menuCount; i++) {
1048     Menu_RunCloseScript(&Menus[i]);
1049     Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
1050   }
1051 }
1052 
1053 
Script_Show(itemDef_t * item,char ** args)1054 void Script_Show(itemDef_t *item, char **args) {
1055   const char *name;
1056   if (String_Parse(args, &name)) {
1057     Menu_ShowItemByName(item->parent, name, qtrue);
1058   }
1059 }
1060 
Script_Hide(itemDef_t * item,char ** args)1061 void Script_Hide(itemDef_t *item, char **args) {
1062   const char *name;
1063   if (String_Parse(args, &name)) {
1064     Menu_ShowItemByName(item->parent, name, qfalse);
1065   }
1066 }
1067 
Script_FadeIn(itemDef_t * item,char ** args)1068 void Script_FadeIn(itemDef_t *item, char **args) {
1069   const char *name;
1070   if (String_Parse(args, &name)) {
1071     Menu_FadeItemByName(item->parent, name, qfalse);
1072   }
1073 }
1074 
Script_FadeOut(itemDef_t * item,char ** args)1075 void Script_FadeOut(itemDef_t *item, char **args) {
1076   const char *name;
1077   if (String_Parse(args, &name)) {
1078     Menu_FadeItemByName(item->parent, name, qtrue);
1079   }
1080 }
1081 
1082 
1083 
Script_Open(itemDef_t * item,char ** args)1084 void Script_Open(itemDef_t *item, char **args) {
1085   const char *name;
1086   if (String_Parse(args, &name)) {
1087     Menus_OpenByName(name);
1088   }
1089 }
1090 
Script_ConditionalOpen(itemDef_t * item,char ** args)1091 void Script_ConditionalOpen(itemDef_t *item, char **args) {
1092   const char *cvar;
1093   const char *name1;
1094   const char *name2;
1095   float           val;
1096 
1097   if ( String_Parse(args, &cvar) && String_Parse(args, &name1) && String_Parse(args, &name2) ) {
1098     val = DC->getCVarValue( cvar );
1099     if ( val == 0.f ) {
1100       Menus_OpenByName(name2);
1101     } else {
1102       Menus_OpenByName(name1);
1103     }
1104   }
1105 }
1106 
Script_Close(itemDef_t * item,char ** args)1107 void Script_Close(itemDef_t *item, char **args) {
1108   const char *name;
1109   if (String_Parse(args, &name)) {
1110     Menus_CloseByName(name);
1111   }
1112 }
1113 
Menu_TransitionItemByName(menuDef_t * menu,const char * p,rectDef_t rectFrom,rectDef_t rectTo,int time,float amt)1114 void Menu_TransitionItemByName(menuDef_t *menu, const char *p, rectDef_t rectFrom, rectDef_t rectTo, int time, float amt) {
1115   itemDef_t *item;
1116   int i;
1117   int count = Menu_ItemsMatchingGroup(menu, p);
1118   for (i = 0; i < count; i++) {
1119     item = Menu_GetMatchingItemByNumber(menu, i, p);
1120     if (item != NULL) {
1121       item->window.flags |= (WINDOW_INTRANSITION | WINDOW_VISIBLE);
1122       item->window.offsetTime = time;
1123       memcpy(&item->window.rectClient, &rectFrom, sizeof(rectDef_t));
1124       memcpy(&item->window.rectEffects, &rectTo, sizeof(rectDef_t));
1125       item->window.rectEffects2.x = abs(rectTo.x - rectFrom.x) / amt;
1126       item->window.rectEffects2.y = abs(rectTo.y - rectFrom.y) / amt;
1127       item->window.rectEffects2.w = abs(rectTo.w - rectFrom.w) / amt;
1128       item->window.rectEffects2.h = abs(rectTo.h - rectFrom.h) / amt;
1129       Item_UpdatePosition(item);
1130     }
1131   }
1132 }
1133 
1134 
Script_Transition(itemDef_t * item,char ** args)1135 void Script_Transition(itemDef_t *item, char **args) {
1136   const char *name;
1137   rectDef_t rectFrom, rectTo;
1138   int time;
1139   float amt;
1140 
1141   if (String_Parse(args, &name)) {
1142     if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) {
1143       Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt);
1144     }
1145   }
1146 }
1147 
1148 
Menu_OrbitItemByName(menuDef_t * menu,const char * p,float x,float y,float cx,float cy,int time)1149 void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) {
1150   itemDef_t *item;
1151   int i;
1152   int count = Menu_ItemsMatchingGroup(menu, p);
1153   for (i = 0; i < count; i++) {
1154     item = Menu_GetMatchingItemByNumber(menu, i, p);
1155     if (item != NULL) {
1156       item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE);
1157       item->window.offsetTime = time;
1158       item->window.rectEffects.x = cx;
1159       item->window.rectEffects.y = cy;
1160       item->window.rectClient.x = x;
1161       item->window.rectClient.y = y;
1162       Item_UpdatePosition(item);
1163     }
1164   }
1165 }
1166 
1167 
Script_Orbit(itemDef_t * item,char ** args)1168 void Script_Orbit(itemDef_t *item, char **args) {
1169   const char *name;
1170   float cx, cy, x, y;
1171   int time;
1172 
1173   if (String_Parse(args, &name)) {
1174     if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) {
1175       Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time);
1176     }
1177   }
1178 }
1179 
1180 
1181 
Script_SetFocus(itemDef_t * item,char ** args)1182 void Script_SetFocus(itemDef_t *item, char **args) {
1183   const char *name;
1184   itemDef_t *focusItem;
1185 
1186   if (String_Parse(args, &name)) {
1187     focusItem = Menu_FindItemByName(item->parent, name);
1188     if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION) && !(focusItem->window.flags & WINDOW_HASFOCUS)) {
1189       Menu_ClearFocus(item->parent);
1190       focusItem->window.flags |= WINDOW_HASFOCUS;
1191       if (focusItem->onFocus) {
1192         Item_RunScript(focusItem, focusItem->onFocus);
1193       }
1194       if (DC->Assets.itemFocusSound) {
1195         DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
1196       }
1197     }
1198   }
1199 }
1200 
Script_SetPlayerModel(itemDef_t * item,char ** args)1201 void Script_SetPlayerModel(itemDef_t *item, char **args) {
1202   const char *name;
1203   if (String_Parse(args, &name)) {
1204     DC->setCVar("team_model", name);
1205   }
1206 }
1207 
Script_SetPlayerHead(itemDef_t * item,char ** args)1208 void Script_SetPlayerHead(itemDef_t *item, char **args) {
1209   const char *name;
1210   if (String_Parse(args, &name)) {
1211     DC->setCVar("team_headmodel", name);
1212   }
1213 }
1214 
Script_SetCvar(itemDef_t * item,char ** args)1215 void Script_SetCvar(itemDef_t *item, char **args) {
1216   const char *cvar, *val;
1217   if (String_Parse(args, &cvar) && String_Parse(args, &val)) {
1218     DC->setCVar(cvar, val);
1219   }
1220 
1221 }
1222 
Script_Exec(itemDef_t * item,char ** args)1223 void Script_Exec(itemDef_t *item, char **args) {
1224   const char *val;
1225   if (String_Parse(args, &val)) {
1226     DC->executeText(EXEC_APPEND, va("%s ; ", val));
1227   }
1228 }
1229 
Script_Play(itemDef_t * item,char ** args)1230 void Script_Play(itemDef_t *item, char **args) {
1231   const char *val;
1232   if (String_Parse(args, &val)) {
1233     DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_LOCAL_SOUND);
1234   }
1235 }
1236 
Script_playLooped(itemDef_t * item,char ** args)1237 void Script_playLooped(itemDef_t *item, char **args) {
1238   const char *val;
1239   if (String_Parse(args, &val)) {
1240     DC->stopBackgroundTrack();
1241     DC->startBackgroundTrack(val, val);
1242   }
1243 }
1244 
1245 
1246 commandDef_t commandList[] =
1247 {
1248   {"fadein", &Script_FadeIn},                   // group/name
1249   {"fadeout", &Script_FadeOut},                 // group/name
1250   {"show", &Script_Show},                       // group/name
1251   {"hide", &Script_Hide},                       // group/name
1252   {"setcolor", &Script_SetColor},               // works on this
1253   {"open", &Script_Open},                       // menu
1254   {"conditionalopen", &Script_ConditionalOpen}, // menu
1255   {"close", &Script_Close},                     // menu
1256   {"setasset", &Script_SetAsset},               // works on this
1257   {"setbackground", &Script_SetBackground},     // works on this
1258   {"setitemcolor", &Script_SetItemColor},       // group/name
1259   {"setteamcolor", &Script_SetTeamColor},       // sets this background color to team color
1260   {"setfocus", &Script_SetFocus},               // sets this background color to team color
1261   {"setplayermodel", &Script_SetPlayerModel},   // sets this background color to team color
1262   {"setplayerhead", &Script_SetPlayerHead},     // sets this background color to team color
1263   {"transition", &Script_Transition},           // group/name
1264   {"setcvar", &Script_SetCvar},           // group/name
1265   {"exec", &Script_Exec},           // group/name
1266   {"play", &Script_Play},           // group/name
1267   {"playlooped", &Script_playLooped},           // group/name
1268   {"orbit", &Script_Orbit}                      // group/name
1269 };
1270 
1271 int scriptCommandCount = sizeof(commandList) / sizeof(commandDef_t);
1272 
1273 
Item_RunScript(itemDef_t * item,const char * s)1274 void Item_RunScript(itemDef_t *item, const char *s) {
1275   char script[1024], *p;
1276   int i;
1277   qboolean bRan;
1278   memset(script, 0, sizeof(script));
1279   if (item && s && s[0]) {
1280     Q_strcat(script, 1024, s);
1281     p = script;
1282     while (1) {
1283       const char *command;
1284       // expect command then arguments, ; ends command, NULL ends script
1285       if (!String_Parse(&p, &command)) {
1286         return;
1287       }
1288 
1289       if (command[0] == ';' && command[1] == '\0') {
1290         continue;
1291       }
1292 
1293       bRan = qfalse;
1294       for (i = 0; i < scriptCommandCount; i++) {
1295         if (Q_stricmp(command, commandList[i].name) == 0) {
1296           (commandList[i].handler(item, &p));
1297           bRan = qtrue;
1298           break;
1299         }
1300       }
1301       // not in our auto list, pass to handler
1302       if (!bRan) {
1303         DC->runScript(&p);
1304       }
1305     }
1306   }
1307 }
1308 
1309 
Item_EnableShowViaCvar(itemDef_t * item,int flag)1310 qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) {
1311   char script[1024], *p;
1312   memset(script, 0, sizeof(script));
1313   if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
1314     char buff[1024];
1315     DC->getCVarString(item->cvarTest, buff, sizeof(buff));
1316 
1317     Q_strcat(script, 1024, item->enableCvar);
1318     p = script;
1319     while (1) {
1320       const char *val;
1321       // expect value then ; or NULL, NULL ends list
1322       if (!String_Parse(&p, &val)) {
1323         return (item->cvarFlags & flag) ? qfalse : qtrue;
1324       }
1325 
1326       if (val[0] == ';' && val[1] == '\0') {
1327         continue;
1328       }
1329 
1330       // enable it if any of the values are true
1331       if (item->cvarFlags & flag) {
1332         if (Q_stricmp(buff, val) == 0) {
1333           return qtrue;
1334         }
1335       } else {
1336         // disable it if any of the values are true
1337         if (Q_stricmp(buff, val) == 0) {
1338           return qfalse;
1339         }
1340       }
1341 
1342     }
1343     return (item->cvarFlags & flag) ? qfalse : qtrue;
1344   }
1345   return qtrue;
1346 }
1347 
1348 
1349 // will optionaly set focus to this item
Item_SetFocus(itemDef_t * item,float x,float y)1350 qboolean Item_SetFocus(itemDef_t *item, float x, float y) {
1351   int i;
1352   itemDef_t *oldFocus;
1353   sfxHandle_t *sfx = &DC->Assets.itemFocusSound;
1354   qboolean playSound = qfalse;
1355   menuDef_t *parent; // bk001206: = (menuDef_t*)item->parent;
1356   // sanity check, non-null, not a decoration and does not already have the focus
1357   if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS || !(item->window.flags & WINDOW_VISIBLE)) {
1358     return qfalse;
1359   }
1360 
1361   // bk001206 - this can be NULL.
1362   parent = (menuDef_t*)item->parent;
1363 
1364   // items can be enabled and disabled based on cvars
1365   if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
1366     return qfalse;
1367   }
1368 
1369   if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
1370     return qfalse;
1371   }
1372 
1373   oldFocus = Menu_ClearFocus(item->parent);
1374 
1375   if (item->type == ITEM_TYPE_TEXT) {
1376     rectDef_t r;
1377     r = item->textRect;
1378     r.y -= r.h;
1379     if (Rect_ContainsPoint(&r, x, y)) {
1380       item->window.flags |= WINDOW_HASFOCUS;
1381       if (item->focusSound) {
1382         sfx = &item->focusSound;
1383       }
1384       playSound = qtrue;
1385     } else {
1386       if (oldFocus) {
1387         oldFocus->window.flags |= WINDOW_HASFOCUS;
1388         if (oldFocus->onFocus) {
1389           Item_RunScript(oldFocus, oldFocus->onFocus);
1390         }
1391       }
1392     }
1393   } else {
1394       item->window.flags |= WINDOW_HASFOCUS;
1395     if (item->onFocus) {
1396       Item_RunScript(item, item->onFocus);
1397     }
1398     if (item->focusSound) {
1399       sfx = &item->focusSound;
1400     }
1401     playSound = qtrue;
1402   }
1403 
1404   if (playSound && sfx) {
1405     DC->startLocalSound( *sfx, CHAN_LOCAL_SOUND );
1406   }
1407 
1408   for (i = 0; i < parent->itemCount; i++) {
1409     if (parent->items[i] == item) {
1410       parent->cursorItem = i;
1411       break;
1412     }
1413   }
1414 
1415   return qtrue;
1416 }
1417 
Item_ListBox_MaxScroll(itemDef_t * item)1418 int Item_ListBox_MaxScroll(itemDef_t *item) {
1419   listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
1420   int count = DC->feederCount(item->special);
1421   int max;
1422 
1423   if (item->window.flags & WINDOW_HORIZONTAL) {
1424     max = count - (item->window.rect.w / listPtr->elementWidth) + 1;
1425   }
1426   else {
1427     max = count - (item->window.rect.h / listPtr->elementHeight) + 1;
1428   }
1429   if (max < 0) {
1430     return 0;
1431   }
1432   return max;
1433 }
1434 
Item_ListBox_ThumbPosition(itemDef_t * item)1435 int Item_ListBox_ThumbPosition(itemDef_t *item) {
1436   float max, pos, size;
1437   listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
1438 
1439   max = Item_ListBox_MaxScroll(item);
1440   if (item->window.flags & WINDOW_HORIZONTAL) {
1441     size = item->window.rect.w - (SCROLLBAR_SIZE * 2) - 2;
1442     if (max > 0) {
1443       pos = (size-SCROLLBAR_SIZE) / (float) max;
1444     } else {
1445       pos = 0;
1446     }
1447     pos *= listPtr->startPos;
1448     return item->window.rect.x + 1 + SCROLLBAR_SIZE + pos;
1449   }
1450   else {
1451     size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2;
1452     if (max > 0) {
1453       pos = (size-SCROLLBAR_SIZE) / (float) max;
1454     } else {
1455       pos = 0;
1456     }
1457     pos *= listPtr->startPos;
1458     return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos;
1459   }
1460 }
1461 
Item_ListBox_ThumbDrawPosition(itemDef_t * item)1462 int Item_ListBox_ThumbDrawPosition(itemDef_t *item) {
1463   int min, max;
1464 
1465   if (itemCapture == item) {
1466     if (item->window.flags & WINDOW_HORIZONTAL) {
1467       min = item->window.rect.x + SCROLLBAR_SIZE + 1;
1468       max = item->window.rect.x + item->window.rect.w - 2*SCROLLBAR_SIZE - 1;
1469       if (DC->cursorx >= min + SCROLLBAR_SIZE/2 && DC->cursorx <= max + SCROLLBAR_SIZE/2) {
1470         return DC->cursorx - SCROLLBAR_SIZE/2;
1471       }
1472       else {
1473         return Item_ListBox_ThumbPosition(item);
1474       }
1475     }
1476     else {
1477       min = item->window.rect.y + SCROLLBAR_SIZE + 1;
1478       max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1;
1479       if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) {
1480         return DC->cursory - SCROLLBAR_SIZE/2;
1481       }
1482       else {
1483         return Item_ListBox_ThumbPosition(item);
1484       }
1485     }
1486   }
1487   else {
1488     return Item_ListBox_ThumbPosition(item);
1489   }
1490 }
1491 
Item_Slider_ThumbPosition(itemDef_t * item)1492 float Item_Slider_ThumbPosition(itemDef_t *item) {
1493   float value, range, x;
1494   editFieldDef_t *editDef = item->typeData;
1495 
1496   if (item->text) {
1497     x = item->textRect.x + item->textRect.w + 8;
1498   } else {
1499     x = item->window.rect.x;
1500   }
1501 
1502   if (editDef == NULL && item->cvar) {
1503     return x;
1504   }
1505 
1506   value = DC->getCVarValue(item->cvar);
1507 
1508   if (value < editDef->minVal) {
1509     value = editDef->minVal;
1510   } else if (value > editDef->maxVal) {
1511     value = editDef->maxVal;
1512   }
1513 
1514   range = editDef->maxVal - editDef->minVal;
1515   value -= editDef->minVal;
1516   value /= range;
1517   //value /= (editDef->maxVal - editDef->minVal);
1518   value *= SLIDER_WIDTH;
1519   x += value;
1520   // vm fuckage
1521   //x = x + (((float)value / editDef->maxVal) * SLIDER_WIDTH);
1522   return x;
1523 }
1524 
Item_Slider_OverSlider(itemDef_t * item,float x,float y)1525 int Item_Slider_OverSlider(itemDef_t *item, float x, float y) {
1526   rectDef_t r;
1527 
1528   r.x = Item_Slider_ThumbPosition(item) - (SLIDER_THUMB_WIDTH / 2);
1529   r.y = item->window.rect.y - 2;
1530   r.w = SLIDER_THUMB_WIDTH;
1531   r.h = SLIDER_THUMB_HEIGHT;
1532 
1533   if (Rect_ContainsPoint(&r, x, y)) {
1534     return WINDOW_LB_THUMB;
1535   }
1536   return 0;
1537 }
1538 
Item_ListBox_OverLB(itemDef_t * item,float x,float y)1539 int Item_ListBox_OverLB(itemDef_t *item, float x, float y) {
1540   rectDef_t r;
1541   listBoxDef_t *listPtr;
1542   int thumbstart;
1543   int count;
1544 
1545   count = DC->feederCount(item->special);
1546   listPtr = (listBoxDef_t*)item->typeData;
1547   if (item->window.flags & WINDOW_HORIZONTAL) {
1548     // check if on left arrow
1549     r.x = item->window.rect.x;
1550     r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
1551     r.h = r.w = SCROLLBAR_SIZE;
1552     if (Rect_ContainsPoint(&r, x, y)) {
1553       return WINDOW_LB_LEFTARROW;
1554     }
1555     // check if on right arrow
1556     r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
1557     if (Rect_ContainsPoint(&r, x, y)) {
1558       return WINDOW_LB_RIGHTARROW;
1559     }
1560     // check if on thumb
1561     thumbstart = Item_ListBox_ThumbPosition(item);
1562     r.x = thumbstart;
1563     if (Rect_ContainsPoint(&r, x, y)) {
1564       return WINDOW_LB_THUMB;
1565     }
1566     r.x = item->window.rect.x + SCROLLBAR_SIZE;
1567     r.w = thumbstart - r.x;
1568     if (Rect_ContainsPoint(&r, x, y)) {
1569       return WINDOW_LB_PGUP;
1570     }
1571     r.x = thumbstart + SCROLLBAR_SIZE;
1572     r.w = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
1573     if (Rect_ContainsPoint(&r, x, y)) {
1574       return WINDOW_LB_PGDN;
1575     }
1576   } else {
1577     r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
1578     r.y = item->window.rect.y;
1579     r.h = r.w = SCROLLBAR_SIZE;
1580     if (Rect_ContainsPoint(&r, x, y)) {
1581       return WINDOW_LB_LEFTARROW;
1582     }
1583     r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
1584     if (Rect_ContainsPoint(&r, x, y)) {
1585       return WINDOW_LB_RIGHTARROW;
1586     }
1587     thumbstart = Item_ListBox_ThumbPosition(item);
1588     r.y = thumbstart;
1589     if (Rect_ContainsPoint(&r, x, y)) {
1590       return WINDOW_LB_THUMB;
1591     }
1592     r.y = item->window.rect.y + SCROLLBAR_SIZE;
1593     r.h = thumbstart - r.y;
1594     if (Rect_ContainsPoint(&r, x, y)) {
1595       return WINDOW_LB_PGUP;
1596     }
1597     r.y = thumbstart + SCROLLBAR_SIZE;
1598     r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
1599     if (Rect_ContainsPoint(&r, x, y)) {
1600       return WINDOW_LB_PGDN;
1601     }
1602   }
1603   return 0;
1604 }
1605 
1606 
Item_ListBox_MouseEnter(itemDef_t * item,float x,float y)1607 void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y)
1608 {
1609   rectDef_t r;
1610   listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
1611 
1612   item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
1613   item->window.flags |= Item_ListBox_OverLB(item, x, y);
1614 
1615   if (item->window.flags & WINDOW_HORIZONTAL) {
1616     if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
1617       // check for selection hit as we have exausted buttons and thumb
1618       if (listPtr->elementStyle == LISTBOX_IMAGE) {
1619         r.x = item->window.rect.x;
1620         r.y = item->window.rect.y;
1621         r.h = item->window.rect.h - SCROLLBAR_SIZE;
1622         r.w = item->window.rect.w - listPtr->drawPadding;
1623         if (Rect_ContainsPoint(&r, x, y)) {
1624           listPtr->cursorPos =  (int)((x - r.x) / listPtr->elementWidth)  + listPtr->startPos;
1625           if (listPtr->cursorPos >= listPtr->endPos) {
1626             listPtr->cursorPos = listPtr->endPos;
1627           }
1628         }
1629       } else {
1630         // text hit..
1631       }
1632     }
1633   } else if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
1634     r.x = item->window.rect.x;
1635     r.y = item->window.rect.y;
1636     r.w = item->window.rect.w - SCROLLBAR_SIZE;
1637     r.h = item->window.rect.h - listPtr->drawPadding;
1638     if (Rect_ContainsPoint(&r, x, y)) {
1639       listPtr->cursorPos =  (int)((y - 2 - r.y) / listPtr->elementHeight)  + listPtr->startPos;
1640       if (listPtr->cursorPos > listPtr->endPos) {
1641         listPtr->cursorPos = listPtr->endPos;
1642       }
1643     }
1644   }
1645 }
1646 
Item_MouseEnter(itemDef_t * item,float x,float y)1647 void Item_MouseEnter(itemDef_t *item, float x, float y) {
1648   rectDef_t r;
1649   if (item) {
1650     r = item->textRect;
1651     r.y -= r.h;
1652     // in the text rect?
1653 
1654     // items can be enabled and disabled based on cvars
1655     if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
1656       return;
1657     }
1658 
1659     if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
1660       return;
1661     }
1662 
1663     if (Rect_ContainsPoint(&r, x, y)) {
1664       if (!(item->window.flags & WINDOW_MOUSEOVERTEXT)) {
1665         Item_RunScript(item, item->mouseEnterText);
1666         item->window.flags |= WINDOW_MOUSEOVERTEXT;
1667       }
1668       if (!(item->window.flags & WINDOW_MOUSEOVER)) {
1669         Item_RunScript(item, item->mouseEnter);
1670         item->window.flags |= WINDOW_MOUSEOVER;
1671       }
1672 
1673     } else {
1674       // not in the text rect
1675       if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
1676         // if we were
1677         Item_RunScript(item, item->mouseExitText);
1678         item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
1679       }
1680       if (!(item->window.flags & WINDOW_MOUSEOVER)) {
1681         Item_RunScript(item, item->mouseEnter);
1682         item->window.flags |= WINDOW_MOUSEOVER;
1683       }
1684 
1685       if (item->type == ITEM_TYPE_LISTBOX) {
1686         Item_ListBox_MouseEnter(item, x, y);
1687       }
1688     }
1689   }
1690 }
1691 
Item_MouseLeave(itemDef_t * item)1692 void Item_MouseLeave(itemDef_t *item) {
1693   if (item) {
1694     if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
1695       Item_RunScript(item, item->mouseExitText);
1696       item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
1697     }
1698     Item_RunScript(item, item->mouseExit);
1699     item->window.flags &= ~(WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW);
1700   }
1701 }
1702 
Menu_HitTest(menuDef_t * menu,float x,float y)1703 itemDef_t *Menu_HitTest(menuDef_t *menu, float x, float y) {
1704   int i;
1705   for (i = 0; i < menu->itemCount; i++) {
1706     if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
1707       return menu->items[i];
1708     }
1709   }
1710   return NULL;
1711 }
1712 
Item_SetMouseOver(itemDef_t * item,qboolean focus)1713 void Item_SetMouseOver(itemDef_t *item, qboolean focus) {
1714   if (item) {
1715     if (focus) {
1716       item->window.flags |= WINDOW_MOUSEOVER;
1717     } else {
1718       item->window.flags &= ~WINDOW_MOUSEOVER;
1719     }
1720   }
1721 }
1722 
1723 
Item_OwnerDraw_HandleKey(itemDef_t * item,int key)1724 qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) {
1725   if (item && DC->ownerDrawHandleKey) {
1726     return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key);
1727   }
1728   return qfalse;
1729 }
1730 
Item_ListBox_HandleKey(itemDef_t * item,int key,qboolean down,qboolean force)1731 qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force) {
1732   listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
1733   int count = DC->feederCount(item->special);
1734   int max, viewmax;
1735 
1736   if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) {
1737     max = Item_ListBox_MaxScroll(item);
1738     if (item->window.flags & WINDOW_HORIZONTAL) {
1739       viewmax = (item->window.rect.w / listPtr->elementWidth);
1740       if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
1741       {
1742         if (!listPtr->notselectable) {
1743           listPtr->cursorPos--;
1744           if (listPtr->cursorPos < 0) {
1745             listPtr->cursorPos = 0;
1746           }
1747           if (listPtr->cursorPos < listPtr->startPos) {
1748             listPtr->startPos = listPtr->cursorPos;
1749           }
1750           if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
1751             listPtr->startPos = listPtr->cursorPos - viewmax + 1;
1752           }
1753           item->cursorPos = listPtr->cursorPos;
1754           DC->feederSelection(item->special, item->cursorPos);
1755         }
1756         else {
1757           listPtr->startPos--;
1758           if (listPtr->startPos < 0)
1759             listPtr->startPos = 0;
1760         }
1761         return qtrue;
1762       }
1763       if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
1764       {
1765         if (!listPtr->notselectable) {
1766           listPtr->cursorPos++;
1767           if (listPtr->cursorPos < listPtr->startPos) {
1768             listPtr->startPos = listPtr->cursorPos;
1769           }
1770           if (listPtr->cursorPos >= count) {
1771             listPtr->cursorPos = count-1;
1772           }
1773           if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
1774             listPtr->startPos = listPtr->cursorPos - viewmax + 1;
1775           }
1776           item->cursorPos = listPtr->cursorPos;
1777           DC->feederSelection(item->special, item->cursorPos);
1778         }
1779         else {
1780           listPtr->startPos++;
1781           if (listPtr->startPos >= count)
1782             listPtr->startPos = count-1;
1783         }
1784         return qtrue;
1785       }
1786     }
1787     else {
1788       viewmax = (item->window.rect.h / listPtr->elementHeight);
1789       if ( key == K_UPARROW || key == K_KP_UPARROW )
1790       {
1791         if (!listPtr->notselectable) {
1792           listPtr->cursorPos--;
1793           if (listPtr->cursorPos < 0) {
1794             listPtr->cursorPos = 0;
1795           }
1796           if (listPtr->cursorPos < listPtr->startPos) {
1797             listPtr->startPos = listPtr->cursorPos;
1798           }
1799           if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
1800             listPtr->startPos = listPtr->cursorPos - viewmax + 1;
1801           }
1802           item->cursorPos = listPtr->cursorPos;
1803           DC->feederSelection(item->special, item->cursorPos);
1804         }
1805         else {
1806           listPtr->startPos--;
1807           if (listPtr->startPos < 0)
1808             listPtr->startPos = 0;
1809         }
1810         return qtrue;
1811       }
1812       if ( key == K_DOWNARROW || key == K_KP_DOWNARROW )
1813       {
1814         if (!listPtr->notselectable) {
1815           listPtr->cursorPos++;
1816           if (listPtr->cursorPos < listPtr->startPos) {
1817             listPtr->startPos = listPtr->cursorPos;
1818           }
1819           if (listPtr->cursorPos >= count) {
1820             listPtr->cursorPos = count-1;
1821           }
1822           if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
1823             listPtr->startPos = listPtr->cursorPos - viewmax + 1;
1824           }
1825           item->cursorPos = listPtr->cursorPos;
1826           DC->feederSelection(item->special, item->cursorPos);
1827         }
1828         else {
1829           listPtr->startPos++;
1830           if (listPtr->startPos > max)
1831             listPtr->startPos = max;
1832         }
1833         return qtrue;
1834       }
1835     }
1836     // mouse hit
1837     if (key == K_MOUSE1 || key == K_MOUSE2) {
1838       if (item->window.flags & WINDOW_LB_LEFTARROW) {
1839         listPtr->startPos--;
1840         if (listPtr->startPos < 0) {
1841           listPtr->startPos = 0;
1842         }
1843       } else if (item->window.flags & WINDOW_LB_RIGHTARROW) {
1844         // one down
1845         listPtr->startPos++;
1846         if (listPtr->startPos > max) {
1847           listPtr->startPos = max;
1848         }
1849       } else if (item->window.flags & WINDOW_LB_PGUP) {
1850         // page up
1851         listPtr->startPos -= viewmax;
1852         if (listPtr->startPos < 0) {
1853           listPtr->startPos = 0;
1854         }
1855       } else if (item->window.flags & WINDOW_LB_PGDN) {
1856         // page down
1857         listPtr->startPos += viewmax;
1858         if (listPtr->startPos > max) {
1859           listPtr->startPos = max;
1860         }
1861       } else if (item->window.flags & WINDOW_LB_THUMB) {
1862         // Display_SetCaptureItem(item);
1863       } else {
1864         // select an item
1865         if (DC->realTime < lastListBoxClickTime && listPtr->doubleClick) {
1866           Item_RunScript(item, listPtr->doubleClick);
1867         }
1868         lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
1869         if (item->cursorPos != listPtr->cursorPos) {
1870           item->cursorPos = listPtr->cursorPos;
1871           DC->feederSelection(item->special, item->cursorPos);
1872         }
1873       }
1874       return qtrue;
1875     }
1876 
1877     //TA: invoke the doubleClick handler when enter is pressed
1878     if( key == K_ENTER )
1879     {
1880       if( listPtr->doubleClick )
1881         Item_RunScript( item, listPtr->doubleClick );
1882 
1883       return qtrue;
1884     }
1885 
1886     if ( key == K_HOME || key == K_KP_HOME) {
1887       // home
1888       listPtr->startPos = 0;
1889       return qtrue;
1890     }
1891     if ( key == K_END || key == K_KP_END) {
1892       // end
1893       listPtr->startPos = max;
1894       return qtrue;
1895     }
1896     if (key == K_PGUP || key == K_KP_PGUP ) {
1897       // page up
1898       if (!listPtr->notselectable) {
1899         listPtr->cursorPos -= viewmax;
1900         if (listPtr->cursorPos < 0) {
1901           listPtr->cursorPos = 0;
1902         }
1903         if (listPtr->cursorPos < listPtr->startPos) {
1904           listPtr->startPos = listPtr->cursorPos;
1905         }
1906         if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
1907           listPtr->startPos = listPtr->cursorPos - viewmax + 1;
1908         }
1909         item->cursorPos = listPtr->cursorPos;
1910         DC->feederSelection(item->special, item->cursorPos);
1911       }
1912       else {
1913         listPtr->startPos -= viewmax;
1914         if (listPtr->startPos < 0) {
1915           listPtr->startPos = 0;
1916         }
1917       }
1918       return qtrue;
1919     }
1920     if ( key == K_PGDN || key == K_KP_PGDN ) {
1921       // page down
1922       if (!listPtr->notselectable) {
1923         listPtr->cursorPos += viewmax;
1924         if (listPtr->cursorPos < listPtr->startPos) {
1925           listPtr->startPos = listPtr->cursorPos;
1926         }
1927         if (listPtr->cursorPos >= count) {
1928           listPtr->cursorPos = count-1;
1929         }
1930         if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
1931           listPtr->startPos = listPtr->cursorPos - viewmax + 1;
1932         }
1933         item->cursorPos = listPtr->cursorPos;
1934         DC->feederSelection(item->special, item->cursorPos);
1935       }
1936       else {
1937         listPtr->startPos += viewmax;
1938         if (listPtr->startPos > max) {
1939           listPtr->startPos = max;
1940         }
1941       }
1942       return qtrue;
1943     }
1944   }
1945   return qfalse;
1946 }
1947 
Item_YesNo_HandleKey(itemDef_t * item,int key)1948 qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) {
1949 
1950   if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
1951     if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
1952       DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar)));
1953       return qtrue;
1954     }
1955   }
1956 
1957   return qfalse;
1958 
1959 }
1960 
Item_Multi_CountSettings(itemDef_t * item)1961 int Item_Multi_CountSettings(itemDef_t *item) {
1962   multiDef_t *multiPtr = (multiDef_t*)item->typeData;
1963   if (multiPtr == NULL) {
1964     return 0;
1965   }
1966   return multiPtr->count;
1967 }
1968 
Item_Multi_FindCvarByValue(itemDef_t * item)1969 int Item_Multi_FindCvarByValue(itemDef_t *item) {
1970   char buff[1024];
1971   float value = 0;
1972   int i;
1973   multiDef_t *multiPtr = (multiDef_t*)item->typeData;
1974   if (multiPtr) {
1975     if (multiPtr->strDef) {
1976       DC->getCVarString(item->cvar, buff, sizeof(buff));
1977     } else {
1978       value = DC->getCVarValue(item->cvar);
1979     }
1980     for (i = 0; i < multiPtr->count; i++) {
1981       if (multiPtr->strDef) {
1982         if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
1983           return i;
1984         }
1985       } else {
1986         if (multiPtr->cvarValue[i] == value) {
1987           return i;
1988         }
1989       }
1990     }
1991   }
1992   return 0;
1993 }
1994 
Item_Multi_Setting(itemDef_t * item)1995 const char *Item_Multi_Setting(itemDef_t *item) {
1996   char buff[1024];
1997   float value = 0;
1998   int i;
1999   multiDef_t *multiPtr = (multiDef_t*)item->typeData;
2000   if (multiPtr) {
2001     if (multiPtr->strDef) {
2002       DC->getCVarString(item->cvar, buff, sizeof(buff));
2003     } else {
2004       value = DC->getCVarValue(item->cvar);
2005     }
2006     for (i = 0; i < multiPtr->count; i++) {
2007       if (multiPtr->strDef) {
2008         if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
2009           return multiPtr->cvarList[i];
2010         }
2011       } else {
2012         if (multiPtr->cvarValue[i] == value) {
2013           return multiPtr->cvarList[i];
2014         }
2015       }
2016     }
2017   }
2018   return "";
2019 }
2020 
Item_Multi_HandleKey(itemDef_t * item,int key)2021 qboolean Item_Multi_HandleKey(itemDef_t *item, int key) {
2022   multiDef_t *multiPtr = (multiDef_t*)item->typeData;
2023   if (multiPtr) {
2024     if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
2025       if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
2026         int current = Item_Multi_FindCvarByValue(item) + 1;
2027         int max = Item_Multi_CountSettings(item);
2028         if ( current < 0 || current >= max ) {
2029           current = 0;
2030         }
2031         if (multiPtr->strDef) {
2032           DC->setCVar(item->cvar, multiPtr->cvarStr[current]);
2033         } else {
2034           float value = multiPtr->cvarValue[current];
2035           if (((float)((int) value)) == value) {
2036             DC->setCVar(item->cvar, va("%i", (int) value ));
2037           }
2038           else {
2039             DC->setCVar(item->cvar, va("%f", value ));
2040           }
2041         }
2042         return qtrue;
2043       }
2044     }
2045   }
2046   return qfalse;
2047 }
2048 
Item_TextField_HandleKey(itemDef_t * item,int key)2049 qboolean Item_TextField_HandleKey(itemDef_t *item, int key) {
2050   char buff[1024];
2051   int len;
2052   itemDef_t *newItem = NULL;
2053   editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
2054 
2055   if (item->cvar) {
2056 
2057     memset(buff, 0, sizeof(buff));
2058     DC->getCVarString(item->cvar, buff, sizeof(buff));
2059     len = strlen(buff);
2060     if (editPtr->maxChars && len > editPtr->maxChars) {
2061       len = editPtr->maxChars;
2062     }
2063     if ( key & K_CHAR_FLAG ) {
2064       key &= ~K_CHAR_FLAG;
2065 
2066 
2067       if (key == 'h' - 'a' + 1 )  { // ctrl-h is backspace
2068         if ( item->cursorPos > 0 ) {
2069           memmove( &buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
2070           item->cursorPos--;
2071           if (item->cursorPos < editPtr->paintOffset) {
2072             editPtr->paintOffset--;
2073           }
2074         }
2075         DC->setCVar(item->cvar, buff);
2076           return qtrue;
2077       }
2078 
2079 
2080       //
2081       // ignore any non printable chars
2082       //
2083       if ( key < 32 || !item->cvar) {
2084           return qtrue;
2085         }
2086 
2087       if (item->type == ITEM_TYPE_NUMERICFIELD) {
2088         if (key < '0' || key > '9') {
2089           return qfalse;
2090         }
2091       }
2092 
2093       if (!DC->getOverstrikeMode()) {
2094         if (( len == MAX_EDITFIELD - 1 ) || (editPtr->maxChars && len >= editPtr->maxChars)) {
2095           return qtrue;
2096         }
2097         memmove( &buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos );
2098       } else {
2099         if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars) {
2100           return qtrue;
2101         }
2102       }
2103 
2104       buff[item->cursorPos] = key;
2105 
2106       DC->setCVar(item->cvar, buff);
2107 
2108       if (item->cursorPos < len + 1) {
2109         item->cursorPos++;
2110         if (editPtr->maxPaintChars && item->cursorPos > editPtr->maxPaintChars) {
2111           editPtr->paintOffset++;
2112         }
2113       }
2114 
2115     } else {
2116 
2117       if ( key == K_DEL || key == K_KP_DEL ) {
2118         if ( item->cursorPos < len ) {
2119           memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos);
2120           DC->setCVar(item->cvar, buff);
2121         }
2122         return qtrue;
2123       }
2124 
2125       if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
2126       {
2127         if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) {
2128           item->cursorPos++;
2129           editPtr->paintOffset++;
2130           return qtrue;
2131         }
2132         if (item->cursorPos < len) {
2133           item->cursorPos++;
2134         }
2135         return qtrue;
2136       }
2137 
2138       if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
2139       {
2140         if ( item->cursorPos > 0 ) {
2141           item->cursorPos--;
2142         }
2143         if (item->cursorPos < editPtr->paintOffset) {
2144           editPtr->paintOffset--;
2145         }
2146         return qtrue;
2147       }
2148 
2149       if ( key == K_HOME || key == K_KP_HOME) {// || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
2150         item->cursorPos = 0;
2151         editPtr->paintOffset = 0;
2152         return qtrue;
2153       }
2154 
2155       if ( key == K_END || key == K_KP_END)  {// ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
2156         item->cursorPos = len;
2157         if(item->cursorPos > editPtr->maxPaintChars) {
2158           editPtr->paintOffset = len - editPtr->maxPaintChars;
2159         }
2160         return qtrue;
2161       }
2162 
2163       if ( key == K_INS || key == K_KP_INS ) {
2164         DC->setOverstrikeMode(!DC->getOverstrikeMode());
2165         return qtrue;
2166       }
2167     }
2168 
2169     if (key == K_TAB || key == K_DOWNARROW || key == K_KP_DOWNARROW) {
2170       newItem = Menu_SetNextCursorItem(item->parent);
2171       if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
2172         g_editItem = newItem;
2173       }
2174     }
2175 
2176     if (key == K_UPARROW || key == K_KP_UPARROW) {
2177       newItem = Menu_SetPrevCursorItem(item->parent);
2178       if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
2179         g_editItem = newItem;
2180       }
2181     }
2182 
2183     if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE)  {
2184       return qfalse;
2185     }
2186 
2187     return qtrue;
2188   }
2189   return qfalse;
2190 
2191 }
2192 
Scroll_ListBox_AutoFunc(void * p)2193 static void Scroll_ListBox_AutoFunc(void *p) {
2194   scrollInfo_t *si = (scrollInfo_t*)p;
2195   if (DC->realTime > si->nextScrollTime) {
2196     // need to scroll which is done by simulating a click to the item
2197     // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
2198     // so it calls it directly
2199     Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
2200     si->nextScrollTime = DC->realTime + si->adjustValue;
2201   }
2202 
2203   if (DC->realTime > si->nextAdjustTime) {
2204     si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
2205     if (si->adjustValue > SCROLL_TIME_FLOOR) {
2206       si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
2207     }
2208   }
2209 }
2210 
Scroll_ListBox_ThumbFunc(void * p)2211 static void Scroll_ListBox_ThumbFunc(void *p) {
2212   scrollInfo_t *si = (scrollInfo_t*)p;
2213   rectDef_t r;
2214   int pos, max;
2215 
2216   listBoxDef_t *listPtr = (listBoxDef_t*)si->item->typeData;
2217   if (si->item->window.flags & WINDOW_HORIZONTAL) {
2218     if (DC->cursorx == si->xStart) {
2219       return;
2220     }
2221     r.x = si->item->window.rect.x + SCROLLBAR_SIZE + 1;
2222     r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_SIZE - 1;
2223     r.h = SCROLLBAR_SIZE;
2224     r.w = si->item->window.rect.w - (SCROLLBAR_SIZE*2) - 2;
2225     max = Item_ListBox_MaxScroll(si->item);
2226     //
2227     pos = (DC->cursorx - r.x - SCROLLBAR_SIZE/2) * max / (r.w - SCROLLBAR_SIZE);
2228     if (pos < 0) {
2229       pos = 0;
2230     }
2231     else if (pos > max) {
2232       pos = max;
2233     }
2234     listPtr->startPos = pos;
2235     si->xStart = DC->cursorx;
2236   }
2237   else if (DC->cursory != si->yStart) {
2238 
2239     r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1;
2240     r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1;
2241     r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2;
2242     r.w = SCROLLBAR_SIZE;
2243     max = Item_ListBox_MaxScroll(si->item);
2244     //
2245     pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE);
2246     if (pos < 0) {
2247       pos = 0;
2248     }
2249     else if (pos > max) {
2250       pos = max;
2251     }
2252     listPtr->startPos = pos;
2253     si->yStart = DC->cursory;
2254   }
2255 
2256   if (DC->realTime > si->nextScrollTime) {
2257     // need to scroll which is done by simulating a click to the item
2258     // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
2259     // so it calls it directly
2260     Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
2261     si->nextScrollTime = DC->realTime + si->adjustValue;
2262   }
2263 
2264   if (DC->realTime > si->nextAdjustTime) {
2265     si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
2266     if (si->adjustValue > SCROLL_TIME_FLOOR) {
2267       si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
2268     }
2269   }
2270 }
2271 
Scroll_Slider_ThumbFunc(void * p)2272 static void Scroll_Slider_ThumbFunc(void *p) {
2273   float x, value, cursorx;
2274   scrollInfo_t *si = (scrollInfo_t*)p;
2275   editFieldDef_t *editDef = si->item->typeData;
2276 
2277   if (si->item->text) {
2278     x = si->item->textRect.x + si->item->textRect.w + 8;
2279   } else {
2280     x = si->item->window.rect.x;
2281   }
2282 
2283   cursorx = DC->cursorx;
2284 
2285   if (cursorx < x) {
2286     cursorx = x;
2287   } else if (cursorx > x + SLIDER_WIDTH) {
2288     cursorx = x + SLIDER_WIDTH;
2289   }
2290   value = cursorx - x;
2291   value /= SLIDER_WIDTH;
2292   value *= (editDef->maxVal - editDef->minVal);
2293   value += editDef->minVal;
2294   DC->setCVar(si->item->cvar, va("%f", value));
2295 }
2296 
Item_StartCapture(itemDef_t * item,int key)2297 void Item_StartCapture(itemDef_t *item, int key) {
2298   int flags;
2299   switch (item->type) {
2300     case ITEM_TYPE_EDITFIELD:
2301     case ITEM_TYPE_NUMERICFIELD:
2302 
2303     case ITEM_TYPE_LISTBOX:
2304     {
2305       flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory);
2306       if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) {
2307         scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
2308         scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
2309         scrollInfo.adjustValue = SCROLL_TIME_START;
2310         scrollInfo.scrollKey = key;
2311         scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse;
2312         scrollInfo.item = item;
2313         captureData = &scrollInfo;
2314         captureFunc = &Scroll_ListBox_AutoFunc;
2315         itemCapture = item;
2316       } else if (flags & WINDOW_LB_THUMB) {
2317         scrollInfo.scrollKey = key;
2318         scrollInfo.item = item;
2319         scrollInfo.xStart = DC->cursorx;
2320         scrollInfo.yStart = DC->cursory;
2321         captureData = &scrollInfo;
2322         captureFunc = &Scroll_ListBox_ThumbFunc;
2323         itemCapture = item;
2324       }
2325       break;
2326     }
2327     case ITEM_TYPE_SLIDER:
2328     {
2329       flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory);
2330       if (flags & WINDOW_LB_THUMB) {
2331         scrollInfo.scrollKey = key;
2332         scrollInfo.item = item;
2333         scrollInfo.xStart = DC->cursorx;
2334         scrollInfo.yStart = DC->cursory;
2335         captureData = &scrollInfo;
2336         captureFunc = &Scroll_Slider_ThumbFunc;
2337         itemCapture = item;
2338       }
2339       break;
2340     }
2341   }
2342 }
2343 
Item_StopCapture(itemDef_t * item)2344 void Item_StopCapture(itemDef_t *item) {
2345 
2346 }
2347 
Item_Slider_HandleKey(itemDef_t * item,int key,qboolean down)2348 qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) {
2349   float x, value, width, work;
2350 
2351   //DC->Print("slider handle key\n");
2352   if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
2353     if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
2354       editFieldDef_t *editDef = item->typeData;
2355       if (editDef) {
2356         rectDef_t testRect;
2357         width = SLIDER_WIDTH;
2358         if (item->text) {
2359           x = item->textRect.x + item->textRect.w + 8;
2360         } else {
2361           x = item->window.rect.x;
2362         }
2363 
2364         testRect = item->window.rect;
2365         testRect.x = x;
2366         value = (float)SLIDER_THUMB_WIDTH / 2;
2367         testRect.x -= value;
2368         //DC->Print("slider x: %f\n", testRect.x);
2369         testRect.w = (SLIDER_WIDTH + (float)SLIDER_THUMB_WIDTH / 2);
2370         //DC->Print("slider w: %f\n", testRect.w);
2371         if (Rect_ContainsPoint(&testRect, DC->cursorx, DC->cursory)) {
2372           work = DC->cursorx - x;
2373           value = work / width;
2374           value *= (editDef->maxVal - editDef->minVal);
2375           // vm fuckage
2376           // value = (((float)(DC->cursorx - x)/ SLIDER_WIDTH) * (editDef->maxVal - editDef->minVal));
2377           value += editDef->minVal;
2378           DC->setCVar(item->cvar, va("%f", value));
2379           return qtrue;
2380         }
2381       }
2382     }
2383   }
2384   DC->Print("slider handle key exit\n");
2385   return qfalse;
2386 }
2387 
2388 
Item_HandleKey(itemDef_t * item,int key,qboolean down)2389 qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) {
2390 
2391   if (itemCapture) {
2392     Item_StopCapture(itemCapture);
2393     itemCapture = NULL;
2394     captureFunc = voidFunction;
2395     captureData = NULL;
2396   } else {
2397     // bk001206 - parentheses
2398     if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
2399       Item_StartCapture(item, key);
2400     }
2401   }
2402 
2403   if (!down) {
2404     return qfalse;
2405   }
2406 
2407   switch (item->type) {
2408     case ITEM_TYPE_BUTTON:
2409       return qfalse;
2410       break;
2411     case ITEM_TYPE_RADIOBUTTON:
2412       return qfalse;
2413       break;
2414     case ITEM_TYPE_CHECKBOX:
2415       return qfalse;
2416       break;
2417     case ITEM_TYPE_EDITFIELD:
2418     case ITEM_TYPE_NUMERICFIELD:
2419       //return Item_TextField_HandleKey(item, key);
2420       return qfalse;
2421       break;
2422     case ITEM_TYPE_COMBO:
2423       return qfalse;
2424       break;
2425     case ITEM_TYPE_LISTBOX:
2426       return Item_ListBox_HandleKey(item, key, down, qfalse);
2427       break;
2428     case ITEM_TYPE_YESNO:
2429       return Item_YesNo_HandleKey(item, key);
2430       break;
2431     case ITEM_TYPE_MULTI:
2432       return Item_Multi_HandleKey(item, key);
2433       break;
2434     case ITEM_TYPE_OWNERDRAW:
2435       return Item_OwnerDraw_HandleKey(item, key);
2436       break;
2437     case ITEM_TYPE_BIND:
2438       return Item_Bind_HandleKey(item, key, down);
2439       break;
2440     case ITEM_TYPE_SLIDER:
2441       return Item_Slider_HandleKey(item, key, down);
2442       break;
2443     //case ITEM_TYPE_IMAGE:
2444     //  Item_Image_Paint(item);
2445     //  break;
2446     default:
2447       return qfalse;
2448       break;
2449   }
2450 
2451   //return qfalse;
2452 }
2453 
Item_Action(itemDef_t * item)2454 void Item_Action(itemDef_t *item) {
2455   if (item) {
2456     Item_RunScript(item, item->action);
2457   }
2458 }
2459 
Menu_SetPrevCursorItem(menuDef_t * menu)2460 itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu) {
2461   qboolean wrapped = qfalse;
2462   int oldCursor = menu->cursorItem;
2463 
2464   if (menu->cursorItem < 0) {
2465     menu->cursorItem = menu->itemCount-1;
2466     wrapped = qtrue;
2467   }
2468 
2469   while (menu->cursorItem > -1) {
2470 
2471     menu->cursorItem--;
2472     if (menu->cursorItem < 0 && !wrapped) {
2473       wrapped = qtrue;
2474       menu->cursorItem = menu->itemCount -1;
2475     }
2476 
2477     if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
2478       Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
2479       return menu->items[menu->cursorItem];
2480     }
2481   }
2482   menu->cursorItem = oldCursor;
2483   return NULL;
2484 
2485 }
2486 
Menu_SetNextCursorItem(menuDef_t * menu)2487 itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu) {
2488 
2489   qboolean wrapped = qfalse;
2490   int oldCursor = menu->cursorItem;
2491 
2492 
2493   if (menu->cursorItem == -1) {
2494     menu->cursorItem = 0;
2495     wrapped = qtrue;
2496   }
2497 
2498   while (menu->cursorItem < menu->itemCount) {
2499 
2500     menu->cursorItem++;
2501     if (menu->cursorItem >= menu->itemCount && !wrapped) {
2502       wrapped = qtrue;
2503       menu->cursorItem = 0;
2504     }
2505     if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
2506       Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
2507       return menu->items[menu->cursorItem];
2508     }
2509 
2510   }
2511 
2512   menu->cursorItem = oldCursor;
2513   return NULL;
2514 }
2515 
Window_CloseCinematic(windowDef_t * window)2516 static void Window_CloseCinematic(windowDef_t *window) {
2517   if (window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0) {
2518     DC->stopCinematic(window->cinematic);
2519     window->cinematic = -1;
2520   }
2521 }
2522 
Menu_CloseCinematics(menuDef_t * menu)2523 static void Menu_CloseCinematics(menuDef_t *menu) {
2524   if (menu) {
2525     int i;
2526     Window_CloseCinematic(&menu->window);
2527     for (i = 0; i < menu->itemCount; i++) {
2528       Window_CloseCinematic(&menu->items[i]->window);
2529       if (menu->items[i]->type == ITEM_TYPE_OWNERDRAW) {
2530         DC->stopCinematic(0-menu->items[i]->window.ownerDraw);
2531       }
2532     }
2533   }
2534 }
2535 
Display_CloseCinematics(void)2536 static void Display_CloseCinematics( void ) {
2537   int i;
2538   for (i = 0; i < menuCount; i++) {
2539     Menu_CloseCinematics(&Menus[i]);
2540   }
2541 }
2542 
Menus_Activate(menuDef_t * menu)2543 void  Menus_Activate(menuDef_t *menu) {
2544   menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
2545   if (menu->onOpen) {
2546     itemDef_t item;
2547     item.parent = menu;
2548     Item_RunScript(&item, menu->onOpen);
2549   }
2550 
2551   if (menu->soundName && *menu->soundName) {
2552 //    DC->stopBackgroundTrack();          // you don't want to do this since it will reset s_rawend
2553     DC->startBackgroundTrack(menu->soundName, menu->soundName);
2554   }
2555 
2556   Display_CloseCinematics();
2557 
2558 }
2559 
Display_VisibleMenuCount(void)2560 int Display_VisibleMenuCount( void ) {
2561   int i, count;
2562   count = 0;
2563   for (i = 0; i < menuCount; i++) {
2564     if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE)) {
2565       count++;
2566     }
2567   }
2568   return count;
2569 }
2570 
Menus_HandleOOBClick(menuDef_t * menu,int key,qboolean down)2571 void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down) {
2572   if (menu) {
2573     int i;
2574     // basically the behaviour we are looking for is if there are windows in the stack.. see if
2575     // the cursor is within any of them.. if not close them otherwise activate them and pass the
2576     // key on.. force a mouse move to activate focus and script stuff
2577     if (down && menu->window.flags & WINDOW_OOB_CLICK) {
2578       Menu_RunCloseScript(menu);
2579       menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
2580     }
2581 
2582     for (i = 0; i < menuCount; i++) {
2583       if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory)) {
2584         Menu_RunCloseScript(menu);
2585         menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
2586         Menus_Activate(&Menus[i]);
2587         Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory);
2588         Menu_HandleKey(&Menus[i], key, down);
2589       }
2590     }
2591 
2592     if (Display_VisibleMenuCount() == 0) {
2593       if (DC->Pause) {
2594         DC->Pause(qfalse);
2595       }
2596     }
2597     Display_CloseCinematics();
2598   }
2599 }
2600 
Item_CorrectedTextRect(itemDef_t * item)2601 static rectDef_t *Item_CorrectedTextRect(itemDef_t *item) {
2602   static rectDef_t rect;
2603   memset(&rect, 0, sizeof(rectDef_t));
2604   if (item) {
2605     rect = item->textRect;
2606     if (rect.w) {
2607       rect.y -= rect.h;
2608     }
2609   }
2610   return &rect;
2611 }
2612 
Menu_HandleKey(menuDef_t * menu,int key,qboolean down)2613 void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) {
2614   int i;
2615   itemDef_t *item = NULL;
2616   qboolean inHandler = qfalse;
2617 
2618   if (inHandler) {
2619     return;
2620   }
2621 
2622   inHandler = qtrue;
2623   if (g_waitingForKey && down) {
2624     Item_Bind_HandleKey(g_bindItem, key, down);
2625     inHandler = qfalse;
2626     return;
2627   }
2628 
2629   if (g_editingField && down) {
2630     if (!Item_TextField_HandleKey(g_editItem, key)) {
2631       g_editingField = qfalse;
2632       g_editItem = NULL;
2633       inHandler = qfalse;
2634       return;
2635     } else if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) {
2636       g_editingField = qfalse;
2637       g_editItem = NULL;
2638       Display_MouseMove(NULL, DC->cursorx, DC->cursory);
2639     } else if (key == K_TAB || key == K_UPARROW || key == K_DOWNARROW) {
2640       return;
2641     }
2642   }
2643 
2644   if (menu == NULL) {
2645     inHandler = qfalse;
2646     return;
2647   }
2648 
2649     // see if the mouse is within the window bounds and if so is this a mouse click
2650   if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) {
2651     static qboolean inHandleKey = qfalse;
2652     // bk001206 - parentheses
2653     if (!inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
2654       inHandleKey = qtrue;
2655       Menus_HandleOOBClick(menu, key, down);
2656       inHandleKey = qfalse;
2657       inHandler = qfalse;
2658       return;
2659     }
2660   }
2661 
2662   // get the item with focus
2663   for (i = 0; i < menu->itemCount; i++) {
2664     if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
2665       item = menu->items[i];
2666     }
2667   }
2668 
2669   if (item != NULL) {
2670     if (Item_HandleKey(item, key, down)) {
2671       Item_Action(item);
2672       inHandler = qfalse;
2673       return;
2674     }
2675   }
2676 
2677   if (!down) {
2678     inHandler = qfalse;
2679     return;
2680   }
2681 
2682   // default handling
2683   switch ( key ) {
2684 
2685     case K_F11:
2686       if (DC->getCVarValue("developer")) {
2687         debugMode ^= 1;
2688       }
2689       break;
2690 
2691     case K_F12:
2692       if (DC->getCVarValue("developer")) {
2693         DC->executeText(EXEC_APPEND, "screenshot\n");
2694       }
2695       break;
2696     case K_KP_UPARROW:
2697     case K_UPARROW:
2698       Menu_SetPrevCursorItem(menu);
2699       break;
2700 
2701     case K_ESCAPE:
2702       if (!g_waitingForKey && menu->onESC) {
2703         itemDef_t it;
2704         it.parent = menu;
2705         Item_RunScript(&it, menu->onESC);
2706       }
2707       break;
2708     case K_TAB:
2709     case K_KP_DOWNARROW:
2710     case K_DOWNARROW:
2711       Menu_SetNextCursorItem(menu);
2712       break;
2713 
2714     case K_MOUSE1:
2715     case K_MOUSE2:
2716       if (item) {
2717         if (item->type == ITEM_TYPE_TEXT) {
2718           if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory)) {
2719             Item_Action(item);
2720           }
2721         } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
2722           if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
2723             item->cursorPos = 0;
2724             g_editingField = qtrue;
2725             g_editItem = item;
2726             DC->setOverstrikeMode(qtrue);
2727           }
2728         } else {
2729           if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
2730             Item_Action(item);
2731           }
2732         }
2733       }
2734       break;
2735 
2736     case K_JOY1:
2737     case K_JOY2:
2738     case K_JOY3:
2739     case K_JOY4:
2740     case K_AUX1:
2741     case K_AUX2:
2742     case K_AUX3:
2743     case K_AUX4:
2744     case K_AUX5:
2745     case K_AUX6:
2746     case K_AUX7:
2747     case K_AUX8:
2748     case K_AUX9:
2749     case K_AUX10:
2750     case K_AUX11:
2751     case K_AUX12:
2752     case K_AUX13:
2753     case K_AUX14:
2754     case K_AUX15:
2755     case K_AUX16:
2756       break;
2757     case K_KP_ENTER:
2758     case K_ENTER:
2759       if (item) {
2760         if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
2761           item->cursorPos = 0;
2762           g_editingField = qtrue;
2763           g_editItem = item;
2764           DC->setOverstrikeMode(qtrue);
2765         } else {
2766             Item_Action(item);
2767         }
2768       }
2769       break;
2770   }
2771   inHandler = qfalse;
2772 }
2773 
ToWindowCoords(float * x,float * y,windowDef_t * window)2774 void ToWindowCoords(float *x, float *y, windowDef_t *window) {
2775   if (window->border != 0) {
2776     *x += window->borderSize;
2777     *y += window->borderSize;
2778   }
2779   *x += window->rect.x;
2780   *y += window->rect.y;
2781 }
2782 
Rect_ToWindowCoords(rectDef_t * rect,windowDef_t * window)2783 void Rect_ToWindowCoords(rectDef_t *rect, windowDef_t *window) {
2784   ToWindowCoords(&rect->x, &rect->y, window);
2785 }
2786 
Item_SetTextExtents(itemDef_t * item,int * width,int * height,const char * text)2787 void Item_SetTextExtents(itemDef_t *item, int *width, int *height, const char *text) {
2788   const char *textPtr = (text) ? text : item->text;
2789 
2790   if (textPtr == NULL ) {
2791     return;
2792   }
2793 
2794   *width = item->textRect.w;
2795   *height = item->textRect.h;
2796 
2797   // keeps us from computing the widths and heights more than once
2798   if (*width == 0 || (item->type == ITEM_TYPE_OWNERDRAW && item->textalignment == ITEM_ALIGN_CENTER)) {
2799     int originalWidth = DC->textWidth(item->text, item->textscale, 0);
2800 
2801     if (item->type == ITEM_TYPE_OWNERDRAW && (item->textalignment == ITEM_ALIGN_CENTER || item->textalignment == ITEM_ALIGN_RIGHT)) {
2802       originalWidth += DC->ownerDrawWidth(item->window.ownerDraw, item->textscale);
2803     } else if (item->type == ITEM_TYPE_EDITFIELD && item->textalignment == ITEM_ALIGN_CENTER && item->cvar) {
2804       char buff[256];
2805       DC->getCVarString(item->cvar, buff, 256);
2806       originalWidth += DC->textWidth(buff, item->textscale, 0);
2807     }
2808 
2809     *width = DC->textWidth(textPtr, item->textscale, 0);
2810     *height = DC->textHeight(textPtr, item->textscale, 0);
2811     item->textRect.w = *width;
2812     item->textRect.h = *height;
2813     item->textRect.x = item->textalignx;
2814     item->textRect.y = item->textaligny;
2815     if (item->textalignment == ITEM_ALIGN_RIGHT) {
2816       item->textRect.x = item->textalignx - originalWidth;
2817     } else if (item->textalignment == ITEM_ALIGN_CENTER) {
2818       item->textRect.x = item->textalignx - originalWidth / 2;
2819     }
2820 
2821     ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
2822   }
2823 }
2824 
Item_TextColor(itemDef_t * item,vec4_t * newColor)2825 void Item_TextColor(itemDef_t *item, vec4_t *newColor) {
2826   vec4_t lowLight;
2827   menuDef_t *parent = (menuDef_t*)item->parent;
2828 
2829   Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
2830 
2831   if (item->window.flags & WINDOW_HASFOCUS) {
2832 /*    lowLight[0] = 0.8 * parent->focusColor[0];
2833     lowLight[1] = 0.8 * parent->focusColor[1];
2834     lowLight[2] = 0.8 * parent->focusColor[2];
2835     lowLight[3] = 0.8 * parent->focusColor[3];
2836     LerpColor(parent->focusColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
2837     //TA:
2838     memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
2839   } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
2840     lowLight[0] = 0.8 * item->window.foreColor[0];
2841     lowLight[1] = 0.8 * item->window.foreColor[1];
2842     lowLight[2] = 0.8 * item->window.foreColor[2];
2843     lowLight[3] = 0.8 * item->window.foreColor[3];
2844     LerpColor(item->window.foreColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
2845   } else {
2846     memcpy(newColor, &item->window.foreColor, sizeof(vec4_t));
2847     // items can be enabled and disabled based on cvars
2848   }
2849 
2850   if (item->enableCvar != NULL && *item->enableCvar && item->cvarTest != NULL && *item->cvarTest) {
2851     if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
2852       memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
2853     }
2854   }
2855 }
2856 
Item_Text_AutoWrapped_Lines(itemDef_t * item)2857 int Item_Text_AutoWrapped_Lines( itemDef_t *item )
2858 {
2859   char        text[ 1024 ];
2860   const char  *p, *textPtr, *newLinePtr;
2861   char        buff[ 1024 ];
2862   int         len, textWidth, newLine;
2863   int         lines = 0;
2864 
2865   textWidth = 0;
2866   newLinePtr = NULL;
2867 
2868   if( item->text == NULL )
2869   {
2870     if( item->cvar == NULL )
2871       return 0;
2872     else
2873     {
2874       DC->getCVarString( item->cvar, text, sizeof( text ) );
2875       textPtr = text;
2876     }
2877   }
2878   else
2879     textPtr = item->text;
2880 
2881   if( *textPtr == '\0' )
2882     return 0;
2883 
2884   len = 0;
2885   buff[ 0 ] = '\0';
2886   newLine = 0;
2887   p = textPtr;
2888 
2889   while( p )
2890   {
2891     textWidth = DC->textWidth( buff, item->textscale, 0 );
2892 
2893     if( *p == ' ' || *p == '\t' || *p == '\n' || *p == '\0' )
2894     {
2895       newLine = len;
2896       newLinePtr = p + 1;
2897     }
2898 
2899     //TA: forceably split lines that are too long (where normal splitage has failed)
2900     if( textWidth > item->window.rect.w && newLine == 0 && *p != '\n' )
2901     {
2902       newLine = len;
2903       newLinePtr = p;
2904     }
2905 
2906     if( ( newLine && textWidth > item->window.rect.w ) || *p == '\n' || *p == '\0' )
2907     {
2908       if( len )
2909         buff[ newLine ] = '\0';
2910 
2911       if( !( *p == '\n' && !*( p + 1 ) ) )
2912         lines++;
2913 
2914       if( *p == '\0' )
2915         break;
2916 
2917       //
2918       p = newLinePtr;
2919       len = 0;
2920       newLine = 0;
2921 
2922       continue;
2923     }
2924 
2925     buff[ len++ ] = *p++;
2926     buff[ len ] = '\0';
2927   }
2928 
2929   return lines;
2930 }
2931 
2932 #define MAX_AUTOWRAP_CACHE  16
2933 #define MAX_AUTOWRAP_LINES  32
2934 #define MAX_AUTOWRAP_TEXT   512
2935 
2936 typedef struct
2937 {
2938   //this is used purely for checking for cache hits
2939   char      text[ MAX_AUTOWRAP_TEXT * MAX_AUTOWRAP_LINES ];
2940   rectDef_t rect;
2941   int       textWidth, textHeight;
2942   char      lines[ MAX_AUTOWRAP_LINES ][ MAX_AUTOWRAP_TEXT ];
2943   int       lineOffsets[ MAX_AUTOWRAP_LINES ][ 2 ];
2944   int       numLines;
2945 } autoWrapCache_t;
2946 
2947 static int              cacheIndex = 0;
2948 static autoWrapCache_t  awc[ MAX_AUTOWRAP_CACHE ];
2949 
checkCache(const char * text,rectDef_t * rect,int width,int height)2950 static int checkCache( const char *text, rectDef_t *rect, int width, int height )
2951 {
2952   int i;
2953 
2954   for( i = 0; i < MAX_AUTOWRAP_CACHE; i++ )
2955   {
2956     if( Q_stricmp( text, awc[ i ].text ) )
2957       continue;
2958 
2959     if( rect->x != awc[ i ].rect.x ||
2960         rect->y != awc[ i ].rect.y ||
2961         rect->w != awc[ i ].rect.w ||
2962         rect->h != awc[ i ].rect.h )
2963       continue;
2964 
2965     if( awc[ i ].textWidth != width || awc[ i ].textHeight != height )
2966       continue;
2967 
2968     //this is a match
2969     return i;
2970   }
2971 
2972   //no match - autowrap isn't cached
2973   return -1;
2974 }
2975 
Item_Text_AutoWrapped_Paint(itemDef_t * item)2976 void Item_Text_AutoWrapped_Paint( itemDef_t *item )
2977 {
2978   char        text[ 1024 ];
2979   const char  *p, *textPtr, *newLinePtr;
2980   char        buff[ 1024 ];
2981   char        lastCMod[ 2 ] = { 0, 0 };
2982   qboolean    forwardColor = qfalse;
2983   int         width, height, len, textWidth, newLine, newLineWidth;
2984   int         skipLines, totalLines, lineNum = 0;
2985   float       y, totalY, diffY;
2986   vec4_t      color;
2987   int         cache, i;
2988 
2989   textWidth = 0;
2990   newLinePtr = NULL;
2991 
2992   if( item->text == NULL )
2993   {
2994     if( item->cvar == NULL )
2995       return;
2996     else
2997     {
2998       DC->getCVarString( item->cvar, text, sizeof( text ) );
2999       textPtr = text;
3000     }
3001   }
3002   else
3003     textPtr = item->text;
3004 
3005   if( *textPtr == '\0' )
3006     return;
3007 
3008   Item_TextColor( item, &color );
3009   Item_SetTextExtents( item, &width, &height, textPtr );
3010 
3011   //check if this block is cached
3012   cache = checkCache( textPtr, &item->window.rect, width, height );
3013   if( cache >= 0 )
3014   {
3015     lineNum = awc[ cache ].numLines;
3016 
3017     for( i = 0; i < lineNum; i++ )
3018     {
3019       item->textRect.x = awc[ cache ].lineOffsets[ i ][ 0 ];
3020       item->textRect.y = awc[ cache ].lineOffsets[ i ][ 1 ];
3021 
3022       DC->drawText( item->textRect.x, item->textRect.y, item->textscale, color,
3023                     awc[ cache ].lines[ i ], 0, 0, item->textStyle );
3024     }
3025   }
3026   else
3027   {
3028     y = item->textaligny;
3029     len = 0;
3030     buff[ 0 ] = '\0';
3031     newLine = 0;
3032     newLineWidth = 0;
3033     p = textPtr;
3034 
3035     totalLines = Item_Text_AutoWrapped_Lines( item );
3036 
3037     totalY = totalLines * ( height + 5 );
3038     diffY = totalY - item->window.rect.h;
3039 
3040     if( diffY > 0.0f )
3041       skipLines = (int)( diffY / ( (float)height + 5.0f ) );
3042     else
3043       skipLines = 0;
3044 
3045     //set up a cache entry
3046     strcpy( awc[ cacheIndex ].text, textPtr );
3047     awc[ cacheIndex ].rect.x = item->window.rect.x;
3048     awc[ cacheIndex ].rect.y = item->window.rect.y;
3049     awc[ cacheIndex ].rect.w = item->window.rect.w;
3050     awc[ cacheIndex ].rect.h = item->window.rect.h;
3051     awc[ cacheIndex ].textWidth = width;
3052     awc[ cacheIndex ].textHeight = height;
3053 
3054     while( p )
3055     {
3056       textWidth = DC->textWidth( buff, item->textscale, 0 );
3057 
3058       if( *p == '^' )
3059       {
3060         lastCMod[ 0 ] = p[ 0 ];
3061         lastCMod[ 1 ] = p[ 1 ];
3062       }
3063 
3064       if( *p == ' ' || *p == '\t' || *p == '\n' || *p == '\0' )
3065       {
3066         newLine = len;
3067         newLinePtr = p+1;
3068         newLineWidth = textWidth;
3069 
3070         if( *p == '\n' ) //don't forward colours past deilberate \n's
3071           lastCMod[ 0 ] = lastCMod[ 1 ] = 0;
3072         else
3073           forwardColor = qtrue;
3074       }
3075 
3076       //TA: forceably split lines that are too long (where normal splitage has failed)
3077       if( textWidth > item->window.rect.w && newLine == 0 && *p != '\n' )
3078       {
3079         newLine = len;
3080         newLinePtr = p;
3081         newLineWidth = textWidth;
3082 
3083         forwardColor = qtrue;
3084       }
3085 
3086       if( ( newLine && textWidth > item->window.rect.w ) || *p == '\n' || *p == '\0' )
3087       {
3088         if( len )
3089         {
3090           if( item->textalignment == ITEM_ALIGN_LEFT )
3091             item->textRect.x = item->textalignx;
3092           else if( item->textalignment == ITEM_ALIGN_RIGHT )
3093             item->textRect.x = item->textalignx - newLineWidth;
3094           else if( item->textalignment == ITEM_ALIGN_CENTER )
3095             item->textRect.x = item->textalignx - newLineWidth / 2;
3096 
3097           item->textRect.y = y;
3098           ToWindowCoords( &item->textRect.x, &item->textRect.y, &item->window );
3099           //
3100           buff[ newLine ] = '\0';
3101 
3102           if( !skipLines )
3103           {
3104             DC->drawText( item->textRect.x, item->textRect.y, item->textscale, color, buff, 0, 0, item->textStyle );
3105 
3106             strcpy( awc[ cacheIndex ].lines[ lineNum ], buff );
3107             awc[ cacheIndex ].lineOffsets[ lineNum ][ 0 ] = item->textRect.x;
3108             awc[ cacheIndex ].lineOffsets[ lineNum ][ 1 ] = item->textRect.y;
3109 
3110             lineNum++;
3111           }
3112         }
3113         if( *p == '\0' )
3114           break;
3115 
3116         //
3117         if( !skipLines )
3118           y += height + 5;
3119 
3120         if( skipLines )
3121           skipLines--;
3122 
3123         p = newLinePtr;
3124         len = 0;
3125         newLine = 0;
3126         newLineWidth = 0;
3127 
3128         if( forwardColor && lastCMod[ 0 ] != 0 )
3129         {
3130           buff[ len++ ] = lastCMod[ 0 ];
3131           buff[ len++ ] = lastCMod[ 1 ];
3132           buff[ len ] = '\0';
3133 
3134           forwardColor = qfalse;
3135         }
3136 
3137         continue;
3138       }
3139 
3140       buff[ len++ ] = *p++;
3141       buff[ len ] = '\0';
3142     }
3143 
3144     //mark the end of the lines list
3145     awc[ cacheIndex ].numLines = lineNum;
3146 
3147     //increment cacheIndex
3148     cacheIndex = ( cacheIndex + 1 ) % MAX_AUTOWRAP_CACHE;
3149   }
3150 }
3151 
Item_Text_Wrapped_Paint(itemDef_t * item)3152 void Item_Text_Wrapped_Paint(itemDef_t *item) {
3153   char text[1024];
3154   const char *p, *start, *textPtr;
3155   char buff[1024];
3156   int width, height;
3157   float x, y;
3158   vec4_t color;
3159 
3160   // now paint the text and/or any optional images
3161   // default to left
3162 
3163   if (item->text == NULL) {
3164     if (item->cvar == NULL) {
3165       return;
3166     }
3167     else {
3168       DC->getCVarString(item->cvar, text, sizeof(text));
3169       textPtr = text;
3170     }
3171   }
3172   else {
3173     textPtr = item->text;
3174   }
3175   if (*textPtr == '\0') {
3176     return;
3177   }
3178 
3179   Item_TextColor(item, &color);
3180   Item_SetTextExtents(item, &width, &height, textPtr);
3181 
3182   x = item->textRect.x;
3183   y = item->textRect.y;
3184   start = textPtr;
3185   p = strchr(textPtr, '\r');
3186   while (p && *p) {
3187     strncpy(buff, start, p-start+1);
3188     buff[p-start] = '\0';
3189     DC->drawText(x, y, item->textscale, color, buff, 0, 0, item->textStyle);
3190     y += height + 5;
3191     start += p - start + 1;
3192     p = strchr(p+1, '\r');
3193   }
3194   DC->drawText(x, y, item->textscale, color, start, 0, 0, item->textStyle);
3195 }
3196 
Item_Text_Paint(itemDef_t * item)3197 void Item_Text_Paint(itemDef_t *item) {
3198   char text[1024];
3199   const char *textPtr;
3200   int height, width;
3201   vec4_t color;
3202 
3203   if (item->window.flags & WINDOW_WRAPPED) {
3204     Item_Text_Wrapped_Paint(item);
3205     return;
3206   }
3207   if (item->window.flags & WINDOW_AUTOWRAPPED) {
3208     Item_Text_AutoWrapped_Paint(item);
3209     return;
3210   }
3211 
3212   if (item->text == NULL) {
3213     if (item->cvar == NULL) {
3214       return;
3215     }
3216     else {
3217       DC->getCVarString(item->cvar, text, sizeof(text));
3218       textPtr = text;
3219     }
3220   }
3221   else {
3222     textPtr = item->text;
3223   }
3224 
3225   // this needs to go here as it sets extents for cvar types as well
3226   Item_SetTextExtents(item, &width, &height, textPtr);
3227 
3228   if (*textPtr == '\0') {
3229     return;
3230   }
3231 
3232 
3233   Item_TextColor(item, &color);
3234 
3235   //FIXME: this is a fucking mess
3236 /*
3237   adjust = 0;
3238   if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
3239     adjust = 0.5;
3240   }
3241 
3242   if (item->textStyle == ITEM_TEXTSTYLE_SHADOWED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
3243     Fade(&item->window.flags, &DC->Assets.shadowColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
3244     DC->drawText(item->textRect.x + DC->Assets.shadowX, item->textRect.y + DC->Assets.shadowY, item->textscale, DC->Assets.shadowColor, textPtr, adjust);
3245   }
3246 */
3247 
3248 
3249 //  if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
3250 //    Fade(&item->window.flags, &item->window.outlineColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
3251 //    /*
3252 //    Text_Paint(item->textRect.x-1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
3253 //    Text_Paint(item->textRect.x, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
3254 //    Text_Paint(item->textRect.x+1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
3255 //    Text_Paint(item->textRect.x-1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
3256 //    Text_Paint(item->textRect.x+1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
3257 //    Text_Paint(item->textRect.x-1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
3258 //    Text_Paint(item->textRect.x, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
3259 //    Text_Paint(item->textRect.x+1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
3260 //    */
3261 //    DC->drawText(item->textRect.x - 1, item->textRect.y + 1, item->textscale * 1.02, item->window.outlineColor, textPtr, adjust);
3262 //  }
3263 
3264   DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, 0, item->textStyle);
3265 }
3266 
3267 
3268 
3269 //float     trap_Cvar_VariableValue( const char *var_name );
3270 //void      trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
3271 
Item_TextField_Paint(itemDef_t * item)3272 void Item_TextField_Paint(itemDef_t *item) {
3273   char buff[1024];
3274   vec4_t newColor;
3275   int offset;
3276   menuDef_t *parent = (menuDef_t*)item->parent;
3277   editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
3278 
3279   Item_Text_Paint(item);
3280 
3281   buff[0] = '\0';
3282 
3283   if (item->cvar) {
3284     DC->getCVarString(item->cvar, buff, sizeof(buff));
3285   }
3286 
3287   parent = (menuDef_t*)item->parent;
3288 
3289   if (item->window.flags & WINDOW_HASFOCUS) {
3290 /*    lowLight[0] = 0.8 * parent->focusColor[0];
3291     lowLight[1] = 0.8 * parent->focusColor[1];
3292     lowLight[2] = 0.8 * parent->focusColor[2];
3293     lowLight[3] = 0.8 * parent->focusColor[3];
3294     LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
3295     //TA:
3296     memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
3297   } else {
3298     memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
3299   }
3300 
3301   offset = (item->text && *item->text) ? 8 : 0;
3302   if (item->window.flags & WINDOW_HASFOCUS && g_editingField) {
3303     char cursor = DC->getOverstrikeMode() ? '_' : '|';
3304     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);
3305   } else {
3306     DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle);
3307   }
3308 
3309 }
3310 
Item_YesNo_Paint(itemDef_t * item)3311 void Item_YesNo_Paint(itemDef_t *item) {
3312   vec4_t newColor;
3313   float value;
3314   menuDef_t *parent = (menuDef_t*)item->parent;
3315 
3316   value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
3317 
3318   if (item->window.flags & WINDOW_HASFOCUS) {
3319 /*    lowLight[0] = 0.8 * parent->focusColor[0];
3320     lowLight[1] = 0.8 * parent->focusColor[1];
3321     lowLight[2] = 0.8 * parent->focusColor[2];
3322     lowLight[3] = 0.8 * parent->focusColor[3];
3323     LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
3324     //TA:
3325     memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
3326   } else {
3327     memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
3328   }
3329 
3330   if (item->text) {
3331     Item_Text_Paint(item);
3332     DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
3333   } else {
3334     DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
3335   }
3336 }
3337 
Item_Multi_Paint(itemDef_t * item)3338 void Item_Multi_Paint(itemDef_t *item) {
3339   vec4_t newColor;
3340   const char *text = "";
3341   menuDef_t *parent = (menuDef_t*)item->parent;
3342 
3343   if (item->window.flags & WINDOW_HASFOCUS) {
3344 /*    lowLight[0] = 0.8 * parent->focusColor[0];
3345     lowLight[1] = 0.8 * parent->focusColor[1];
3346     lowLight[2] = 0.8 * parent->focusColor[2];
3347     lowLight[3] = 0.8 * parent->focusColor[3];
3348     LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
3349     //TA:
3350     memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
3351   } else {
3352     memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
3353   }
3354 
3355   text = Item_Multi_Setting(item);
3356 
3357   if (item->text) {
3358     Item_Text_Paint(item);
3359     DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
3360   } else {
3361     DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
3362   }
3363 }
3364 
3365 
3366 typedef struct {
3367   char  *command;
3368   int   id;
3369   int   defaultbind1;
3370   int   defaultbind2;
3371   int   bind1;
3372   int   bind2;
3373 } bind_t;
3374 
3375 typedef struct
3376 {
3377   char* name;
3378   float defaultvalue;
3379   float value;
3380 } configcvar_t;
3381 
3382 
3383 static bind_t g_bindings[] =
3384 {
3385   { "+scores",      K_TAB,         -1, -1, -1 },
3386   { "+button2",     K_ENTER,       -1, -1, -1 },
3387   { "+speed",       K_SHIFT,       -1, -1, -1 },
3388   { "boost",        'x',           -1, -1, -1 }, //TA: human sprinting
3389   { "+forward",     K_UPARROW,     -1, -1, -1 },
3390   { "+back",        K_DOWNARROW,   -1, -1, -1 },
3391   { "+moveleft",    ',',           -1, -1, -1 },
3392   { "+moveright",   '.',           -1, -1, -1 },
3393   { "+moveup",      K_SPACE,       -1, -1, -1 },
3394   { "+movedown",    'c',           -1, -1, -1 },
3395   { "+left",        K_LEFTARROW,   -1, -1, -1 },
3396   { "+right",       K_RIGHTARROW,  -1, -1, -1 },
3397   { "+strafe",      K_ALT,         -1, -1, -1 },
3398   { "+lookup",      K_PGDN,        -1, -1, -1 },
3399   { "+lookdown",    K_DEL,         -1, -1, -1 },
3400   { "+mlook",       '/',           -1, -1, -1 },
3401   { "centerview",   K_END,         -1, -1, -1 },
3402   { "+zoom",        -1,            -1, -1, -1 },
3403   { "weapon 1",     '1',           -1, -1, -1 },
3404   { "weapon 2",     '2',           -1, -1, -1 },
3405   { "weapon 3",     '3',           -1, -1, -1 },
3406   { "weapon 4",     '4',           -1, -1, -1 },
3407   { "weapon 5",     '5',           -1, -1, -1 },
3408   { "weapon 6",     '6',           -1, -1, -1 },
3409   { "weapon 7",     '7',           -1, -1, -1 },
3410   { "weapon 8",     '8',           -1, -1, -1 },
3411   { "weapon 9",     '9',           -1, -1, -1 },
3412   { "weapon 10",    '0',           -1, -1, -1 },
3413   { "weapon 11",    -1,            -1, -1, -1 },
3414   { "weapon 12",    -1,            -1, -1, -1 },
3415   { "weapon 13",    -1,            -1, -1, -1 },
3416   { "+attack",      K_MOUSE1,      -1, -1, -1 },
3417   { "+button5",     K_MOUSE2,      -1, -1, -1 }, //TA: secondary attack
3418   { "reload",       'r',           -1, -1, -1 }, //TA: reload
3419   { "buy ammo",     'b',           -1, -1, -1 }, //TA: buy ammo
3420   { "itemact medkit", 'm',         -1, -1, -1 }, //TA: use medkit
3421   { "+button7",     'q',           -1, -1, -1 }, //TA: buildable use
3422   { "deconstruct",  'e',           -1, -1, -1 }, //TA: buildable destroy
3423   { "weapprev",     '[',           -1, -1, -1 },
3424   { "weapnext",     ']',           -1, -1, -1 },
3425   { "+button3",     K_MOUSE3,      -1, -1, -1 },
3426   { "+button4",     K_MOUSE4,      -1, -1, -1 },
3427   { "prevTeamMember", 'w',         -1, -1, -1 },
3428   { "nextTeamMember", 'r',         -1, -1, -1 },
3429   { "nextOrder",    't',           -1, -1, -1 },
3430   { "confirmOrder", 'y',           -1, -1, -1 },
3431   { "denyOrder",    'n',           -1, -1, -1 },
3432   { "taskOffense",  'o',           -1, -1, -1 },
3433   { "taskDefense",  'd',           -1, -1, -1 },
3434   { "taskPatrol",   'p',           -1, -1, -1 },
3435   { "taskCamp",     'c',           -1, -1, -1 },
3436   { "taskFollow",   'f',           -1, -1, -1 },
3437   { "taskRetrieve", 'v',           -1, -1, -1 },
3438   { "taskEscort",   'l',           -1, -1, -1 },
3439   { "taskOwnFlag",  'i',           -1, -1, -1 },
3440   { "taskSuicide",  'k',           -1, -1, -1 },
3441   { "tauntKillInsult", K_F1,       -1, -1, -1 },
3442   { "tauntPraise",   K_F2,         -1, -1, -1 },
3443   { "tauntTaunt",    K_F3,         -1, -1, -1 },
3444   { "tauntDeathInsult", K_F4,      -1, -1, -1 },
3445   { "tauntGauntlet", K_F5,         -1, -1, -1 },
3446   { "scoresUp",      K_KP_PGUP,    -1, -1, -1 },
3447   { "scoresDown",    K_KP_PGDN,    -1, -1, -1 },
3448   // bk001205 - this one below was:  '-1'
3449   { "messagemode",  -1,            -1, -1, -1 },
3450   { "messagemode2", -1,            -1, -1, -1 },
3451   { "messagemode3", -1,            -1, -1, -1 },
3452   { "messagemode4", -1,            -1, -1, -1 }
3453 };
3454 
3455 
3456 static const int g_bindCount = sizeof(g_bindings) / sizeof(bind_t);
3457 
3458 /*
3459 =================
3460 Controls_GetKeyAssignment
3461 =================
3462 */
Controls_GetKeyAssignment(char * command,int * twokeys)3463 static void Controls_GetKeyAssignment (char *command, int *twokeys)
3464 {
3465   int   count;
3466   int   j;
3467   char  b[256];
3468 
3469   twokeys[0] = twokeys[1] = -1;
3470   count = 0;
3471 
3472   for ( j = 0; j < 256; j++ )
3473   {
3474     DC->getBindingBuf( j, b, 256 );
3475     if ( *b == 0 ) {
3476       continue;
3477     }
3478     if ( !Q_stricmp( b, command ) ) {
3479       twokeys[count] = j;
3480       count++;
3481       if (count == 2) {
3482         break;
3483       }
3484     }
3485   }
3486 }
3487 
3488 /*
3489 =================
3490 Controls_GetConfig
3491 =================
3492 */
Controls_GetConfig(void)3493 void Controls_GetConfig( void )
3494 {
3495   int   i;
3496   int   twokeys[ 2 ];
3497 
3498   // iterate each command, get its numeric binding
3499   for( i = 0; i < g_bindCount; i++ )
3500   {
3501     Controls_GetKeyAssignment( g_bindings[ i ].command, twokeys );
3502 
3503     g_bindings[ i ].bind1 = twokeys[ 0 ];
3504     g_bindings[ i ].bind2 = twokeys[ 1 ];
3505   }
3506 
3507   //s_controls.invertmouse.curvalue  = DC->getCVarValue( "m_pitch" ) < 0;
3508   //s_controls.smoothmouse.curvalue  = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
3509   //s_controls.alwaysrun.curvalue    = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
3510   //s_controls.autoswitch.curvalue   = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) );
3511   //s_controls.sensitivity.curvalue  = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
3512   //s_controls.joyenable.curvalue    = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
3513   //s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05, 0.75, Controls_GetCvarValue( "joy_threshold" ) );
3514   //s_controls.freelook.curvalue     = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
3515 }
3516 
3517 /*
3518 =================
3519 Controls_SetConfig
3520 =================
3521 */
Controls_SetConfig(qboolean restart)3522 void Controls_SetConfig(qboolean restart)
3523 {
3524   int   i;
3525 
3526   // iterate each command, get its numeric binding
3527   for (i=0; i < g_bindCount; i++)
3528   {
3529 
3530     if (g_bindings[i].bind1 != -1)
3531     {
3532       DC->setBinding( g_bindings[i].bind1, g_bindings[i].command );
3533 
3534       if (g_bindings[i].bind2 != -1)
3535         DC->setBinding( g_bindings[i].bind2, g_bindings[i].command );
3536     }
3537   }
3538 
3539   //if ( s_controls.invertmouse.curvalue )
3540   //  DC->setCVar("m_pitch", va("%f),-fabs( DC->getCVarValue( "m_pitch" ) ) );
3541   //else
3542   //  trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
3543 
3544   //trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
3545   //trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
3546   //trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
3547   //trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
3548   //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
3549   //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
3550   //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
3551   DC->executeText(EXEC_APPEND, "in_restart\n");
3552   //trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
3553 }
3554 
3555 /*
3556 =================
3557 Controls_SetDefaults
3558 =================
3559 */
Controls_SetDefaults(void)3560 void Controls_SetDefaults( void )
3561 {
3562   int i;
3563 
3564   // iterate each command, set its default binding
3565   for (i=0; i < g_bindCount; i++)
3566   {
3567     g_bindings[i].bind1 = g_bindings[i].defaultbind1;
3568     g_bindings[i].bind2 = g_bindings[i].defaultbind2;
3569   }
3570 
3571   //s_controls.invertmouse.curvalue  = Controls_GetCvarDefault( "m_pitch" ) < 0;
3572   //s_controls.smoothmouse.curvalue  = Controls_GetCvarDefault( "m_filter" );
3573   //s_controls.alwaysrun.curvalue    = Controls_GetCvarDefault( "cl_run" );
3574   //s_controls.autoswitch.curvalue   = Controls_GetCvarDefault( "cg_autoswitch" );
3575   //s_controls.sensitivity.curvalue  = Controls_GetCvarDefault( "sensitivity" );
3576   //s_controls.joyenable.curvalue    = Controls_GetCvarDefault( "in_joystick" );
3577   //s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
3578   //s_controls.freelook.curvalue     = Controls_GetCvarDefault( "cl_freelook" );
3579 }
3580 
BindingIDFromName(const char * name)3581 int BindingIDFromName(const char *name) {
3582   int i;
3583   for (i=0; i < g_bindCount; i++)
3584   {
3585     if (Q_stricmp(name, g_bindings[i].command) == 0) {
3586       return i;
3587     }
3588   }
3589   return -1;
3590 }
3591 
3592 char g_nameBind1[32];
3593 char g_nameBind2[32];
3594 
BindingFromName(const char * cvar)3595 void BindingFromName(const char *cvar) {
3596   int i, b1, b2;
3597 
3598   // iterate each command, set its default binding
3599   for (i=0; i < g_bindCount; i++)
3600   {
3601     if (Q_stricmp(cvar, g_bindings[i].command) == 0) {
3602       b1 = g_bindings[i].bind1;
3603       if (b1 == -1) {
3604         break;
3605       }
3606         DC->keynumToStringBuf( b1, g_nameBind1, 32 );
3607         Q_strupr(g_nameBind1);
3608 
3609         b2 = g_bindings[i].bind2;
3610         if (b2 != -1)
3611         {
3612           DC->keynumToStringBuf( b2, g_nameBind2, 32 );
3613           Q_strupr(g_nameBind2);
3614           strcat( g_nameBind1, " or " );
3615           strcat( g_nameBind1, g_nameBind2 );
3616         }
3617       return;
3618     }
3619   }
3620   strcpy(g_nameBind1, "???");
3621 }
3622 
Item_Slider_Paint(itemDef_t * item)3623 void Item_Slider_Paint(itemDef_t *item) {
3624   vec4_t newColor;
3625   float x, y, value;
3626   menuDef_t *parent = (menuDef_t*)item->parent;
3627 
3628   value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
3629 
3630   if (item->window.flags & WINDOW_HASFOCUS) {
3631 /*    lowLight[0] = 0.8 * parent->focusColor[0];
3632     lowLight[1] = 0.8 * parent->focusColor[1];
3633     lowLight[2] = 0.8 * parent->focusColor[2];
3634     lowLight[3] = 0.8 * parent->focusColor[3];
3635     LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
3636     //TA:
3637     memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
3638   } else {
3639     memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
3640   }
3641 
3642   y = item->window.rect.y;
3643   if (item->text) {
3644     Item_Text_Paint(item);
3645     x = item->textRect.x + item->textRect.w + 8;
3646   } else {
3647     x = item->window.rect.x;
3648   }
3649   DC->setColor(newColor);
3650   DC->drawHandlePic( x, y, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar );
3651 
3652   x = Item_Slider_ThumbPosition(item);
3653   DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y - 2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb );
3654 
3655 }
3656 
Item_Bind_Paint(itemDef_t * item)3657 void Item_Bind_Paint(itemDef_t *item) {
3658   vec4_t newColor, lowLight;
3659   float value;
3660   int maxChars = 0;
3661   menuDef_t *parent = (menuDef_t*)item->parent;
3662   editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
3663   if (editPtr) {
3664     maxChars = editPtr->maxPaintChars;
3665   }
3666 
3667   value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
3668 
3669   if (item->window.flags & WINDOW_HASFOCUS) {
3670     if (g_bindItem == item) {
3671       lowLight[0] = 0.8f * 1.0f;
3672       lowLight[1] = 0.8f * 0.0f;
3673       lowLight[2] = 0.8f * 0.0f;
3674       lowLight[3] = 0.8f * 1.0f;
3675     } else {
3676       lowLight[0] = 0.8f * parent->focusColor[0];
3677       lowLight[1] = 0.8f * parent->focusColor[1];
3678       lowLight[2] = 0.8f * parent->focusColor[2];
3679       lowLight[3] = 0.8f * parent->focusColor[3];
3680     }
3681     /*LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
3682     //TA:
3683     memcpy(newColor, &parent->focusColor, sizeof(vec4_t));
3684   } else {
3685     memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
3686   }
3687 
3688   if (item->text) {
3689     Item_Text_Paint(item);
3690     BindingFromName(item->cvar);
3691     DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, 0, maxChars, item->textStyle);
3692   } else {
3693     DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "FIXME" : "FIXME", 0, maxChars, item->textStyle);
3694   }
3695 }
3696 
Display_KeyBindPending(void)3697 qboolean Display_KeyBindPending( void ) {
3698   return g_waitingForKey;
3699 }
3700 
Item_Bind_HandleKey(itemDef_t * item,int key,qboolean down)3701 qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) {
3702   int     id;
3703   int     i;
3704 
3705   if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey)
3706   {
3707     if (down && (key == K_MOUSE1 || key == K_ENTER)) {
3708       g_waitingForKey = qtrue;
3709       g_bindItem = item;
3710     }
3711     return qtrue;
3712   }
3713   else
3714   {
3715     if (!g_waitingForKey || g_bindItem == NULL) {
3716       return qtrue;
3717     }
3718 
3719     if (key & K_CHAR_FLAG) {
3720       return qtrue;
3721     }
3722 
3723     switch (key)
3724     {
3725       case K_ESCAPE:
3726         g_waitingForKey = qfalse;
3727         return qtrue;
3728 
3729       case K_BACKSPACE:
3730         id = BindingIDFromName(item->cvar);
3731         if (id != -1) {
3732           g_bindings[id].bind1 = -1;
3733           g_bindings[id].bind2 = -1;
3734         }
3735         Controls_SetConfig(qtrue);
3736         g_waitingForKey = qfalse;
3737         g_bindItem = NULL;
3738         return qtrue;
3739 
3740       case '`':
3741         return qtrue;
3742     }
3743   }
3744 
3745   if (key != -1)
3746   {
3747 
3748     for (i=0; i < g_bindCount; i++)
3749     {
3750 
3751       if (g_bindings[i].bind2 == key) {
3752         g_bindings[i].bind2 = -1;
3753       }
3754 
3755       if (g_bindings[i].bind1 == key)
3756       {
3757         g_bindings[i].bind1 = g_bindings[i].bind2;
3758         g_bindings[i].bind2 = -1;
3759       }
3760     }
3761   }
3762 
3763 
3764   id = BindingIDFromName(item->cvar);
3765 
3766   if (id != -1) {
3767     if (key == -1) {
3768       if( g_bindings[id].bind1 != -1 ) {
3769         DC->setBinding( g_bindings[id].bind1, "" );
3770         g_bindings[id].bind1 = -1;
3771       }
3772       if( g_bindings[id].bind2 != -1 ) {
3773         DC->setBinding( g_bindings[id].bind2, "" );
3774         g_bindings[id].bind2 = -1;
3775       }
3776     }
3777     else if (g_bindings[id].bind1 == -1) {
3778       g_bindings[id].bind1 = key;
3779     }
3780     else if (g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1) {
3781       g_bindings[id].bind2 = key;
3782     }
3783     else {
3784       DC->setBinding( g_bindings[id].bind1, "" );
3785       DC->setBinding( g_bindings[id].bind2, "" );
3786       g_bindings[id].bind1 = key;
3787       g_bindings[id].bind2 = -1;
3788     }
3789   }
3790 
3791   Controls_SetConfig(qtrue);
3792   g_waitingForKey = qfalse;
3793 
3794   return qtrue;
3795 }
3796 
3797 
3798 
AdjustFrom640(float * x,float * y,float * w,float * h)3799 void AdjustFrom640(float *x, float *y, float *w, float *h) {
3800   //*x = *x * DC->scale + DC->bias;
3801   *x *= DC->xscale;
3802   *y *= DC->yscale;
3803   *w *= DC->xscale;
3804   *h *= DC->yscale;
3805 }
3806 
Item_Model_Paint(itemDef_t * item)3807 void Item_Model_Paint(itemDef_t *item) {
3808   float x, y, w, h;
3809   refdef_t refdef;
3810   refEntity_t   ent;
3811   vec3_t      mins, maxs, origin;
3812   vec3_t      angles;
3813   modelDef_t *modelPtr = (modelDef_t*)item->typeData;
3814 
3815   if (modelPtr == NULL) {
3816     return;
3817   }
3818 
3819   // setup the refdef
3820   memset( &refdef, 0, sizeof( refdef ) );
3821   refdef.rdflags = RDF_NOWORLDMODEL;
3822   AxisClear( refdef.viewaxis );
3823   x = item->window.rect.x+1;
3824   y = item->window.rect.y+1;
3825   w = item->window.rect.w-2;
3826   h = item->window.rect.h-2;
3827 
3828   AdjustFrom640( &x, &y, &w, &h );
3829 
3830   refdef.x = x;
3831   refdef.y = y;
3832   refdef.width = w;
3833   refdef.height = h;
3834 
3835   DC->modelBounds( item->asset, mins, maxs );
3836 
3837   origin[2] = -0.5 * ( mins[2] + maxs[2] );
3838   origin[1] = 0.5 * ( mins[1] + maxs[1] );
3839 
3840   // calculate distance so the model nearly fills the box
3841   if (qtrue) {
3842     float len = 0.5 * ( maxs[2] - mins[2] );
3843     origin[0] = len / 0.268;  // len / tan( fov/2 )
3844     //origin[0] = len / tan(w/2);
3845   } else {
3846     origin[0] = item->textscale;
3847   }
3848   refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w;
3849   refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h;
3850 
3851   //refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
3852   //xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
3853   //refdef.fov_y = atan2( refdef.height, xx );
3854   //refdef.fov_y *= ( 360 / M_PI );
3855 
3856   DC->clearScene();
3857 
3858   refdef.time = DC->realTime;
3859 
3860   // add the model
3861 
3862   memset( &ent, 0, sizeof(ent) );
3863 
3864   //adjust = 5.0 * sin( (float)uis.realtime / 500 );
3865   //adjust = 360 % (int)((float)uis.realtime / 1000);
3866   //VectorSet( angles, 0, 0, 1 );
3867 
3868   // use item storage to track
3869   if (modelPtr->rotationSpeed) {
3870     if (DC->realTime > item->window.nextTime) {
3871       item->window.nextTime = DC->realTime + modelPtr->rotationSpeed;
3872       modelPtr->angle = (int)(modelPtr->angle + 1) % 360;
3873     }
3874   }
3875   VectorSet( angles, 0, modelPtr->angle, 0 );
3876   AnglesToAxis( angles, ent.axis );
3877 
3878   ent.hModel = item->asset;
3879   VectorCopy( origin, ent.origin );
3880   VectorCopy( origin, ent.lightingOrigin );
3881   ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
3882   VectorCopy( ent.origin, ent.oldorigin );
3883 
3884   DC->addRefEntityToScene( &ent );
3885   DC->renderScene( &refdef );
3886 
3887 }
3888 
3889 
Item_Image_Paint(itemDef_t * item)3890 void Item_Image_Paint(itemDef_t *item) {
3891   if (item == NULL) {
3892     return;
3893   }
3894   DC->drawHandlePic(item->window.rect.x+1, item->window.rect.y+1, item->window.rect.w-2, item->window.rect.h-2, item->asset);
3895 }
3896 
Item_ListBox_Paint(itemDef_t * item)3897 void Item_ListBox_Paint(itemDef_t *item) {
3898   float x, y, size, thumb;
3899   int i, count;
3900   qhandle_t image;
3901   qhandle_t optionalImage;
3902   listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
3903 
3904   // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction
3905   // elements are enumerated from the DC and either text or image handles are acquired from the DC as well
3906   // textscale is used to size the text, textalignx and textaligny are used to size image elements
3907   // there is no clipping available so only the last completely visible item is painted
3908   count = DC->feederCount(item->special);
3909   // default is vertical if horizontal flag is not here
3910   if (item->window.flags & WINDOW_HORIZONTAL) {
3911     // draw scrollbar in bottom of the window
3912     // bar
3913     x = item->window.rect.x + 1;
3914     y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE - 1;
3915     DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft);
3916     x += SCROLLBAR_SIZE - 1;
3917     size = item->window.rect.w - (SCROLLBAR_SIZE * 2);
3918     DC->drawHandlePic(x, y, size+1, SCROLLBAR_SIZE, DC->Assets.scrollBar);
3919     x += size - 1;
3920     DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowRight);
3921     // thumb
3922     thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
3923     if (thumb > x - SCROLLBAR_SIZE - 1) {
3924       thumb = x - SCROLLBAR_SIZE - 1;
3925     }
3926     DC->drawHandlePic(thumb, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
3927     //
3928     listPtr->endPos = listPtr->startPos;
3929     size = item->window.rect.w - 2;
3930     // items
3931     // size contains max available space
3932     if (listPtr->elementStyle == LISTBOX_IMAGE) {
3933       // fit = 0;
3934       x = item->window.rect.x + 1;
3935       y = item->window.rect.y + 1;
3936       for (i = listPtr->startPos; i < count; i++) {
3937         // always draw at least one
3938         // which may overdraw the box if it is too small for the element
3939         image = DC->feederItemImage(item->special, i);
3940         if (image) {
3941           DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
3942         }
3943 
3944         if (i == item->cursorPos) {
3945           DC->drawRect(x, y, listPtr->elementWidth-1, listPtr->elementHeight-1, item->window.borderSize, item->window.borderColor);
3946         }
3947 
3948         listPtr->endPos++;
3949         size -= listPtr->elementWidth;
3950         if (size < listPtr->elementWidth) {
3951           listPtr->drawPadding = size; //listPtr->elementWidth - size;
3952           break;
3953         }
3954         x += listPtr->elementWidth;
3955         // fit++;
3956       }
3957     } else {
3958       //
3959     }
3960   } else {
3961     // draw scrollbar to right side of the window
3962     x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1;
3963     y = item->window.rect.y + 1;
3964     DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp);
3965     y += SCROLLBAR_SIZE - 1;
3966 
3967     listPtr->endPos = listPtr->startPos;
3968     size = item->window.rect.h - (SCROLLBAR_SIZE * 2);
3969     DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar);
3970     y += size - 1;
3971     DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown);
3972     // thumb
3973     thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
3974     if (thumb > y - SCROLLBAR_SIZE - 1) {
3975       thumb = y - SCROLLBAR_SIZE - 1;
3976     }
3977     DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
3978 
3979     // adjust size for item painting
3980     size = item->window.rect.h - 2;
3981     if (listPtr->elementStyle == LISTBOX_IMAGE) {
3982       // fit = 0;
3983       x = item->window.rect.x + 1;
3984       y = item->window.rect.y + 1;
3985       for (i = listPtr->startPos; i < count; i++) {
3986         // always draw at least one
3987         // which may overdraw the box if it is too small for the element
3988         image = DC->feederItemImage(item->special, i);
3989         if (image) {
3990           DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
3991         }
3992 
3993         if (i == item->cursorPos) {
3994           DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.borderColor);
3995         }
3996 
3997         listPtr->endPos++;
3998         size -= listPtr->elementWidth;
3999         if (size < listPtr->elementHeight) {
4000           listPtr->drawPadding = listPtr->elementHeight - size;
4001           break;
4002         }
4003         y += listPtr->elementHeight;
4004         // fit++;
4005       }
4006     } else {
4007       x = item->window.rect.x + 1;
4008       y = item->window.rect.y + 1;
4009       for (i = listPtr->startPos; i < count; i++) {
4010         const char *text;
4011         // always draw at least one
4012         // which may overdraw the box if it is too small for the element
4013 
4014         if (listPtr->numColumns > 0) {
4015           int j;
4016           for (j = 0; j < listPtr->numColumns; j++) {
4017             text = DC->feederItemText(item->special, i, j, &optionalImage);
4018             if (optionalImage >= 0) {
4019               DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
4020             } else if (text) {
4021               //TA:
4022               int alignOffset = 0.0f, tw;
4023 
4024               tw = DC->textWidth( text, item->textscale, 0 );
4025 
4026               switch( listPtr->columnInfo[ j ].align )
4027               {
4028                 case ITEM_ALIGN_LEFT:
4029                   alignOffset = 0.0f;
4030                   break;
4031 
4032                 case ITEM_ALIGN_RIGHT:
4033                   alignOffset = listPtr->columnInfo[ j ].width - tw;
4034                   break;
4035 
4036                 case ITEM_ALIGN_CENTER:
4037                   alignOffset = ( listPtr->columnInfo[ j ].width / 2.0f ) - ( tw / 2.0f );
4038                   break;
4039 
4040                 default:
4041                   alignOffset = 0.0f;
4042               }
4043 
4044               DC->drawText( x + 4 + listPtr->columnInfo[j].pos + alignOffset, y + listPtr->elementHeight,
4045                             item->textscale, item->window.foreColor, text, 0,
4046                             listPtr->columnInfo[j].maxChars, item->textStyle );
4047             }
4048           }
4049         } else {
4050           text = DC->feederItemText(item->special, i, 0, &optionalImage);
4051           if (optionalImage >= 0) {
4052             //DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
4053           } else if (text) {
4054             DC->drawText(x + 4, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, 0, item->textStyle);
4055           }
4056         }
4057 
4058         if (i == item->cursorPos) {
4059           DC->fillRect(x + 2, y + 2, item->window.rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight, item->window.outlineColor);
4060         }
4061 
4062         listPtr->endPos++;
4063         size -= listPtr->elementHeight;
4064         if (size < listPtr->elementHeight) {
4065           listPtr->drawPadding = listPtr->elementHeight - size;
4066           break;
4067         }
4068         y += listPtr->elementHeight;
4069         // fit++;
4070       }
4071     }
4072   }
4073 
4074   //TA: FIXME: hacky fix to off-by-one bug
4075   listPtr->endPos--;
4076 }
4077 
4078 
Item_OwnerDraw_Paint(itemDef_t * item)4079 void Item_OwnerDraw_Paint(itemDef_t *item) {
4080   menuDef_t *parent;
4081 
4082   if (item == NULL) {
4083     return;
4084   }
4085   parent = (menuDef_t*)item->parent;
4086 
4087   if (DC->ownerDrawItem) {
4088     vec4_t color, lowLight;
4089     menuDef_t *parent = (menuDef_t*)item->parent;
4090     Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
4091     memcpy(&color, &item->window.foreColor, sizeof(color));
4092     if (item->numColors > 0 && DC->getValue) {
4093       // if the value is within one of the ranges then set color to that, otherwise leave at default
4094       int i;
4095       float f = DC->getValue(item->window.ownerDraw);
4096       for (i = 0; i < item->numColors; i++) {
4097         if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high) {
4098           memcpy(&color, &item->colorRanges[i].color, sizeof(color));
4099           break;
4100         }
4101       }
4102     }
4103 
4104     if (item->window.flags & WINDOW_HASFOCUS) {
4105 /*      lowLight[0] = 0.8 * parent->focusColor[0];
4106       lowLight[1] = 0.8 * parent->focusColor[1];
4107       lowLight[2] = 0.8 * parent->focusColor[2];
4108       lowLight[3] = 0.8 * parent->focusColor[3];
4109       LerpColor(parent->focusColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));*/
4110       //TA:
4111       memcpy(color, &parent->focusColor, sizeof(vec4_t));
4112     } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
4113       lowLight[0] = 0.8 * item->window.foreColor[0];
4114       lowLight[1] = 0.8 * item->window.foreColor[1];
4115       lowLight[2] = 0.8 * item->window.foreColor[2];
4116       lowLight[3] = 0.8 * item->window.foreColor[3];
4117       LerpColor(item->window.foreColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
4118     }
4119 
4120     if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
4121       memcpy(color, parent->disableColor, sizeof(vec4_t)); // bk001207 - FIXME: Com_Memcpy
4122     }
4123 
4124     if (item->text) {
4125       Item_Text_Paint(item);
4126         if (item->text[0]) {
4127           // +8 is an offset kludge to properly align owner draw items that have text combined with them
4128           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 );
4129         } else {
4130           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 );
4131         }
4132       } else {
4133       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 );
4134     }
4135   }
4136 }
4137 
4138 
Item_Paint(itemDef_t * item)4139 void Item_Paint(itemDef_t *item) {
4140   vec4_t red;
4141   menuDef_t *parent = (menuDef_t*)item->parent;
4142   red[0] = red[3] = 1;
4143   red[1] = red[2] = 0;
4144 
4145   if (item == NULL) {
4146     return;
4147   }
4148 
4149   if (item->window.flags & WINDOW_ORBITING) {
4150     if (DC->realTime > item->window.nextTime) {
4151       float rx, ry, a, c, s, w, h;
4152 
4153       item->window.nextTime = DC->realTime + item->window.offsetTime;
4154       // translate
4155       w = item->window.rectClient.w / 2;
4156       h = item->window.rectClient.h / 2;
4157       rx = item->window.rectClient.x + w - item->window.rectEffects.x;
4158       ry = item->window.rectClient.y + h - item->window.rectEffects.y;
4159       a = 3 * M_PI / 180;
4160       c = cos(a);
4161       s = sin(a);
4162       item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w;
4163       item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h;
4164       Item_UpdatePosition(item);
4165 
4166     }
4167   }
4168 
4169 
4170   if (item->window.flags & WINDOW_INTRANSITION) {
4171     if (DC->realTime > item->window.nextTime) {
4172       int done = 0;
4173       item->window.nextTime = DC->realTime + item->window.offsetTime;
4174       // transition the x,y
4175       if (item->window.rectClient.x == item->window.rectEffects.x) {
4176         done++;
4177       } else {
4178         if (item->window.rectClient.x < item->window.rectEffects.x) {
4179           item->window.rectClient.x += item->window.rectEffects2.x;
4180           if (item->window.rectClient.x > item->window.rectEffects.x) {
4181             item->window.rectClient.x = item->window.rectEffects.x;
4182             done++;
4183           }
4184         } else {
4185           item->window.rectClient.x -= item->window.rectEffects2.x;
4186           if (item->window.rectClient.x < item->window.rectEffects.x) {
4187             item->window.rectClient.x = item->window.rectEffects.x;
4188             done++;
4189           }
4190         }
4191       }
4192       if (item->window.rectClient.y == item->window.rectEffects.y) {
4193         done++;
4194       } else {
4195         if (item->window.rectClient.y < item->window.rectEffects.y) {
4196           item->window.rectClient.y += item->window.rectEffects2.y;
4197           if (item->window.rectClient.y > item->window.rectEffects.y) {
4198             item->window.rectClient.y = item->window.rectEffects.y;
4199             done++;
4200           }
4201         } else {
4202           item->window.rectClient.y -= item->window.rectEffects2.y;
4203           if (item->window.rectClient.y < item->window.rectEffects.y) {
4204             item->window.rectClient.y = item->window.rectEffects.y;
4205             done++;
4206           }
4207         }
4208       }
4209       if (item->window.rectClient.w == item->window.rectEffects.w) {
4210         done++;
4211       } else {
4212         if (item->window.rectClient.w < item->window.rectEffects.w) {
4213           item->window.rectClient.w += item->window.rectEffects2.w;
4214           if (item->window.rectClient.w > item->window.rectEffects.w) {
4215             item->window.rectClient.w = item->window.rectEffects.w;
4216             done++;
4217           }
4218         } else {
4219           item->window.rectClient.w -= item->window.rectEffects2.w;
4220           if (item->window.rectClient.w < item->window.rectEffects.w) {
4221             item->window.rectClient.w = item->window.rectEffects.w;
4222             done++;
4223           }
4224         }
4225       }
4226       if (item->window.rectClient.h == item->window.rectEffects.h) {
4227         done++;
4228       } else {
4229         if (item->window.rectClient.h < item->window.rectEffects.h) {
4230           item->window.rectClient.h += item->window.rectEffects2.h;
4231           if (item->window.rectClient.h > item->window.rectEffects.h) {
4232             item->window.rectClient.h = item->window.rectEffects.h;
4233             done++;
4234           }
4235         } else {
4236           item->window.rectClient.h -= item->window.rectEffects2.h;
4237           if (item->window.rectClient.h < item->window.rectEffects.h) {
4238             item->window.rectClient.h = item->window.rectEffects.h;
4239             done++;
4240           }
4241         }
4242       }
4243 
4244       Item_UpdatePosition(item);
4245 
4246       if (done == 4) {
4247         item->window.flags &= ~WINDOW_INTRANSITION;
4248       }
4249 
4250     }
4251   }
4252 
4253   if (item->window.ownerDrawFlags && DC->ownerDrawVisible) {
4254     if (!DC->ownerDrawVisible(item->window.ownerDrawFlags)) {
4255       item->window.flags &= ~WINDOW_VISIBLE;
4256     } else {
4257       item->window.flags |= WINDOW_VISIBLE;
4258     }
4259   }
4260 
4261   if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE)) {
4262     if (!Item_EnableShowViaCvar(item, CVAR_SHOW)) {
4263       return;
4264     }
4265   }
4266 
4267   if (item->window.flags & WINDOW_TIMEDVISIBLE) {
4268 
4269   }
4270 
4271   if (!(item->window.flags & WINDOW_VISIBLE)) {
4272     return;
4273   }
4274 
4275   // paint the rect first..
4276   Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle);
4277 
4278   if (debugMode) {
4279     vec4_t color;
4280     rectDef_t *r = Item_CorrectedTextRect(item);
4281     color[1] = color[3] = 1;
4282     color[0] = color[2] = 0;
4283     DC->drawRect(r->x, r->y, r->w, r->h, 1, color);
4284   }
4285 
4286   //DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red);
4287 
4288   switch (item->type) {
4289     case ITEM_TYPE_OWNERDRAW:
4290       Item_OwnerDraw_Paint(item);
4291       break;
4292     case ITEM_TYPE_TEXT:
4293     case ITEM_TYPE_BUTTON:
4294       Item_Text_Paint(item);
4295       break;
4296     case ITEM_TYPE_RADIOBUTTON:
4297       break;
4298     case ITEM_TYPE_CHECKBOX:
4299       break;
4300     case ITEM_TYPE_EDITFIELD:
4301     case ITEM_TYPE_NUMERICFIELD:
4302       Item_TextField_Paint(item);
4303       break;
4304     case ITEM_TYPE_COMBO:
4305       break;
4306     case ITEM_TYPE_LISTBOX:
4307       Item_ListBox_Paint(item);
4308       break;
4309     //case ITEM_TYPE_IMAGE:
4310     //  Item_Image_Paint(item);
4311     //  break;
4312     case ITEM_TYPE_MODEL:
4313       Item_Model_Paint(item);
4314       break;
4315     case ITEM_TYPE_YESNO:
4316       Item_YesNo_Paint(item);
4317       break;
4318     case ITEM_TYPE_MULTI:
4319       Item_Multi_Paint(item);
4320       break;
4321     case ITEM_TYPE_BIND:
4322       Item_Bind_Paint(item);
4323       break;
4324     case ITEM_TYPE_SLIDER:
4325       Item_Slider_Paint(item);
4326       break;
4327     default:
4328       break;
4329   }
4330 
4331 }
4332 
Menu_Init(menuDef_t * menu)4333 void Menu_Init(menuDef_t *menu) {
4334   memset(menu, 0, sizeof(menuDef_t));
4335   menu->cursorItem = -1;
4336   menu->fadeAmount = DC->Assets.fadeAmount;
4337   menu->fadeClamp = DC->Assets.fadeClamp;
4338   menu->fadeCycle = DC->Assets.fadeCycle;
4339   Window_Init(&menu->window);
4340 }
4341 
Menu_GetFocusedItem(menuDef_t * menu)4342 itemDef_t *Menu_GetFocusedItem(menuDef_t *menu) {
4343   int i;
4344   if (menu) {
4345     for (i = 0; i < menu->itemCount; i++) {
4346       if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
4347         return menu->items[i];
4348       }
4349     }
4350   }
4351   return NULL;
4352 }
4353 
Menu_GetFocused(void)4354 menuDef_t *Menu_GetFocused( void ) {
4355   int i;
4356   for (i = 0; i < menuCount; i++) {
4357     if (Menus[i].window.flags & WINDOW_HASFOCUS && Menus[i].window.flags & WINDOW_VISIBLE) {
4358       return &Menus[i];
4359     }
4360   }
4361   return NULL;
4362 }
4363 
Menu_ScrollFeeder(menuDef_t * menu,int feeder,qboolean down)4364 void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down) {
4365   if (menu) {
4366     int i;
4367     for (i = 0; i < menu->itemCount; i++) {
4368       if (menu->items[i]->special == feeder) {
4369         Item_ListBox_HandleKey(menu->items[i], (down) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue);
4370         return;
4371       }
4372     }
4373   }
4374 }
4375 
4376 
4377 
Menu_SetFeederSelection(menuDef_t * menu,int feeder,int index,const char * name)4378 void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name) {
4379   if (menu == NULL) {
4380     if (name == NULL) {
4381       menu = Menu_GetFocused();
4382     } else {
4383       menu = Menus_FindByName(name);
4384     }
4385   }
4386 
4387   if (menu) {
4388     int i;
4389     for (i = 0; i < menu->itemCount; i++) {
4390       if (menu->items[i]->special == feeder) {
4391         if (index == 0) {
4392           listBoxDef_t *listPtr = (listBoxDef_t*)menu->items[i]->typeData;
4393           listPtr->cursorPos = 0;
4394           listPtr->startPos = 0;
4395         }
4396         menu->items[i]->cursorPos = index;
4397         DC->feederSelection(menu->items[i]->special, menu->items[i]->cursorPos);
4398         return;
4399       }
4400     }
4401   }
4402 }
4403 
Menus_AnyFullScreenVisible(void)4404 qboolean Menus_AnyFullScreenVisible( void ) {
4405   int i;
4406   for (i = 0; i < menuCount; i++) {
4407     if (Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen) {
4408       return qtrue;
4409     }
4410   }
4411   return qfalse;
4412 }
4413 
Menus_ActivateByName(const char * p)4414 menuDef_t *Menus_ActivateByName(const char *p) {
4415   int i, j;
4416   menuDef_t *m = NULL;
4417   menuDef_t *focus = Menu_GetFocused();
4418 
4419   for (i = 0; i < menuCount; i++) {
4420     if (Q_stricmp(Menus[i].window.name, p) == 0) {
4421       m = &Menus[i];
4422       Menus_Activate(m);
4423       Menu_HandleMouseMove( m, DC->cursorx, DC->cursory ); //TA: force the item under the cursor to focus
4424 
4425       for( j = 0; j < m->itemCount; j++ ) //TA: reset selection in listboxes when opened
4426       {
4427         if( m->items[ j ]->type == ITEM_TYPE_LISTBOX )
4428         {
4429           listBoxDef_t *listPtr = (listBoxDef_t*)m->items[ j ]->typeData;
4430           m->items[ j ]->cursorPos = 0;
4431           listPtr->startPos = 0;
4432           DC->feederSelection( m->items[ j ]->special, 0 );
4433         }
4434       }
4435 
4436       if (openMenuCount < MAX_OPEN_MENUS && focus != NULL) {
4437         menuStack[openMenuCount++] = focus;
4438       }
4439     } else {
4440       Menus[i].window.flags &= ~WINDOW_HASFOCUS;
4441     }
4442   }
4443   Display_CloseCinematics();
4444   return m;
4445 }
4446 
4447 
Item_Init(itemDef_t * item)4448 void Item_Init(itemDef_t *item) {
4449   memset(item, 0, sizeof(itemDef_t));
4450   item->textscale = 0.55f;
4451   Window_Init(&item->window);
4452 }
4453 
Menu_HandleMouseMove(menuDef_t * menu,float x,float y)4454 void Menu_HandleMouseMove(menuDef_t *menu, float x, float y) {
4455   int i, pass;
4456   qboolean focusSet = qfalse;
4457 
4458   itemDef_t *overItem;
4459   if (menu == NULL) {
4460     return;
4461   }
4462 
4463   if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
4464     return;
4465   }
4466 
4467   if (itemCapture) {
4468     //Item_MouseMove(itemCapture, x, y);
4469     return;
4470   }
4471 
4472   if (g_waitingForKey || g_editingField) {
4473     return;
4474   }
4475 
4476   // FIXME: this is the whole issue of focus vs. mouse over..
4477   // need a better overall solution as i don't like going through everything twice
4478   for (pass = 0; pass < 2; pass++) {
4479     for (i = 0; i < menu->itemCount; i++) {
4480       // turn off focus each item
4481       // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
4482 
4483       if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
4484         continue;
4485       }
4486 
4487       // items can be enabled and disabled based on cvars
4488       if (menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE)) {
4489         continue;
4490       }
4491 
4492       if (menu->items[i]->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_SHOW)) {
4493         continue;
4494       }
4495 
4496 
4497 
4498       if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
4499         if (pass == 1) {
4500           overItem = menu->items[i];
4501           if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
4502             if (!Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
4503               continue;
4504             }
4505           }
4506           // if we are over an item
4507           if (IsVisible(overItem->window.flags)) {
4508             // different one
4509             Item_MouseEnter(overItem, x, y);
4510             // Item_SetMouseOver(overItem, qtrue);
4511 
4512             // if item is not a decoration see if it can take focus
4513             if (!focusSet) {
4514               focusSet = Item_SetFocus(overItem, x, y);
4515             }
4516           }
4517         }
4518       } else if (menu->items[i]->window.flags & WINDOW_MOUSEOVER) {
4519           Item_MouseLeave(menu->items[i]);
4520           Item_SetMouseOver(menu->items[i], qfalse);
4521       }
4522     }
4523   }
4524 
4525 }
4526 
Menu_Paint(menuDef_t * menu,qboolean forcePaint)4527 void Menu_Paint(menuDef_t *menu, qboolean forcePaint) {
4528   int i;
4529 
4530   if (menu == NULL) {
4531     return;
4532   }
4533 
4534   if (!(menu->window.flags & WINDOW_VISIBLE) &&  !forcePaint) {
4535     return;
4536   }
4537 
4538   if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags)) {
4539     return;
4540   }
4541 
4542   if (forcePaint) {
4543     menu->window.flags |= WINDOW_FORCED;
4544   }
4545 
4546   // draw the background if necessary
4547   if (menu->fullScreen) {
4548     // implies a background shader
4549     // FIXME: make sure we have a default shader if fullscreen is set with no background
4550     DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background );
4551   } else if (menu->window.background) {
4552     // this allows a background shader without being full screen
4553     //UI_DrawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader);
4554   }
4555 
4556   // paint the background and or border
4557   Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle );
4558 
4559   for (i = 0; i < menu->itemCount; i++) {
4560     Item_Paint(menu->items[i]);
4561   }
4562 
4563   if (debugMode) {
4564     vec4_t color;
4565     color[0] = color[2] = color[3] = 1;
4566     color[1] = 0;
4567     DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color);
4568   }
4569 }
4570 
4571 /*
4572 ===============
4573 Item_ValidateTypeData
4574 ===============
4575 */
Item_ValidateTypeData(itemDef_t * item)4576 void Item_ValidateTypeData(itemDef_t *item) {
4577   if (item->typeData) {
4578     return;
4579   }
4580 
4581   if (item->type == ITEM_TYPE_LISTBOX) {
4582     item->typeData = UI_Alloc(sizeof(listBoxDef_t));
4583     memset(item->typeData, 0, sizeof(listBoxDef_t));
4584   } 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) {
4585     item->typeData = UI_Alloc(sizeof(editFieldDef_t));
4586     memset(item->typeData, 0, sizeof(editFieldDef_t));
4587     if (item->type == ITEM_TYPE_EDITFIELD) {
4588       if (!((editFieldDef_t *) item->typeData)->maxPaintChars) {
4589         ((editFieldDef_t *) item->typeData)->maxPaintChars = MAX_EDITFIELD;
4590       }
4591     }
4592   } else if (item->type == ITEM_TYPE_MULTI) {
4593     item->typeData = UI_Alloc(sizeof(multiDef_t));
4594   } else if (item->type == ITEM_TYPE_MODEL) {
4595     item->typeData = UI_Alloc(sizeof(modelDef_t));
4596   }
4597 }
4598 
4599 /*
4600 ===============
4601 Keyword Hash
4602 ===============
4603 */
4604 
4605 #define KEYWORDHASH_SIZE  512
4606 
4607 typedef struct keywordHash_s
4608 {
4609   char *keyword;
4610   qboolean (*func)(itemDef_t *item, int handle);
4611   struct keywordHash_s *next;
4612 } keywordHash_t;
4613 
KeywordHash_Key(char * keyword)4614 int KeywordHash_Key(char *keyword) {
4615   int register hash, i;
4616 
4617   hash = 0;
4618   for (i = 0; keyword[i] != '\0'; i++) {
4619     if (keyword[i] >= 'A' && keyword[i] <= 'Z')
4620       hash += (keyword[i] + ('a' - 'A')) * (119 + i);
4621     else
4622       hash += keyword[i] * (119 + i);
4623   }
4624   hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (KEYWORDHASH_SIZE-1);
4625   return hash;
4626 }
4627 
KeywordHash_Add(keywordHash_t * table[],keywordHash_t * key)4628 void KeywordHash_Add(keywordHash_t *table[], keywordHash_t *key) {
4629   int hash;
4630 
4631   hash = KeywordHash_Key(key->keyword);
4632 /*
4633   if (table[hash]) {
4634     int collision = qtrue;
4635   }
4636 */
4637   key->next = table[hash];
4638   table[hash] = key;
4639 }
4640 
KeywordHash_Find(keywordHash_t * table[],char * keyword)4641 keywordHash_t *KeywordHash_Find(keywordHash_t *table[], char *keyword)
4642 {
4643   keywordHash_t *key;
4644   int hash;
4645 
4646   hash = KeywordHash_Key(keyword);
4647   for (key = table[hash]; key; key = key->next) {
4648     if (!Q_stricmp(key->keyword, keyword))
4649       return key;
4650   }
4651   return NULL;
4652 }
4653 
4654 /*
4655 ===============
4656 Item Keyword Parse functions
4657 ===============
4658 */
4659 
4660 // name <string>
ItemParse_name(itemDef_t * item,int handle)4661 qboolean ItemParse_name( itemDef_t *item, int handle ) {
4662   if (!PC_String_Parse(handle, &item->window.name)) {
4663     return qfalse;
4664   }
4665   return qtrue;
4666 }
4667 
4668 // name <string>
ItemParse_focusSound(itemDef_t * item,int handle)4669 qboolean ItemParse_focusSound( itemDef_t *item, int handle ) {
4670   const char *temp;
4671   if (!PC_String_Parse(handle, &temp)) {
4672     return qfalse;
4673   }
4674   item->focusSound = DC->registerSound(temp, qfalse);
4675   return qtrue;
4676 }
4677 
4678 
4679 // text <string>
ItemParse_text(itemDef_t * item,int handle)4680 qboolean ItemParse_text( itemDef_t *item, int handle ) {
4681   if (!PC_String_Parse(handle, &item->text)) {
4682     return qfalse;
4683   }
4684   return qtrue;
4685 }
4686 
4687 // group <string>
ItemParse_group(itemDef_t * item,int handle)4688 qboolean ItemParse_group( itemDef_t *item, int handle ) {
4689   if (!PC_String_Parse(handle, &item->window.group)) {
4690     return qfalse;
4691   }
4692   return qtrue;
4693 }
4694 
4695 // asset_model <string>
ItemParse_asset_model(itemDef_t * item,int handle)4696 qboolean ItemParse_asset_model( itemDef_t *item, int handle ) {
4697   const char *temp;
4698   modelDef_t *modelPtr;
4699   Item_ValidateTypeData(item);
4700   modelPtr = (modelDef_t*)item->typeData;
4701 
4702   if (!PC_String_Parse(handle, &temp)) {
4703     return qfalse;
4704   }
4705   item->asset = DC->registerModel(temp);
4706   modelPtr->angle = rand() % 360;
4707   return qtrue;
4708 }
4709 
4710 // asset_shader <string>
ItemParse_asset_shader(itemDef_t * item,int handle)4711 qboolean ItemParse_asset_shader( itemDef_t *item, int handle ) {
4712   const char *temp;
4713 
4714   if (!PC_String_Parse(handle, &temp)) {
4715     return qfalse;
4716   }
4717   item->asset = DC->registerShaderNoMip(temp);
4718   return qtrue;
4719 }
4720 
4721 // model_origin <number> <number> <number>
ItemParse_model_origin(itemDef_t * item,int handle)4722 qboolean ItemParse_model_origin( itemDef_t *item, int handle ) {
4723   modelDef_t *modelPtr;
4724   Item_ValidateTypeData(item);
4725   modelPtr = (modelDef_t*)item->typeData;
4726 
4727   if (PC_Float_Parse(handle, &modelPtr->origin[0])) {
4728     if (PC_Float_Parse(handle, &modelPtr->origin[1])) {
4729       if (PC_Float_Parse(handle, &modelPtr->origin[2])) {
4730         return qtrue;
4731       }
4732     }
4733   }
4734   return qfalse;
4735 }
4736 
4737 // model_fovx <number>
ItemParse_model_fovx(itemDef_t * item,int handle)4738 qboolean ItemParse_model_fovx( itemDef_t *item, int handle ) {
4739   modelDef_t *modelPtr;
4740   Item_ValidateTypeData(item);
4741   modelPtr = (modelDef_t*)item->typeData;
4742 
4743   if (!PC_Float_Parse(handle, &modelPtr->fov_x)) {
4744     return qfalse;
4745   }
4746   return qtrue;
4747 }
4748 
4749 // model_fovy <number>
ItemParse_model_fovy(itemDef_t * item,int handle)4750 qboolean ItemParse_model_fovy( itemDef_t *item, int handle ) {
4751   modelDef_t *modelPtr;
4752   Item_ValidateTypeData(item);
4753   modelPtr = (modelDef_t*)item->typeData;
4754 
4755   if (!PC_Float_Parse(handle, &modelPtr->fov_y)) {
4756     return qfalse;
4757   }
4758   return qtrue;
4759 }
4760 
4761 // model_rotation <integer>
ItemParse_model_rotation(itemDef_t * item,int handle)4762 qboolean ItemParse_model_rotation( itemDef_t *item, int handle ) {
4763   modelDef_t *modelPtr;
4764   Item_ValidateTypeData(item);
4765   modelPtr = (modelDef_t*)item->typeData;
4766 
4767   if (!PC_Int_Parse(handle, &modelPtr->rotationSpeed)) {
4768     return qfalse;
4769   }
4770   return qtrue;
4771 }
4772 
4773 // model_angle <integer>
ItemParse_model_angle(itemDef_t * item,int handle)4774 qboolean ItemParse_model_angle( itemDef_t *item, int handle ) {
4775   modelDef_t *modelPtr;
4776   Item_ValidateTypeData(item);
4777   modelPtr = (modelDef_t*)item->typeData;
4778 
4779   if (!PC_Int_Parse(handle, &modelPtr->angle)) {
4780     return qfalse;
4781   }
4782   return qtrue;
4783 }
4784 
4785 // rect <rectangle>
ItemParse_rect(itemDef_t * item,int handle)4786 qboolean ItemParse_rect( itemDef_t *item, int handle ) {
4787   if (!PC_Rect_Parse(handle, &item->window.rectClient)) {
4788     return qfalse;
4789   }
4790   return qtrue;
4791 }
4792 
4793 // style <integer>
ItemParse_style(itemDef_t * item,int handle)4794 qboolean ItemParse_style( itemDef_t *item, int handle ) {
4795   if (!PC_Int_Parse(handle, &item->window.style)) {
4796     return qfalse;
4797   }
4798   return qtrue;
4799 }
4800 
4801 // decoration
ItemParse_decoration(itemDef_t * item,int handle)4802 qboolean ItemParse_decoration( itemDef_t *item, int handle ) {
4803   item->window.flags |= WINDOW_DECORATION;
4804   return qtrue;
4805 }
4806 
4807 // notselectable
ItemParse_notselectable(itemDef_t * item,int handle)4808 qboolean ItemParse_notselectable( itemDef_t *item, int handle ) {
4809   listBoxDef_t *listPtr;
4810   Item_ValidateTypeData(item);
4811   listPtr = (listBoxDef_t*)item->typeData;
4812   if (item->type == ITEM_TYPE_LISTBOX && listPtr) {
4813     listPtr->notselectable = qtrue;
4814   }
4815   return qtrue;
4816 }
4817 
4818 // manually wrapped
ItemParse_wrapped(itemDef_t * item,int handle)4819 qboolean ItemParse_wrapped( itemDef_t *item, int handle ) {
4820   item->window.flags |= WINDOW_WRAPPED;
4821   return qtrue;
4822 }
4823 
4824 // auto wrapped
ItemParse_autowrapped(itemDef_t * item,int handle)4825 qboolean ItemParse_autowrapped( itemDef_t *item, int handle ) {
4826   item->window.flags |= WINDOW_AUTOWRAPPED;
4827   return qtrue;
4828 }
4829 
4830 
4831 // horizontalscroll
ItemParse_horizontalscroll(itemDef_t * item,int handle)4832 qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) {
4833   item->window.flags |= WINDOW_HORIZONTAL;
4834   return qtrue;
4835 }
4836 
4837 // type <integer>
ItemParse_type(itemDef_t * item,int handle)4838 qboolean ItemParse_type( itemDef_t *item, int handle ) {
4839   if (!PC_Int_Parse(handle, &item->type)) {
4840     return qfalse;
4841   }
4842   Item_ValidateTypeData(item);
4843   return qtrue;
4844 }
4845 
4846 // elementwidth, used for listbox image elements
4847 // uses textalignx for storage
ItemParse_elementwidth(itemDef_t * item,int handle)4848 qboolean ItemParse_elementwidth( itemDef_t *item, int handle ) {
4849   listBoxDef_t *listPtr;
4850 
4851   Item_ValidateTypeData(item);
4852   listPtr = (listBoxDef_t*)item->typeData;
4853   if (!PC_Float_Parse(handle, &listPtr->elementWidth)) {
4854     return qfalse;
4855   }
4856   return qtrue;
4857 }
4858 
4859 // elementheight, used for listbox image elements
4860 // uses textaligny for storage
ItemParse_elementheight(itemDef_t * item,int handle)4861 qboolean ItemParse_elementheight( itemDef_t *item, int handle ) {
4862   listBoxDef_t *listPtr;
4863 
4864   Item_ValidateTypeData(item);
4865   listPtr = (listBoxDef_t*)item->typeData;
4866   if (!PC_Float_Parse(handle, &listPtr->elementHeight)) {
4867     return qfalse;
4868   }
4869   return qtrue;
4870 }
4871 
4872 // feeder <float>
ItemParse_feeder(itemDef_t * item,int handle)4873 qboolean ItemParse_feeder( itemDef_t *item, int handle ) {
4874   if (!PC_Float_Parse(handle, &item->special)) {
4875     return qfalse;
4876   }
4877   return qtrue;
4878 }
4879 
4880 // elementtype, used to specify what type of elements a listbox contains
4881 // uses textstyle for storage
ItemParse_elementtype(itemDef_t * item,int handle)4882 qboolean ItemParse_elementtype( itemDef_t *item, int handle ) {
4883   listBoxDef_t *listPtr;
4884 
4885   Item_ValidateTypeData(item);
4886   if (!item->typeData)
4887     return qfalse;
4888   listPtr = (listBoxDef_t*)item->typeData;
4889   if (!PC_Int_Parse(handle, &listPtr->elementStyle)) {
4890     return qfalse;
4891   }
4892   return qtrue;
4893 }
4894 
4895 // columns sets a number of columns and an x pos and width per..
ItemParse_columns(itemDef_t * item,int handle)4896 qboolean ItemParse_columns( itemDef_t *item, int handle ) {
4897   int num, i;
4898   listBoxDef_t *listPtr;
4899 
4900   Item_ValidateTypeData(item);
4901   if (!item->typeData)
4902     return qfalse;
4903   listPtr = (listBoxDef_t*)item->typeData;
4904   if (PC_Int_Parse(handle, &num)) {
4905     if (num > MAX_LB_COLUMNS) {
4906       num = MAX_LB_COLUMNS;
4907     }
4908     listPtr->numColumns = num;
4909     for (i = 0; i < num; i++) {
4910       int pos, width, maxChars, align;
4911 
4912       if( PC_Int_Parse( handle, &pos ) &&
4913           PC_Int_Parse( handle, &width ) &&
4914           PC_Int_Parse( handle, &maxChars ) &&
4915           PC_Int_Parse( handle, &align ) )
4916       {
4917         listPtr->columnInfo[i].pos = pos;
4918         listPtr->columnInfo[i].width = width;
4919         listPtr->columnInfo[i].maxChars = maxChars;
4920         listPtr->columnInfo[i].align = align;
4921       } else {
4922         return qfalse;
4923       }
4924     }
4925   } else {
4926     return qfalse;
4927   }
4928   return qtrue;
4929 }
4930 
ItemParse_border(itemDef_t * item,int handle)4931 qboolean ItemParse_border( itemDef_t *item, int handle ) {
4932   if (!PC_Int_Parse(handle, &item->window.border)) {
4933     return qfalse;
4934   }
4935   return qtrue;
4936 }
4937 
ItemParse_bordersize(itemDef_t * item,int handle)4938 qboolean ItemParse_bordersize( itemDef_t *item, int handle ) {
4939   if (!PC_Float_Parse(handle, &item->window.borderSize)) {
4940     return qfalse;
4941   }
4942   return qtrue;
4943 }
4944 
ItemParse_visible(itemDef_t * item,int handle)4945 qboolean ItemParse_visible( itemDef_t *item, int handle ) {
4946   int i;
4947 
4948   if (!PC_Int_Parse(handle, &i)) {
4949     return qfalse;
4950   }
4951   if (i) {
4952     item->window.flags |= WINDOW_VISIBLE;
4953   }
4954   return qtrue;
4955 }
4956 
ItemParse_ownerdraw(itemDef_t * item,int handle)4957 qboolean ItemParse_ownerdraw( itemDef_t *item, int handle ) {
4958   if (!PC_Int_Parse(handle, &item->window.ownerDraw)) {
4959     return qfalse;
4960   }
4961   item->type = ITEM_TYPE_OWNERDRAW;
4962   return qtrue;
4963 }
4964 
ItemParse_align(itemDef_t * item,int handle)4965 qboolean ItemParse_align( itemDef_t *item, int handle ) {
4966   if (!PC_Int_Parse(handle, &item->alignment)) {
4967     return qfalse;
4968   }
4969   return qtrue;
4970 }
4971 
ItemParse_textalign(itemDef_t * item,int handle)4972 qboolean ItemParse_textalign( itemDef_t *item, int handle ) {
4973   if (!PC_Int_Parse(handle, &item->textalignment)) {
4974     return qfalse;
4975   }
4976   return qtrue;
4977 }
4978 
ItemParse_textalignx(itemDef_t * item,int handle)4979 qboolean ItemParse_textalignx( itemDef_t *item, int handle ) {
4980   if (!PC_Float_Parse(handle, &item->textalignx)) {
4981     return qfalse;
4982   }
4983   return qtrue;
4984 }
4985 
ItemParse_textaligny(itemDef_t * item,int handle)4986 qboolean ItemParse_textaligny( itemDef_t *item, int handle ) {
4987   if (!PC_Float_Parse(handle, &item->textaligny)) {
4988     return qfalse;
4989   }
4990   return qtrue;
4991 }
4992 
ItemParse_textscale(itemDef_t * item,int handle)4993 qboolean ItemParse_textscale( itemDef_t *item, int handle ) {
4994   if (!PC_Float_Parse(handle, &item->textscale)) {
4995     return qfalse;
4996   }
4997   return qtrue;
4998 }
4999 
ItemParse_textstyle(itemDef_t * item,int handle)5000 qboolean ItemParse_textstyle( itemDef_t *item, int handle ) {
5001   if (!PC_Int_Parse(handle, &item->textStyle)) {
5002     return qfalse;
5003   }
5004   return qtrue;
5005 }
5006 
ItemParse_backcolor(itemDef_t * item,int handle)5007 qboolean ItemParse_backcolor( itemDef_t *item, int handle ) {
5008   int i;
5009   float f;
5010 
5011   for (i = 0; i < 4; i++) {
5012     if (!PC_Float_Parse(handle, &f)) {
5013       return qfalse;
5014     }
5015     item->window.backColor[i]  = f;
5016   }
5017   return qtrue;
5018 }
5019 
ItemParse_forecolor(itemDef_t * item,int handle)5020 qboolean ItemParse_forecolor( itemDef_t *item, int handle ) {
5021   int i;
5022   float f;
5023 
5024   for (i = 0; i < 4; i++) {
5025     if (!PC_Float_Parse(handle, &f)) {
5026       return qfalse;
5027     }
5028     item->window.foreColor[i]  = f;
5029     item->window.flags |= WINDOW_FORECOLORSET;
5030   }
5031   return qtrue;
5032 }
5033 
ItemParse_bordercolor(itemDef_t * item,int handle)5034 qboolean ItemParse_bordercolor( itemDef_t *item, int handle ) {
5035   int i;
5036   float f;
5037 
5038   for (i = 0; i < 4; i++) {
5039     if (!PC_Float_Parse(handle, &f)) {
5040       return qfalse;
5041     }
5042     item->window.borderColor[i]  = f;
5043   }
5044   return qtrue;
5045 }
5046 
ItemParse_outlinecolor(itemDef_t * item,int handle)5047 qboolean ItemParse_outlinecolor( itemDef_t *item, int handle ) {
5048   if (!PC_Color_Parse(handle, &item->window.outlineColor)){
5049     return qfalse;
5050   }
5051   return qtrue;
5052 }
5053 
ItemParse_background(itemDef_t * item,int handle)5054 qboolean ItemParse_background( itemDef_t *item, int handle ) {
5055   const char *temp;
5056 
5057   if (!PC_String_Parse(handle, &temp)) {
5058     return qfalse;
5059   }
5060   item->window.background = DC->registerShaderNoMip(temp);
5061   return qtrue;
5062 }
5063 
ItemParse_cinematic(itemDef_t * item,int handle)5064 qboolean ItemParse_cinematic( itemDef_t *item, int handle ) {
5065   if (!PC_String_Parse(handle, &item->window.cinematicName)) {
5066     return qfalse;
5067   }
5068   return qtrue;
5069 }
5070 
ItemParse_doubleClick(itemDef_t * item,int handle)5071 qboolean ItemParse_doubleClick( itemDef_t *item, int handle ) {
5072   listBoxDef_t *listPtr;
5073 
5074   Item_ValidateTypeData(item);
5075   if (!item->typeData) {
5076     return qfalse;
5077   }
5078 
5079   listPtr = (listBoxDef_t*)item->typeData;
5080 
5081   if (!PC_Script_Parse(handle, &listPtr->doubleClick)) {
5082     return qfalse;
5083   }
5084   return qtrue;
5085 }
5086 
ItemParse_onFocus(itemDef_t * item,int handle)5087 qboolean ItemParse_onFocus( itemDef_t *item, int handle ) {
5088   if (!PC_Script_Parse(handle, &item->onFocus)) {
5089     return qfalse;
5090   }
5091   return qtrue;
5092 }
5093 
ItemParse_leaveFocus(itemDef_t * item,int handle)5094 qboolean ItemParse_leaveFocus( itemDef_t *item, int handle ) {
5095   if (!PC_Script_Parse(handle, &item->leaveFocus)) {
5096     return qfalse;
5097   }
5098   return qtrue;
5099 }
5100 
ItemParse_mouseEnter(itemDef_t * item,int handle)5101 qboolean ItemParse_mouseEnter( itemDef_t *item, int handle ) {
5102   if (!PC_Script_Parse(handle, &item->mouseEnter)) {
5103     return qfalse;
5104   }
5105   return qtrue;
5106 }
5107 
ItemParse_mouseExit(itemDef_t * item,int handle)5108 qboolean ItemParse_mouseExit( itemDef_t *item, int handle ) {
5109   if (!PC_Script_Parse(handle, &item->mouseExit)) {
5110     return qfalse;
5111   }
5112   return qtrue;
5113 }
5114 
ItemParse_mouseEnterText(itemDef_t * item,int handle)5115 qboolean ItemParse_mouseEnterText( itemDef_t *item, int handle ) {
5116   if (!PC_Script_Parse(handle, &item->mouseEnterText)) {
5117     return qfalse;
5118   }
5119   return qtrue;
5120 }
5121 
ItemParse_mouseExitText(itemDef_t * item,int handle)5122 qboolean ItemParse_mouseExitText( itemDef_t *item, int handle ) {
5123   if (!PC_Script_Parse(handle, &item->mouseExitText)) {
5124     return qfalse;
5125   }
5126   return qtrue;
5127 }
5128 
ItemParse_action(itemDef_t * item,int handle)5129 qboolean ItemParse_action( itemDef_t *item, int handle ) {
5130   if (!PC_Script_Parse(handle, &item->action)) {
5131     return qfalse;
5132   }
5133   return qtrue;
5134 }
5135 
ItemParse_special(itemDef_t * item,int handle)5136 qboolean ItemParse_special( itemDef_t *item, int handle ) {
5137   if (!PC_Float_Parse(handle, &item->special)) {
5138     return qfalse;
5139   }
5140   return qtrue;
5141 }
5142 
ItemParse_cvarTest(itemDef_t * item,int handle)5143 qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) {
5144   if (!PC_String_Parse(handle, &item->cvarTest)) {
5145     return qfalse;
5146   }
5147   return qtrue;
5148 }
5149 
ItemParse_cvar(itemDef_t * item,int handle)5150 qboolean ItemParse_cvar( itemDef_t *item, int handle ) {
5151   editFieldDef_t *editPtr;
5152 
5153   Item_ValidateTypeData(item);
5154   if (!PC_String_Parse(handle, &item->cvar)) {
5155     return qfalse;
5156   }
5157   if (item->typeData) {
5158     editPtr = (editFieldDef_t*)item->typeData;
5159     editPtr->minVal = -1;
5160     editPtr->maxVal = -1;
5161     editPtr->defVal = -1;
5162   }
5163   return qtrue;
5164 }
5165 
ItemParse_maxChars(itemDef_t * item,int handle)5166 qboolean ItemParse_maxChars( itemDef_t *item, int handle ) {
5167   editFieldDef_t *editPtr;
5168   int maxChars;
5169 
5170   Item_ValidateTypeData(item);
5171   if (!item->typeData)
5172     return qfalse;
5173 
5174   if (!PC_Int_Parse(handle, &maxChars)) {
5175     return qfalse;
5176   }
5177   editPtr = (editFieldDef_t*)item->typeData;
5178   editPtr->maxChars = maxChars;
5179   return qtrue;
5180 }
5181 
ItemParse_maxPaintChars(itemDef_t * item,int handle)5182 qboolean ItemParse_maxPaintChars( itemDef_t *item, int handle ) {
5183   editFieldDef_t *editPtr;
5184   int maxChars;
5185 
5186   Item_ValidateTypeData(item);
5187   if (!item->typeData)
5188     return qfalse;
5189 
5190   if (!PC_Int_Parse(handle, &maxChars)) {
5191     return qfalse;
5192   }
5193   editPtr = (editFieldDef_t*)item->typeData;
5194   editPtr->maxPaintChars = maxChars;
5195   return qtrue;
5196 }
5197 
5198 
5199 
ItemParse_cvarFloat(itemDef_t * item,int handle)5200 qboolean ItemParse_cvarFloat( itemDef_t *item, int handle ) {
5201   editFieldDef_t *editPtr;
5202 
5203   Item_ValidateTypeData(item);
5204   if (!item->typeData)
5205     return qfalse;
5206   editPtr = (editFieldDef_t*)item->typeData;
5207   if (PC_String_Parse(handle, &item->cvar) &&
5208     PC_Float_Parse(handle, &editPtr->defVal) &&
5209     PC_Float_Parse(handle, &editPtr->minVal) &&
5210     PC_Float_Parse(handle, &editPtr->maxVal)) {
5211     return qtrue;
5212   }
5213   return qfalse;
5214 }
5215 
ItemParse_cvarStrList(itemDef_t * item,int handle)5216 qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) {
5217   pc_token_t token;
5218   multiDef_t *multiPtr;
5219   int pass;
5220 
5221   Item_ValidateTypeData(item);
5222   if (!item->typeData)
5223     return qfalse;
5224   multiPtr = (multiDef_t*)item->typeData;
5225   multiPtr->count = 0;
5226   multiPtr->strDef = qtrue;
5227 
5228   if (!trap_PC_ReadToken(handle, &token))
5229     return qfalse;
5230   if (*token.string != '{') {
5231     return qfalse;
5232   }
5233 
5234   pass = 0;
5235   while ( 1 ) {
5236     if (!trap_PC_ReadToken(handle, &token)) {
5237       PC_SourceError(handle, "end of file inside menu item\n");
5238       return qfalse;
5239     }
5240 
5241     if (*token.string == '}') {
5242       return qtrue;
5243     }
5244 
5245     if (*token.string == ',' || *token.string == ';') {
5246       continue;
5247     }
5248 
5249     if (pass == 0) {
5250       multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
5251       pass = 1;
5252     } else {
5253       multiPtr->cvarStr[multiPtr->count] = String_Alloc(token.string);
5254       pass = 0;
5255       multiPtr->count++;
5256       if (multiPtr->count >= MAX_MULTI_CVARS) {
5257         return qfalse;
5258       }
5259     }
5260 
5261   }
5262   return qfalse;  // bk001205 - LCC missing return value
5263 }
5264 
ItemParse_cvarFloatList(itemDef_t * item,int handle)5265 qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) {
5266   pc_token_t token;
5267   multiDef_t *multiPtr;
5268 
5269   Item_ValidateTypeData(item);
5270   if (!item->typeData)
5271     return qfalse;
5272   multiPtr = (multiDef_t*)item->typeData;
5273   multiPtr->count = 0;
5274   multiPtr->strDef = qfalse;
5275 
5276   if (!trap_PC_ReadToken(handle, &token))
5277     return qfalse;
5278   if (*token.string != '{') {
5279     return qfalse;
5280   }
5281 
5282   while ( 1 ) {
5283     if (!trap_PC_ReadToken(handle, &token)) {
5284       PC_SourceError(handle, "end of file inside menu item\n");
5285       return qfalse;
5286     }
5287 
5288     if (*token.string == '}') {
5289       return qtrue;
5290     }
5291 
5292     if (*token.string == ',' || *token.string == ';') {
5293       continue;
5294     }
5295 
5296     multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
5297     if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count])) {
5298       return qfalse;
5299     }
5300 
5301     multiPtr->count++;
5302     if (multiPtr->count >= MAX_MULTI_CVARS) {
5303       return qfalse;
5304     }
5305 
5306   }
5307   return qfalse;  // bk001205 - LCC missing return value
5308 }
5309 
5310 
5311 
ItemParse_addColorRange(itemDef_t * item,int handle)5312 qboolean ItemParse_addColorRange( itemDef_t *item, int handle ) {
5313   colorRangeDef_t color;
5314 
5315   if (PC_Float_Parse(handle, &color.low) &&
5316     PC_Float_Parse(handle, &color.high) &&
5317     PC_Color_Parse(handle, &color.color) ) {
5318     if (item->numColors < MAX_COLOR_RANGES) {
5319       memcpy(&item->colorRanges[item->numColors], &color, sizeof(color));
5320       item->numColors++;
5321     }
5322     return qtrue;
5323   }
5324   return qfalse;
5325 }
5326 
ItemParse_ownerdrawFlag(itemDef_t * item,int handle)5327 qboolean ItemParse_ownerdrawFlag( itemDef_t *item, int handle ) {
5328   int i;
5329   if (!PC_Int_Parse(handle, &i)) {
5330     return qfalse;
5331   }
5332   item->window.ownerDrawFlags |= i;
5333   return qtrue;
5334 }
5335 
ItemParse_enableCvar(itemDef_t * item,int handle)5336 qboolean ItemParse_enableCvar( itemDef_t *item, int handle ) {
5337   if (PC_Script_Parse(handle, &item->enableCvar)) {
5338     item->cvarFlags = CVAR_ENABLE;
5339     return qtrue;
5340   }
5341   return qfalse;
5342 }
5343 
ItemParse_disableCvar(itemDef_t * item,int handle)5344 qboolean ItemParse_disableCvar( itemDef_t *item, int handle ) {
5345   if (PC_Script_Parse(handle, &item->enableCvar)) {
5346     item->cvarFlags = CVAR_DISABLE;
5347     return qtrue;
5348   }
5349   return qfalse;
5350 }
5351 
ItemParse_showCvar(itemDef_t * item,int handle)5352 qboolean ItemParse_showCvar( itemDef_t *item, int handle ) {
5353   if (PC_Script_Parse(handle, &item->enableCvar)) {
5354     item->cvarFlags = CVAR_SHOW;
5355     return qtrue;
5356   }
5357   return qfalse;
5358 }
5359 
ItemParse_hideCvar(itemDef_t * item,int handle)5360 qboolean ItemParse_hideCvar( itemDef_t *item, int handle ) {
5361   if (PC_Script_Parse(handle, &item->enableCvar)) {
5362     item->cvarFlags = CVAR_HIDE;
5363     return qtrue;
5364   }
5365   return qfalse;
5366 }
5367 
5368 
5369 keywordHash_t itemParseKeywords[] = {
5370   {"name", ItemParse_name, NULL},
5371   {"text", ItemParse_text, NULL},
5372   {"group", ItemParse_group, NULL},
5373   {"asset_model", ItemParse_asset_model, NULL},
5374   {"asset_shader", ItemParse_asset_shader, NULL},
5375   {"model_origin", ItemParse_model_origin, NULL},
5376   {"model_fovx", ItemParse_model_fovx, NULL},
5377   {"model_fovy", ItemParse_model_fovy, NULL},
5378   {"model_rotation", ItemParse_model_rotation, NULL},
5379   {"model_angle", ItemParse_model_angle, NULL},
5380   {"rect", ItemParse_rect, NULL},
5381   {"style", ItemParse_style, NULL},
5382   {"decoration", ItemParse_decoration, NULL},
5383   {"notselectable", ItemParse_notselectable, NULL},
5384   {"wrapped", ItemParse_wrapped, NULL},
5385   {"autowrapped", ItemParse_autowrapped, NULL},
5386   {"horizontalscroll", ItemParse_horizontalscroll, NULL},
5387   {"type", ItemParse_type, NULL},
5388   {"elementwidth", ItemParse_elementwidth, NULL},
5389   {"elementheight", ItemParse_elementheight, NULL},
5390   {"feeder", ItemParse_feeder, NULL},
5391   {"elementtype", ItemParse_elementtype, NULL},
5392   {"columns", ItemParse_columns, NULL},
5393   {"border", ItemParse_border, NULL},
5394   {"bordersize", ItemParse_bordersize, NULL},
5395   {"visible", ItemParse_visible, NULL},
5396   {"ownerdraw", ItemParse_ownerdraw, NULL},
5397   {"align", ItemParse_align, NULL},
5398   {"textalign", ItemParse_textalign, NULL},
5399   {"textalignx", ItemParse_textalignx, NULL},
5400   {"textaligny", ItemParse_textaligny, NULL},
5401   {"textscale", ItemParse_textscale, NULL},
5402   {"textstyle", ItemParse_textstyle, NULL},
5403   {"backcolor", ItemParse_backcolor, NULL},
5404   {"forecolor", ItemParse_forecolor, NULL},
5405   {"bordercolor", ItemParse_bordercolor, NULL},
5406   {"outlinecolor", ItemParse_outlinecolor, NULL},
5407   {"background", ItemParse_background, NULL},
5408   {"onFocus", ItemParse_onFocus, NULL},
5409   {"leaveFocus", ItemParse_leaveFocus, NULL},
5410   {"mouseEnter", ItemParse_mouseEnter, NULL},
5411   {"mouseExit", ItemParse_mouseExit, NULL},
5412   {"mouseEnterText", ItemParse_mouseEnterText, NULL},
5413   {"mouseExitText", ItemParse_mouseExitText, NULL},
5414   {"action", ItemParse_action, NULL},
5415   {"special", ItemParse_special, NULL},
5416   {"cvar", ItemParse_cvar, NULL},
5417   {"maxChars", ItemParse_maxChars, NULL},
5418   {"maxPaintChars", ItemParse_maxPaintChars, NULL},
5419   {"focusSound", ItemParse_focusSound, NULL},
5420   {"cvarFloat", ItemParse_cvarFloat, NULL},
5421   {"cvarStrList", ItemParse_cvarStrList, NULL},
5422   {"cvarFloatList", ItemParse_cvarFloatList, NULL},
5423   {"addColorRange", ItemParse_addColorRange, NULL},
5424   {"ownerdrawFlag", ItemParse_ownerdrawFlag, NULL},
5425   {"enableCvar", ItemParse_enableCvar, NULL},
5426   {"cvarTest", ItemParse_cvarTest, NULL},
5427   {"disableCvar", ItemParse_disableCvar, NULL},
5428   {"showCvar", ItemParse_showCvar, NULL},
5429   {"hideCvar", ItemParse_hideCvar, NULL},
5430   {"cinematic", ItemParse_cinematic, NULL},
5431   {"doubleclick", ItemParse_doubleClick, NULL},
5432   {NULL, voidFunction2, NULL}
5433 };
5434 
5435 keywordHash_t *itemParseKeywordHash[KEYWORDHASH_SIZE];
5436 
5437 /*
5438 ===============
5439 Item_SetupKeywordHash
5440 ===============
5441 */
Item_SetupKeywordHash(void)5442 void Item_SetupKeywordHash( void )
5443 {
5444   int i;
5445 
5446   memset( itemParseKeywordHash, 0, sizeof( itemParseKeywordHash ) );
5447 
5448   for( i = 0; itemParseKeywords[ i ].keyword; i++ )
5449     KeywordHash_Add( itemParseKeywordHash, &itemParseKeywords[ i ] );
5450 }
5451 
5452 /*
5453 ===============
5454 Item_Parse
5455 ===============
5456 */
Item_Parse(int handle,itemDef_t * item)5457 qboolean Item_Parse(int handle, itemDef_t *item) {
5458   pc_token_t token;
5459   keywordHash_t *key;
5460 
5461 
5462   if (!trap_PC_ReadToken(handle, &token))
5463     return qfalse;
5464   if (*token.string != '{') {
5465     return qfalse;
5466   }
5467   while ( 1 ) {
5468     if (!trap_PC_ReadToken(handle, &token)) {
5469       PC_SourceError(handle, "end of file inside menu item\n");
5470       return qfalse;
5471     }
5472 
5473     if (*token.string == '}') {
5474       return qtrue;
5475     }
5476 
5477     key = KeywordHash_Find(itemParseKeywordHash, token.string);
5478     if (!key) {
5479       PC_SourceError(handle, "unknown menu item keyword %s", token.string);
5480       continue;
5481     }
5482     if ( !key->func(item, handle) ) {
5483       PC_SourceError(handle, "couldn't parse menu item keyword %s", token.string);
5484       return qfalse;
5485     }
5486   }
5487   return qfalse;  // bk001205 - LCC missing return value
5488 }
5489 
5490 
5491 // Item_InitControls
5492 // init's special control types
Item_InitControls(itemDef_t * item)5493 void Item_InitControls(itemDef_t *item) {
5494   if (item == NULL) {
5495     return;
5496   }
5497   if (item->type == ITEM_TYPE_LISTBOX) {
5498     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
5499     item->cursorPos = 0;
5500     if (listPtr) {
5501       listPtr->cursorPos = 0;
5502       listPtr->startPos = 0;
5503       listPtr->endPos = 0;
5504       listPtr->cursorPos = 0;
5505     }
5506   }
5507 }
5508 
5509 /*
5510 ===============
5511 Menu Keyword Parse functions
5512 ===============
5513 */
5514 
MenuParse_font(itemDef_t * item,int handle)5515 qboolean MenuParse_font( itemDef_t *item, int handle ) {
5516   menuDef_t *menu = (menuDef_t*)item;
5517   if (!PC_String_Parse(handle, &menu->font)) {
5518     return qfalse;
5519   }
5520   if (!DC->Assets.fontRegistered) {
5521     DC->registerFont(menu->font, 48, &DC->Assets.textFont);
5522     DC->Assets.fontRegistered = qtrue;
5523   }
5524   return qtrue;
5525 }
5526 
MenuParse_name(itemDef_t * item,int handle)5527 qboolean MenuParse_name( itemDef_t *item, int handle ) {
5528   menuDef_t *menu = (menuDef_t*)item;
5529   if (!PC_String_Parse(handle, &menu->window.name)) {
5530     return qfalse;
5531   }
5532   if (Q_stricmp(menu->window.name, "main") == 0) {
5533     // default main as having focus
5534     //menu->window.flags |= WINDOW_HASFOCUS;
5535   }
5536   return qtrue;
5537 }
5538 
MenuParse_fullscreen(itemDef_t * item,int handle)5539 qboolean MenuParse_fullscreen( itemDef_t *item, int handle ) {
5540   menuDef_t *menu = (menuDef_t*)item;
5541   if (!PC_Int_Parse(handle, (int*) &menu->fullScreen)) { // bk001206 - cast qboolean
5542     return qfalse;
5543   }
5544   return qtrue;
5545 }
5546 
MenuParse_rect(itemDef_t * item,int handle)5547 qboolean MenuParse_rect( itemDef_t *item, int handle ) {
5548   menuDef_t *menu = (menuDef_t*)item;
5549   if (!PC_Rect_Parse(handle, &menu->window.rect)) {
5550     return qfalse;
5551   }
5552   return qtrue;
5553 }
5554 
MenuParse_style(itemDef_t * item,int handle)5555 qboolean MenuParse_style( itemDef_t *item, int handle ) {
5556   menuDef_t *menu = (menuDef_t*)item;
5557   if (!PC_Int_Parse(handle, &menu->window.style)) {
5558     return qfalse;
5559   }
5560   return qtrue;
5561 }
5562 
MenuParse_visible(itemDef_t * item,int handle)5563 qboolean MenuParse_visible( itemDef_t *item, int handle ) {
5564   int i;
5565   menuDef_t *menu = (menuDef_t*)item;
5566 
5567   if (!PC_Int_Parse(handle, &i)) {
5568     return qfalse;
5569   }
5570   if (i) {
5571     menu->window.flags |= WINDOW_VISIBLE;
5572   }
5573   return qtrue;
5574 }
5575 
MenuParse_onOpen(itemDef_t * item,int handle)5576 qboolean MenuParse_onOpen( itemDef_t *item, int handle ) {
5577   menuDef_t *menu = (menuDef_t*)item;
5578   if (!PC_Script_Parse(handle, &menu->onOpen)) {
5579     return qfalse;
5580   }
5581   return qtrue;
5582 }
5583 
MenuParse_onClose(itemDef_t * item,int handle)5584 qboolean MenuParse_onClose( itemDef_t *item, int handle ) {
5585   menuDef_t *menu = (menuDef_t*)item;
5586   if (!PC_Script_Parse(handle, &menu->onClose)) {
5587     return qfalse;
5588   }
5589   return qtrue;
5590 }
5591 
MenuParse_onESC(itemDef_t * item,int handle)5592 qboolean MenuParse_onESC( itemDef_t *item, int handle ) {
5593   menuDef_t *menu = (menuDef_t*)item;
5594   if (!PC_Script_Parse(handle, &menu->onESC)) {
5595     return qfalse;
5596   }
5597   return qtrue;
5598 }
5599 
5600 
5601 
MenuParse_border(itemDef_t * item,int handle)5602 qboolean MenuParse_border( itemDef_t *item, int handle ) {
5603   menuDef_t *menu = (menuDef_t*)item;
5604   if (!PC_Int_Parse(handle, &menu->window.border)) {
5605     return qfalse;
5606   }
5607   return qtrue;
5608 }
5609 
MenuParse_borderSize(itemDef_t * item,int handle)5610 qboolean MenuParse_borderSize( itemDef_t *item, int handle ) {
5611   menuDef_t *menu = (menuDef_t*)item;
5612   if (!PC_Float_Parse(handle, &menu->window.borderSize)) {
5613     return qfalse;
5614   }
5615   return qtrue;
5616 }
5617 
MenuParse_backcolor(itemDef_t * item,int handle)5618 qboolean MenuParse_backcolor( itemDef_t *item, int handle ) {
5619   int i;
5620   float f;
5621   menuDef_t *menu = (menuDef_t*)item;
5622 
5623   for (i = 0; i < 4; i++) {
5624     if (!PC_Float_Parse(handle, &f)) {
5625       return qfalse;
5626     }
5627     menu->window.backColor[i]  = f;
5628   }
5629   return qtrue;
5630 }
5631 
MenuParse_forecolor(itemDef_t * item,int handle)5632 qboolean MenuParse_forecolor( itemDef_t *item, int handle ) {
5633   int i;
5634   float f;
5635   menuDef_t *menu = (menuDef_t*)item;
5636 
5637   for (i = 0; i < 4; i++) {
5638     if (!PC_Float_Parse(handle, &f)) {
5639       return qfalse;
5640     }
5641     menu->window.foreColor[i]  = f;
5642     menu->window.flags |= WINDOW_FORECOLORSET;
5643   }
5644   return qtrue;
5645 }
5646 
MenuParse_bordercolor(itemDef_t * item,int handle)5647 qboolean MenuParse_bordercolor( itemDef_t *item, int handle ) {
5648   int i;
5649   float f;
5650   menuDef_t *menu = (menuDef_t*)item;
5651 
5652   for (i = 0; i < 4; i++) {
5653     if (!PC_Float_Parse(handle, &f)) {
5654       return qfalse;
5655     }
5656     menu->window.borderColor[i]  = f;
5657   }
5658   return qtrue;
5659 }
5660 
MenuParse_focuscolor(itemDef_t * item,int handle)5661 qboolean MenuParse_focuscolor( itemDef_t *item, int handle ) {
5662   int i;
5663   float f;
5664   menuDef_t *menu = (menuDef_t*)item;
5665 
5666   for (i = 0; i < 4; i++) {
5667     if (!PC_Float_Parse(handle, &f)) {
5668       return qfalse;
5669     }
5670     menu->focusColor[i]  = f;
5671   }
5672   return qtrue;
5673 }
5674 
MenuParse_disablecolor(itemDef_t * item,int handle)5675 qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) {
5676   int i;
5677   float f;
5678   menuDef_t *menu = (menuDef_t*)item;
5679   for (i = 0; i < 4; i++) {
5680     if (!PC_Float_Parse(handle, &f)) {
5681       return qfalse;
5682     }
5683     menu->disableColor[i]  = f;
5684   }
5685   return qtrue;
5686 }
5687 
5688 
MenuParse_outlinecolor(itemDef_t * item,int handle)5689 qboolean MenuParse_outlinecolor( itemDef_t *item, int handle ) {
5690   menuDef_t *menu = (menuDef_t*)item;
5691   if (!PC_Color_Parse(handle, &menu->window.outlineColor)){
5692     return qfalse;
5693   }
5694   return qtrue;
5695 }
5696 
MenuParse_background(itemDef_t * item,int handle)5697 qboolean MenuParse_background( itemDef_t *item, int handle ) {
5698   const char *buff;
5699   menuDef_t *menu = (menuDef_t*)item;
5700 
5701   if (!PC_String_Parse(handle, &buff)) {
5702     return qfalse;
5703   }
5704   menu->window.background = DC->registerShaderNoMip(buff);
5705   return qtrue;
5706 }
5707 
MenuParse_cinematic(itemDef_t * item,int handle)5708 qboolean MenuParse_cinematic( itemDef_t *item, int handle ) {
5709   menuDef_t *menu = (menuDef_t*)item;
5710 
5711   if (!PC_String_Parse(handle, &menu->window.cinematicName)) {
5712     return qfalse;
5713   }
5714   return qtrue;
5715 }
5716 
MenuParse_ownerdrawFlag(itemDef_t * item,int handle)5717 qboolean MenuParse_ownerdrawFlag( itemDef_t *item, int handle ) {
5718   int i;
5719   menuDef_t *menu = (menuDef_t*)item;
5720 
5721   if (!PC_Int_Parse(handle, &i)) {
5722     return qfalse;
5723   }
5724   menu->window.ownerDrawFlags |= i;
5725   return qtrue;
5726 }
5727 
MenuParse_ownerdraw(itemDef_t * item,int handle)5728 qboolean MenuParse_ownerdraw( itemDef_t *item, int handle ) {
5729   menuDef_t *menu = (menuDef_t*)item;
5730 
5731   if (!PC_Int_Parse(handle, &menu->window.ownerDraw)) {
5732     return qfalse;
5733   }
5734   return qtrue;
5735 }
5736 
5737 
5738 // decoration
MenuParse_popup(itemDef_t * item,int handle)5739 qboolean MenuParse_popup( itemDef_t *item, int handle ) {
5740   menuDef_t *menu = (menuDef_t*)item;
5741   menu->window.flags |= WINDOW_POPUP;
5742   return qtrue;
5743 }
5744 
5745 
MenuParse_outOfBounds(itemDef_t * item,int handle)5746 qboolean MenuParse_outOfBounds( itemDef_t *item, int handle ) {
5747   menuDef_t *menu = (menuDef_t*)item;
5748 
5749   menu->window.flags |= WINDOW_OOB_CLICK;
5750   return qtrue;
5751 }
5752 
MenuParse_soundLoop(itemDef_t * item,int handle)5753 qboolean MenuParse_soundLoop( itemDef_t *item, int handle ) {
5754   menuDef_t *menu = (menuDef_t*)item;
5755 
5756   if (!PC_String_Parse(handle, &menu->soundName)) {
5757     return qfalse;
5758   }
5759   return qtrue;
5760 }
5761 
MenuParse_fadeClamp(itemDef_t * item,int handle)5762 qboolean MenuParse_fadeClamp( itemDef_t *item, int handle ) {
5763   menuDef_t *menu = (menuDef_t*)item;
5764 
5765   if (!PC_Float_Parse(handle, &menu->fadeClamp)) {
5766     return qfalse;
5767   }
5768   return qtrue;
5769 }
5770 
MenuParse_fadeAmount(itemDef_t * item,int handle)5771 qboolean MenuParse_fadeAmount( itemDef_t *item, int handle ) {
5772   menuDef_t *menu = (menuDef_t*)item;
5773 
5774   if (!PC_Float_Parse(handle, &menu->fadeAmount)) {
5775     return qfalse;
5776   }
5777   return qtrue;
5778 }
5779 
5780 
MenuParse_fadeCycle(itemDef_t * item,int handle)5781 qboolean MenuParse_fadeCycle( itemDef_t *item, int handle ) {
5782   menuDef_t *menu = (menuDef_t*)item;
5783 
5784   if (!PC_Int_Parse(handle, &menu->fadeCycle)) {
5785     return qfalse;
5786   }
5787   return qtrue;
5788 }
5789 
5790 
MenuParse_itemDef(itemDef_t * item,int handle)5791 qboolean MenuParse_itemDef( itemDef_t *item, int handle ) {
5792   menuDef_t *menu = (menuDef_t*)item;
5793   if (menu->itemCount < MAX_MENUITEMS) {
5794     menu->items[menu->itemCount] = UI_Alloc(sizeof(itemDef_t));
5795     Item_Init(menu->items[menu->itemCount]);
5796     if (!Item_Parse(handle, menu->items[menu->itemCount])) {
5797       return qfalse;
5798     }
5799     Item_InitControls(menu->items[menu->itemCount]);
5800     menu->items[menu->itemCount++]->parent = menu;
5801   }
5802   return qtrue;
5803 }
5804 
5805 keywordHash_t menuParseKeywords[] = {
5806   {"font", MenuParse_font, NULL},
5807   {"name", MenuParse_name, NULL},
5808   {"fullscreen", MenuParse_fullscreen, NULL},
5809   {"rect", MenuParse_rect, NULL},
5810   {"style", MenuParse_style, NULL},
5811   {"visible", MenuParse_visible, NULL},
5812   {"onOpen", MenuParse_onOpen, NULL},
5813   {"onClose", MenuParse_onClose, NULL},
5814   {"onESC", MenuParse_onESC, NULL},
5815   {"border", MenuParse_border, NULL},
5816   {"borderSize", MenuParse_borderSize, NULL},
5817   {"backcolor", MenuParse_backcolor, NULL},
5818   {"forecolor", MenuParse_forecolor, NULL},
5819   {"bordercolor", MenuParse_bordercolor, NULL},
5820   {"focuscolor", MenuParse_focuscolor, NULL},
5821   {"disablecolor", MenuParse_disablecolor, NULL},
5822   {"outlinecolor", MenuParse_outlinecolor, NULL},
5823   {"background", MenuParse_background, NULL},
5824   {"ownerdraw", MenuParse_ownerdraw, NULL},
5825   {"ownerdrawFlag", MenuParse_ownerdrawFlag, NULL},
5826   {"outOfBoundsClick", MenuParse_outOfBounds, NULL},
5827   {"soundLoop", MenuParse_soundLoop, NULL},
5828   {"itemDef", MenuParse_itemDef, NULL},
5829   {"cinematic", MenuParse_cinematic, NULL},
5830   {"popup", MenuParse_popup, NULL},
5831   {"fadeClamp", MenuParse_fadeClamp, NULL},
5832   {"fadeCycle", MenuParse_fadeCycle, NULL},
5833   {"fadeAmount", MenuParse_fadeAmount, NULL},
5834   {NULL, voidFunction2, NULL}
5835 };
5836 
5837 keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE];
5838 
5839 /*
5840 ===============
5841 Menu_SetupKeywordHash
5842 ===============
5843 */
Menu_SetupKeywordHash(void)5844 void Menu_SetupKeywordHash( void )
5845 {
5846   int i;
5847 
5848   memset( menuParseKeywordHash, 0, sizeof( menuParseKeywordHash ) );
5849 
5850   for(i = 0; menuParseKeywords[ i ].keyword; i++ )
5851     KeywordHash_Add( menuParseKeywordHash, &menuParseKeywords[ i ] );
5852 }
5853 
5854 /*
5855 ===============
5856 Menu_Parse
5857 ===============
5858 */
Menu_Parse(int handle,menuDef_t * menu)5859 qboolean Menu_Parse(int handle, menuDef_t *menu) {
5860   pc_token_t token;
5861   keywordHash_t *key;
5862 
5863   if (!trap_PC_ReadToken(handle, &token))
5864     return qfalse;
5865   if (*token.string != '{') {
5866     return qfalse;
5867   }
5868 
5869   while ( 1 ) {
5870 
5871     memset(&token, 0, sizeof(pc_token_t));
5872     if (!trap_PC_ReadToken(handle, &token)) {
5873       PC_SourceError(handle, "end of file inside menu\n");
5874       return qfalse;
5875     }
5876 
5877     if (*token.string == '}') {
5878       return qtrue;
5879     }
5880 
5881     key = KeywordHash_Find(menuParseKeywordHash, token.string);
5882     if (!key) {
5883       PC_SourceError(handle, "unknown menu keyword %s", token.string);
5884       continue;
5885     }
5886     if ( !key->func((itemDef_t*)menu, handle) ) {
5887       PC_SourceError(handle, "couldn't parse menu keyword %s", token.string);
5888       return qfalse;
5889     }
5890   }
5891   return qfalse;  // bk001205 - LCC missing return value
5892 }
5893 
5894 /*
5895 ===============
5896 Menu_New
5897 ===============
5898 */
Menu_New(int handle)5899 void Menu_New(int handle) {
5900   menuDef_t *menu = &Menus[menuCount];
5901 
5902   if (menuCount < MAX_MENUS) {
5903     Menu_Init(menu);
5904     if (Menu_Parse(handle, menu)) {
5905       Menu_PostParse(menu);
5906       menuCount++;
5907     }
5908   }
5909 }
5910 
Menu_Count(void)5911 int Menu_Count( void ) {
5912   return menuCount;
5913 }
5914 
Menu_PaintAll(void)5915 void Menu_PaintAll( void ) {
5916   int i;
5917   if (captureFunc) {
5918     captureFunc(captureData);
5919   }
5920 
5921   for (i = 0; i < Menu_Count(); i++) {
5922     Menu_Paint(&Menus[i], qfalse);
5923   }
5924 
5925   if (debugMode) {
5926     vec4_t v = {1, 1, 1, 1};
5927     DC->drawText(5, 25, .5, v, va("fps: %f", DC->FPS), 0, 0, 0);
5928   }
5929 }
5930 
Menu_Reset(void)5931 void Menu_Reset( void )
5932 {
5933   menuCount = 0;
5934 }
5935 
Display_GetContext(void)5936 displayContextDef_t *Display_GetContext( void ) {
5937   return DC;
5938 }
5939 
Display_CaptureItem(int x,int y)5940 void *Display_CaptureItem(int x, int y) {
5941   int i;
5942 
5943   for (i = 0; i < menuCount; i++) {
5944     // turn off focus each item
5945     // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
5946     if (Rect_ContainsPoint(&Menus[i].window.rect, x, y)) {
5947       return &Menus[i];
5948     }
5949   }
5950   return NULL;
5951 }
5952 
5953 
5954 // FIXME:
Display_MouseMove(void * p,int x,int y)5955 qboolean Display_MouseMove(void *p, int x, int y) {
5956   int i;
5957   menuDef_t *menu = p;
5958 
5959   if (menu == NULL) {
5960     menu = Menu_GetFocused();
5961     if (menu) {
5962       if (menu->window.flags & WINDOW_POPUP) {
5963         Menu_HandleMouseMove(menu, x, y);
5964         return qtrue;
5965       }
5966     }
5967     for (i = 0; i < menuCount; i++) {
5968       Menu_HandleMouseMove(&Menus[i], x, y);
5969     }
5970   } else {
5971     menu->window.rect.x += x;
5972     menu->window.rect.y += y;
5973     Menu_UpdatePosition(menu);
5974   }
5975   return qtrue;
5976 
5977 }
5978 
Display_CursorType(int x,int y)5979 int Display_CursorType(int x, int y) {
5980   int i;
5981   for (i = 0; i < menuCount; i++) {
5982     rectDef_t r2;
5983     r2.x = Menus[i].window.rect.x - 3;
5984     r2.y = Menus[i].window.rect.y - 3;
5985     r2.w = r2.h = 7;
5986     if (Rect_ContainsPoint(&r2, x, y)) {
5987       return CURSOR_SIZER;
5988     }
5989   }
5990   return CURSOR_ARROW;
5991 }
5992 
5993 
Display_HandleKey(int key,qboolean down,int x,int y)5994 void Display_HandleKey(int key, qboolean down, int x, int y) {
5995   menuDef_t *menu = Display_CaptureItem(x, y);
5996   if (menu == NULL) {
5997     menu = Menu_GetFocused();
5998   }
5999   if (menu) {
6000     Menu_HandleKey(menu, key, down );
6001   }
6002 }
6003 
Window_CacheContents(windowDef_t * window)6004 static void Window_CacheContents(windowDef_t *window) {
6005   if (window) {
6006     if (window->cinematicName) {
6007       int cin = DC->playCinematic(window->cinematicName, 0, 0, 0, 0);
6008       DC->stopCinematic(cin);
6009     }
6010   }
6011 }
6012 
6013 
Item_CacheContents(itemDef_t * item)6014 static void Item_CacheContents(itemDef_t *item) {
6015   if (item) {
6016     Window_CacheContents(&item->window);
6017   }
6018 
6019 }
6020 
Menu_CacheContents(menuDef_t * menu)6021 static void Menu_CacheContents(menuDef_t *menu) {
6022   if (menu) {
6023     int i;
6024     Window_CacheContents(&menu->window);
6025     for (i = 0; i < menu->itemCount; i++) {
6026       Item_CacheContents(menu->items[i]);
6027     }
6028 
6029     if (menu->soundName && *menu->soundName) {
6030       DC->registerSound(menu->soundName, qfalse);
6031     }
6032   }
6033 
6034 }
6035 
Display_CacheAll(void)6036 void Display_CacheAll( void ) {
6037   int i;
6038   for (i = 0; i < menuCount; i++) {
6039     Menu_CacheContents(&Menus[i]);
6040   }
6041 }
6042 
6043 
Menu_OverActiveItem(menuDef_t * menu,float x,float y)6044 static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y) {
6045   if (menu && menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)) {
6046     if (Rect_ContainsPoint(&menu->window.rect, x, y)) {
6047       int i;
6048       for (i = 0; i < menu->itemCount; i++) {
6049         // turn off focus each item
6050         // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
6051 
6052         if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
6053           continue;
6054         }
6055 
6056         if (menu->items[i]->window.flags & WINDOW_DECORATION) {
6057           continue;
6058         }
6059 
6060         if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
6061           itemDef_t *overItem = menu->items[i];
6062           if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
6063             if (Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
6064               return qtrue;
6065             } else {
6066               continue;
6067             }
6068           } else {
6069             return qtrue;
6070           }
6071         }
6072       }
6073 
6074     }
6075   }
6076   return qfalse;
6077 }
6078 
6079