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