1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 
20 //
21 // gui_init.c
22 //
23 
24 #include "gui_local.h"
25 
26 static gui_t			cl_guiList[MAX_GUIS];
27 static guiShared_t		cl_guiSharedInfo[MAX_GUIS];
28 static uint32			cl_numGUI;
29 
30 static uint32			cl_numGUIErrors;
31 static uint32			cl_numGUIWarnings;
32 
33 static uint32			cl_guiRegFrames[MAX_GUIS];
34 static uint32			cl_guiRegTouched[MAX_GUIS];
35 static uint32			cl_guiRegFrameNum;
36 
37 cVar_t	*gui_developer;
38 cVar_t	*gui_debugBounds;
39 cVar_t	*gui_debugScale;
40 cVar_t	*gui_mouseFilter;
41 cVar_t	*gui_mouseSensitivity;
42 
43 /*
44 ================
45 GUI_HashValue
46 
47 String passed to this should be lowercase.
48 FIXME: use this! Though it may be unecessary since nested windows
49 will only be looked up while GUIs are being parsed
50 ================
51 */
GUI_HashValue(const char * name)52 static uint32 GUI_HashValue (const char *name)
53 {
54 	uint32	hashValue;
55 	int		ch, i;
56 
57 	for (i=0, hashValue=0 ; *name ; i++) {
58 		ch = *(name++);
59 		hashValue = hashValue * 33 + ch;
60 	}
61 
62 	return (hashValue + (hashValue >> 5)) & (MAX_GUI_HASH-1);
63 }
64 
65 
66 /*
67 ================
68 GUI_FindGUI
69 ================
70 */
GUI_FindGUI(char * name)71 static gui_t *GUI_FindGUI (char *name)
72 {
73 	gui_t	*gui, *bestMatch;
74 	char	tempName[MAX_QPATH];
75 	uint32	bestNum, i;
76 
77 	// Make sure it's lowercase
78 	Q_strncpyz (tempName, name, sizeof (tempName));
79 	Q_strlwr (tempName);
80 
81 	bestMatch = NULL;
82 	bestNum = 0;
83 
84 	// Look for it
85 	for (i=0, gui=cl_guiList ; i<cl_numGUI ; gui++, i++) {
86 		if (strcmp (gui->name, tempName))
87 			continue;
88 
89 		if (!bestMatch || gui->shared->pathType >= gui->shared->pathType) {
90 			bestMatch = gui;
91 			bestNum = i;
92 		}
93 	}
94 
95 	return bestMatch;
96 }
97 
98 
99 /*
100 ================
101 GUI_FindWindow
102 
103 lowerName must be lowercase!
104 ================
105 */
GUI_FindWindow(gui_t * gui,char * lowerName)106 static gui_t *GUI_FindWindow (gui_t *gui, char *lowerName)
107 {
108 	gui_t	*child, *best;
109 	uint32	i;
110 
111 	// See if it matches
112 	if (!strcmp (lowerName, gui->name))
113 		return gui;
114 
115 	// Recurse down the children
116 	for (i=0, child=gui->childList ; i<gui->numChildren ; child++, i++) {
117 		best = GUI_FindWindow (child, lowerName);
118 		if (best)
119 			return best;
120 	}
121 
122 	return NULL;
123 }
124 
125 
126 /*
127 ===============
128 GUI_FindDefFloat
129 ===============
130 */
GUI_FindDefFloat(gui_t * gui,char * lowerName)131 static short GUI_FindDefFloat (gui_t *gui, char *lowerName)
132 {
133 	defineFloat_t	*flt;
134 	short			i;
135 
136 	for (i=0, flt=gui->s.defFloatList ; i<gui->s.numDefFloats ; flt++, i++) {
137 		if (!strcmp (lowerName, flt->name))
138 			break;
139 	}
140 	if (i == gui->s.numDefFloats)
141 		return -1;
142 
143 	return i;
144 }
145 
146 
147 /*
148 ===============
149 GUI_FindDefVec
150 ===============
151 */
GUI_FindDefVec(gui_t * gui,char * lowerName)152 static short GUI_FindDefVec (gui_t *gui, char *lowerName)
153 {
154 	defineVec_t	*vec;
155 	short		i;
156 
157 	for (i=0, vec=gui->s.defVecList ; i<gui->s.numDefVecs ; vec++, i++) {
158 		if (!strcmp (lowerName, vec->name))
159 			break;
160 	}
161 	if (i == gui->s.numDefVecs)
162 		return -1;
163 
164 	return i;
165 }
166 
167 
168 /*
169 ===============
170 GUI_CvarValidate
171 ===============
172 */
GUI_CvarValidate(const char * name)173 static qBool GUI_CvarValidate (const char *name)
174 {
175 	if (strchr (name, '\\'))
176 		return qFalse;
177 	if (strchr (name, '\"'))
178 		return qFalse;
179 	if (strchr (name, ';'))
180 		return qFalse;
181 
182 	return qTrue;
183 }
184 
185 /*
186 =============================================================================
187 
188 	PARSE HELPERS
189 
190 =============================================================================
191 */
192 
193 /*
194 ==================
195 GUI_PrintPos
196 ==================
197 */
GUI_PrintPos(comPrint_t flags,parse_t * ps,char * fileName,gui_t * gui)198 static void GUI_PrintPos (comPrint_t flags, parse_t *ps, char *fileName, gui_t *gui)
199 {
200 	uint32		line, col;
201 
202 	// Increment tallies
203 	if (flags & PRNT_ERROR)
204 		cl_numGUIErrors++;
205 	else if (flags & PRNT_WARNING)
206 		cl_numGUIWarnings++;
207 
208 	if (ps) {
209 		// Print the position
210 		PS_GetPosition (ps, &line, &col);
211 		if (gui)
212 			Com_Printf (flags, "%s(line #%i col#%i): window '%s':\n", fileName, line, col, gui->name);
213 		else
214 			Com_Printf (flags, "%s(line #%i col#%i):\n", fileName, line, col);
215 		return;
216 	}
217 
218 		// Print the position
219 	Com_Printf (flags, "%s:\n", fileName);
220 }
221 
222 
223 /*
224 ==================
225 GUI_DevPrintPos
226 ==================
227 */
GUI_DevPrintPos(comPrint_t flags,parse_t * ps,char * fileName,gui_t * gui)228 static void GUI_DevPrintPos (comPrint_t flags, parse_t *ps, char *fileName, gui_t *gui)
229 {
230 	if (!gui_developer->intVal && !developer->intVal)
231 		return;
232 
233 	GUI_PrintPos (flags, ps, fileName, gui);
234 }
235 
236 
237 /*
238 ==================
239 GUI_PrintError
240 ==================
241 */
GUI_PrintError(char * fmt,...)242 static void GUI_PrintError (char *fmt, ...)
243 {
244 	va_list		argptr;
245 	char		msg[MAX_COMPRINT];
246 
247 	cl_numGUIErrors++;
248 
249 	// Evaluate args
250 	va_start (argptr, fmt);
251 	vsnprintf (msg, sizeof (msg), fmt, argptr);
252 	va_end (argptr);
253 
254 	// Print
255 	Com_ConPrint (PRNT_ERROR, msg);
256 }
257 
258 
259 /*
260 ==================
261 GUI_PrintWarning
262 ==================
263 */
GUI_PrintWarning(char * fmt,...)264 static void GUI_PrintWarning (char *fmt, ...)
265 {
266 	va_list		argptr;
267 	char		msg[MAX_COMPRINT];
268 
269 	cl_numGUIWarnings++;
270 
271 	// Evaluate args
272 	va_start (argptr, fmt);
273 	vsnprintf (msg, sizeof (msg), fmt, argptr);
274 	va_end (argptr);
275 
276 	// Print
277 	Com_ConPrint (PRNT_WARNING, msg);
278 }
279 
280 
281 /*
282 ==================
283 GUI_DevPrintf
284 ==================
285 */
GUI_DevPrintf(comPrint_t flags,parse_t * ps,char * fileName,gui_t * gui,char * fmt,...)286 static void GUI_DevPrintf (comPrint_t flags, parse_t *ps, char *fileName, gui_t *gui, char *fmt, ...)
287 {
288 	va_list		argptr;
289 	char		msg[MAX_COMPRINT];
290 
291 	if (!gui_developer->intVal && !developer->intVal)
292 		return;
293 
294 	if (flags & (PRNT_ERROR|PRNT_WARNING)) {
295 		if (flags & PRNT_ERROR)
296 			cl_numGUIErrors++;
297 		else if (flags & PRNT_WARNING)
298 			cl_numGUIWarnings++;
299 		GUI_PrintPos (flags, ps, fileName, gui);
300 	}
301 
302 	// Evaluate args
303 	va_start (argptr, fmt);
304 	vsnprintf (msg, sizeof (msg), fmt, argptr);
305 	va_end (argptr);
306 
307 	// Print
308 	Com_ConPrint (flags, msg);
309 }
310 
311 
312 /*
313 ==================
314 GUI_ParseFloatRegister
315 ==================
316 */
GUI_ParseFloatRegister(char * fileName,gui_t * gui,parse_t * ps,char * keyName,floatRegister_t * floatReg,qBool requireValue,float defaultValue)317 static qBool GUI_ParseFloatRegister (char *fileName, gui_t *gui, parse_t *ps, char *keyName, floatRegister_t *floatReg, qBool requireValue, float defaultValue)
318 {
319 	char		source[MAX_PS_TOKCHARS];
320 	float		storage;
321 	char		windowName[MAX_GUI_NAMELEN];
322 	gui_t		*windowPtr;
323 	char		floatName[MAX_GUI_NAMELEN];
324 	short		floatNum;
325 	guiVar_t	*var;
326 	char		*charToken;
327 	char		*p;
328 
329 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &charToken)) {
330 		if (!requireValue) {
331 			floatReg->sourceType = REG_SOURCE_SELF;
332 			floatReg->storage = defaultValue;
333 			return qTrue;
334 		}
335 
336 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
337 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
338 		return qFalse;
339 	}
340 
341 	if (charToken[0] == '$') {
342 		// Parse "[window::]var"
343 		Q_strncpyz (source, &charToken[1], sizeof (source));
344 		p = strstr (source, "::");
345 		if (p) {
346 			if (!*(p+2)) {
347 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
348 				GUI_PrintError ("ERROR: invalid argument for '%s', contains '::' with no flag name!\n", keyName);
349 				return qFalse;
350 			}
351 
352 			// "<window::>var"
353 			Q_strncpyz (windowName, source, sizeof (windowName));
354 			p = strstr (windowName, "::");
355 			*p = '\0';
356 			// "window::<var>"
357 			Q_strncpyz (floatName, p+2, sizeof (floatName));
358 		}
359 		else {
360 			// Default to this window
361 			Q_strncpyz (windowName, gui->name, sizeof (windowName));
362 
363 			// "<var>"
364 			Q_strncpyz (floatName, source, sizeof (floatName));
365 		}
366 
367 		// Check if we're looking for a guiVar
368 		if (!strcmp (windowName, "guivar")) {
369 			// Find the variable
370 			var = GUIVar_Register (floatName, GVT_FLOAT);
371 			if (!var) {
372 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
373 				GUI_PrintError ("ERROR: unable to find guivar '%s'\n", floatName);
374 				return qFalse;
375 			}
376 
377 			floatReg->sourceType = REG_SOURCE_GUIVAR;
378 			floatReg->guiVar = var;
379 			return qTrue;
380 		}
381 		else {
382 			// Find the window
383 			windowPtr = GUI_FindWindow (gui->owner, windowName);
384 			if (!windowPtr) {
385 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
386 				GUI_PrintError ("ERROR: unable to find window '%s'\n", windowName);
387 				return qFalse;
388 			}
389 
390 			// Find the defineFloat
391 			floatNum = GUI_FindDefFloat (windowPtr, floatName);
392 			if (floatNum == -1) {
393 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
394 				GUI_PrintError ("ERROR: unable to find float '%s'\n", floatName);
395 				return qFalse;
396 			}
397 
398 			floatReg->sourceType = REG_SOURCE_DEF;
399 			floatReg->defFloatIndex = floatNum;
400 			floatReg->defFloatWindow = windowPtr;
401 		}
402 
403 		return qTrue;
404 	}
405 
406 	// Not a pointer, use value
407 	PS_UndoParse (ps);
408 	if (!PS_ParseDataType (ps, 0, PSDT_FLOAT, &storage, 1)) {
409 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
410 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
411 		return qFalse;
412 	}
413 
414 	floatReg->sourceType = REG_SOURCE_SELF;
415 	floatReg->storage = storage;
416 	return qTrue;
417 }
418 
419 
420 /*
421 ==================
422 GUI_ParseVectorRegister
423 ==================
424 */
GUI_ParseVectorRegister(char * fileName,gui_t * gui,parse_t * ps,char * keyName,vecRegister_t * vecReg)425 static qBool GUI_ParseVectorRegister (char *fileName, gui_t *gui, parse_t *ps, char *keyName, vecRegister_t *vecReg)
426 {
427 	char		source[MAX_PS_TOKCHARS];
428 	vec4_t		storage;
429 	char		windowName[MAX_GUI_NAMELEN];
430 	gui_t		*windowPtr;
431 	char		vecName[MAX_GUI_NAMELEN];
432 	short		vecNum;
433 	guiVar_t	*var;
434 	char		*charToken;
435 	char		*p;
436 
437 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &charToken)) {
438 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
439 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
440 		return qFalse;
441 	}
442 
443 	if (charToken[0] == '$') {
444 		// Parse "[window::]var"
445 		Q_strncpyz (source, &charToken[1], sizeof (source));
446 		p = strstr (source, "::");
447 		if (p) {
448 			if (!*(p+2)) {
449 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
450 				GUI_PrintError ("ERROR: invalid argument for '%s', contains '::' with no flag name!\n", keyName);
451 				return qFalse;
452 			}
453 
454 			// "<window::>var"
455 			Q_strncpyz (windowName, source, sizeof (windowName));
456 			p = strstr (windowName, "::");
457 			*p = '\0';
458 			// "window::<var>"
459 			Q_strncpyz (vecName, p+2, sizeof (vecName));
460 		}
461 		else {
462 			// Default to this window
463 			Q_strncpyz (windowName, gui->name, sizeof (windowName));
464 
465 			// "<var>"
466 			Q_strncpyz (vecName, source, sizeof (vecName));
467 		}
468 
469 		// Check if we're looking for a guiVar
470 		if (!strcmp (windowName, "guivar")) {
471 			// Find the variable
472 			var = GUIVar_Register (vecName, GVT_VEC);
473 			if (!var) {
474 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
475 				GUI_PrintError ("ERROR: unable to find guivar '%s'\n", vecName);
476 				return qFalse;
477 			}
478 
479 			vecReg->sourceType = REG_SOURCE_GUIVAR;
480 			vecReg->guiVar = var;
481 			return qTrue;
482 		}
483 		else {
484 			// Find the window
485 			windowPtr = GUI_FindWindow (gui->owner, windowName);
486 			if (!windowPtr) {
487 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
488 				GUI_PrintError ("ERROR: unable to find window '%s'\n", windowName);
489 				return qFalse;
490 			}
491 
492 			// Find the defineVec
493 			vecNum = GUI_FindDefVec (windowPtr, vecName);
494 			if (vecNum == -1) {
495 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
496 				GUI_PrintError ("ERROR: unable to find vec '%s'\n", vecName);
497 				return qFalse;
498 			}
499 
500 			vecReg->sourceType = REG_SOURCE_DEF;
501 			vecReg->defVecIndex = vecNum;
502 			vecReg->defVecWindow = windowPtr;
503 		}
504 
505 		return qTrue;
506 	}
507 
508 	// Not a pointer, use value
509 	PS_UndoParse (ps);
510 	if (!PS_ParseDataType (ps, 0, PSDT_FLOAT, &storage, 4)) {
511 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
512 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
513 		return qFalse;
514 	}
515 
516 	vecReg->sourceType = REG_SOURCE_SELF;
517 	Vec4Copy (storage, vecReg->storage);
518 	return qTrue;
519 }
520 
521 /*
522 =============================================================================
523 
524 	KEY->FUNC PARSING
525 
526 =============================================================================
527 */
528 
529 typedef struct guiParseKey_s {
530 	const char		*keyWord;
531 	qBool			(*func) (char *fileName, gui_t *gui, parse_t *ps, char *keyName);
532 } guiParseKey_t;
533 
534 /*
535 ==================
536 GUI_CallKeyFunc
537 ==================
538 */
GUI_CallKeyFunc(char * fileName,gui_t * gui,parse_t * ps,guiParseKey_t * keyList1,guiParseKey_t * keyList2,guiParseKey_t * keyList3,char * token)539 static qBool GUI_CallKeyFunc (char *fileName, gui_t *gui, parse_t *ps, guiParseKey_t *keyList1, guiParseKey_t *keyList2, guiParseKey_t *keyList3, char *token)
540 {
541 	guiParseKey_t	*list, *key;
542 	char			keyName[MAX_PS_TOKCHARS];
543 	char			*str;
544 
545 	// Copy off a lower-case copy for faster comparisons
546 	Q_strncpyz (keyName, token, sizeof (keyName));
547 	Q_strlwr (keyName);
548 
549 	// Cycle through the key lists looking for a match
550 	for (list=keyList1 ; list ; ) {
551 		for (key=&list[0] ; key->keyWord ; key++) {
552 			// See if it matches the keyWord
553 			if (strcmp (key->keyWord, keyName))
554 				continue;
555 
556 			// This is just to ignore any warnings
557 			if (!key->func) {
558 				PS_SkipLine (ps);
559 				return qTrue;
560 			}
561 
562 			// Failed to parse line
563 			if (!key->func (fileName, gui, ps, keyName)) {
564 				PS_SkipLine (ps);
565 				return qFalse;
566 			}
567 
568 			// Report any extra parameters
569 			if (PS_ParseToken (ps, PSF_TO_LOWER, &str)) {
570 				GUI_PrintPos (PRNT_WARNING, ps, fileName, gui);
571 				GUI_PrintWarning ("WARNING: unused trailing parameters after key '%s', \"%s\"\n", keyName, str);
572 				PS_SkipLine (ps);
573 				return qTrue;
574 			}
575 
576 			// Parsed fine
577 			return qTrue;
578 		}
579 
580 		// Next list
581 		if (list == keyList1)
582 			list = keyList2;
583 		else if (list == keyList2)
584 			list = keyList3;
585 		else
586 			break;
587 	}
588 
589 	GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
590 	GUI_PrintError ("ERROR: unrecognized key: '%s'\n", keyName);
591 	return qFalse;
592 }
593 
594 /*
595 =============================================================================
596 
597 	ITEMDEF PARSING
598 
599 	The windowDef and itemDef's below can utilize all of these keys.
600 =============================================================================
601 */
602 
603 /*
604 ==================
605 itemDef_item
606 ==================
607 */
itemDef_item(char * fileName,gui_t * gui,parse_t * ps,char * keyName)608 static qBool itemDef_item (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
609 {
610 	qBool	item;
611 
612 	if (!PS_ParseDataType (ps, 0, PSDT_BOOLEAN, &item, 1)) {
613 		GUI_DevPrintPos (PRNT_WARNING, ps, fileName, gui);
614 		GUI_DevPrintf (PRNT_WARNING, ps, fileName, gui, "WARNING: missing '%s' paramter(s), using default\n");
615 		item = qTrue;
616 	}
617 
618 	if (item)
619 		gui->flags |= WFL_ITEM;
620 	else
621 		gui->flags &= ~WFL_ITEM;
622 	return qTrue;
623 }
624 
625 // ==========================================================================
626 
itemDef_rect(char * fileName,gui_t * gui,parse_t * ps,char * keyName)627 static qBool itemDef_rect (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
628 {
629 	return GUI_ParseVectorRegister (fileName, gui, ps, keyName, &gui->s.vecRegisters[VR_RECT]);
630 }
itemDef_rotate(char * fileName,gui_t * gui,parse_t * ps,char * keyName)631 static qBool itemDef_rotate (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
632 {
633 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_ROTATION], qTrue, 0);
634 }
635 
636 // ==========================================================================
637 
638 /*
639 ==================
640 itemDef_mat
641 ==================
642 */
itemDef_mat(char * fileName,gui_t * gui,parse_t * ps,char * keyName)643 static qBool itemDef_mat (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
644 {
645 	char	*str;
646 
647 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &str)) {
648 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
649 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
650 		return qFalse;
651 	}
652 
653 	Q_strncpyz (gui->matName, str, sizeof (gui->matName));
654 	gui->flags |= WFL_MATERIAL;
655 	return qTrue;
656 }
657 
itemDef_fill(char * fileName,gui_t * gui,parse_t * ps,char * keyName)658 static qBool itemDef_fill (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
659 {
660 	if (GUI_ParseVectorRegister (fileName, gui, ps, keyName, &gui->s.vecRegisters[VR_FILL_COLOR])) {
661 		gui->flags |= WFL_FILL_COLOR;
662 		return qTrue;
663 	}
664 	return qFalse;
665 }
itemDef_matColor(char * fileName,gui_t * gui,parse_t * ps,char * keyName)666 static qBool itemDef_matColor (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
667 {
668 	return GUI_ParseVectorRegister (fileName, gui, ps, keyName, &gui->s.vecRegisters[VR_MAT_COLOR]);
669 }
itemDef_matScaleX(char * fileName,gui_t * gui,parse_t * ps,char * keyName)670 static qBool itemDef_matScaleX (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
671 {
672 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_MAT_SCALE_X], qTrue, 1);
673 }
itemDef_matScaleY(char * fileName,gui_t * gui,parse_t * ps,char * keyName)674 static qBool itemDef_matScaleY (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
675 {
676 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_MAT_SCALE_Y], qTrue, 1);
677 }
678 
679 // ==========================================================================
680 
681 /*
682 ==================
683 itemDef_defineFloat
684 ==================
685 */
itemDef_defineFloat(char * fileName,gui_t * gui,parse_t * ps,char * keyName)686 static qBool itemDef_defineFloat (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
687 {
688 	char			*name;
689 	float			floatToken;
690 	defineFloat_t	*flt;
691 	int				i;
692 
693 	// Get the name
694 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &name)) {
695 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
696 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
697 		return qFalse;
698 	}
699 
700 	// Check for duplicates
701 	for (i=0, flt=&gui->s.defFloatList[0] ; i<gui->s.numDefFloats ; flt++, i++) {
702 		if (strcmp (flt->name, name))
703 			continue;
704 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
705 		GUI_PrintError ("ERROR: %s '%s' name already in use!\n", keyName, name);
706 		return qFalse;
707 	}
708 
709 	// Store
710 	Q_strncpyz (gui->s.defFloatList[gui->s.numDefFloats].name, name, sizeof (gui->s.defFloatList[gui->s.numDefFloats].name));
711 
712 	// Get the value
713 	if (!PS_ParseDataType (ps, 0, PSDT_FLOAT, &floatToken, 1)) {
714 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
715 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
716 		return qFalse;
717 	}
718 
719 	// Store
720 	gui->s.defFloatList[gui->s.numDefFloats].value = floatToken;
721 	gui->s.numDefFloats++;
722 	return qTrue;
723 }
724 
725 
726 /*
727 ==================
728 itemDef_defineVec
729 ==================
730 */
itemDef_defineVec(char * fileName,gui_t * gui,parse_t * ps,char * keyName)731 static qBool itemDef_defineVec (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
732 {
733 	char		*name;
734 	vec4_t		vecToken;
735 	defineVec_t	*vec;
736 	int			i;
737 
738 	// Get the name
739 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &name)) {
740 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
741 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
742 		return qFalse;
743 	}
744 
745 	// Check for duplicates
746 	for (i=0, vec=&gui->s.defVecList[0] ; i<gui->s.numDefVecs ; vec++, i++) {
747 		if (strcmp (vec->name, name))
748 			continue;
749 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
750 		GUI_PrintError ("ERROR: %s '%s' name already in use!\n", keyName, name);
751 		return qFalse;
752 	}
753 
754 	// Store
755 	Q_strncpyz (gui->s.defVecList[gui->s.numDefVecs].name, name, sizeof (gui->s.defVecList[gui->s.numDefVecs].name));
756 
757 	// Get the value
758 	if (!PS_ParseDataType (ps, 0, PSDT_FLOAT, &vecToken[0], 4)) {
759 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
760 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
761 		return qFalse;
762 	}
763 
764 	// Store
765 	Vec4Copy (vecToken, gui->s.defVecList[gui->s.numDefVecs].value);
766 	gui->s.numDefVecs++;
767 	return qTrue;
768 }
769 
770 // ==========================================================================
771 
itemDef_modal(char * fileName,gui_t * gui,parse_t * ps,char * keyName)772 static qBool itemDef_modal (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
773 {
774 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_MODAL], qFalse, 1);
775 }
itemDef_noEvents(char * fileName,gui_t * gui,parse_t * ps,char * keyName)776 static qBool itemDef_noEvents (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
777 {
778 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_NO_EVENTS], qFalse, 1);
779 }
itemDef_noTime(char * fileName,gui_t * gui,parse_t * ps,char * keyName)780 static qBool itemDef_noTime (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
781 {
782 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_NO_TIME], qFalse, 1);
783 }
itemDef_visible(char * fileName,gui_t * gui,parse_t * ps,char * keyName)784 static qBool itemDef_visible (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
785 {
786 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_VISIBLE], qFalse, 1);
787 }
itemDef_wantEnter(char * fileName,gui_t * gui,parse_t * ps,char * keyName)788 static qBool itemDef_wantEnter (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
789 {
790 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_WANT_ENTER], qFalse, 1);
791 }
792 
793 // ==========================================================================
794 
795 /*
796 ==================
797 event_newAction
798 ==================
799 */
800 typedef struct eva_setDest_s {
801 	const char		*name;
802 
803 	int				destNumVecs;
804 	uint32			destRegister;
805 	set_destType_t	destType;
806 
807 	guiType_t		destWindowType;
808 } eva_setDest_t;
809 
810 static eva_setDest_t gui_setDests[] = {
811 	// textDef
812 	{ "textcolor",			4,		VR_TEXT_COLOR,		EVA_SETDEST_VEC,	WTP_TEXT	},
813 	{ "texthovercolor",		4,		VR_TEXT_HOVERCOLOR,	EVA_SETDEST_VEC,	WTP_TEXT	},
814 
815 	{ "textalign",			1,		FR_TEXT_ALIGN,		EVA_SETDEST_FLOAT,	WTP_TEXT	},
816 	{ "textscale",			1,		FR_TEXT_SCALE,		EVA_SETDEST_FLOAT,	WTP_TEXT	},
817 	{ "textshadow",			1,		FR_TEXT_SHADOW,		EVA_SETDEST_FLOAT,	WTP_TEXT	},
818 
819 	// All windows
820 	{ "fillcolor",			4,		VR_FILL_COLOR,		EVA_SETDEST_VEC,	WTP_MAX		},
821 	{ "matcolor",			4,		VR_MAT_COLOR,		EVA_SETDEST_VEC,	WTP_MAX		},
822 
823 	{ "matscalex",			1,		FR_MAT_SCALE_X,		EVA_SETDEST_FLOAT,	WTP_MAX		},
824 	{ "matscaley",			1,		FR_MAT_SCALE_Y,		EVA_SETDEST_FLOAT,	WTP_MAX		},
825 
826 	{ "modal",				1,		FR_MODAL,			EVA_SETDEST_FLOAT,	WTP_MAX		},
827 	{ "noevents",			1,		FR_NO_EVENTS,		EVA_SETDEST_FLOAT,	WTP_MAX		},
828 	{ "notime",				1,		FR_NO_TIME,			EVA_SETDEST_FLOAT,	WTP_MAX		},
829 	{ "visible",			1,		FR_VISIBLE,			EVA_SETDEST_FLOAT,	WTP_MAX		},
830 	{ "wantenter",			1,		FR_WANT_ENTER,		EVA_SETDEST_FLOAT,	WTP_MAX		},
831 
832 	{ NULL,					0,		0,					0,					WTP_MAX		},
833 };
834 
event_newAction(evAction_t * newAction,evaType_t type,char * fileName,gui_t * gui,parse_t * ps,char * keyName,qBool gotSemicolon)835 static qBool event_newAction (evAction_t *newAction, evaType_t type, char *fileName, gui_t *gui, parse_t *ps, char *keyName, qBool gotSemicolon)
836 {
837 	eva_setDest_t	*setDest;
838 	char			target[MAX_PS_TOKCHARS];
839 	char			*charToken;
840 	char			*p;
841 
842 	// If we got a semi-colon, certain types require args
843 	if (gotSemicolon) {
844 		switch (type) {
845 		case EVA_COMMAND:
846 		case EVA_LOCAL_SOUND:
847 		case EVA_RESET_TIME:
848 		case EVA_SET:
849 		case EVA_TRANSITION:
850 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
851 			GUI_PrintError ("ERROR: invalid/missing arguments for '%s'!\n", keyName);
852 			return qFalse;
853 		}
854 	}
855 
856 	// Parse arguments
857 	switch (type) {
858 	case EVA_CLOSE:
859 		break;
860 
861 	case EVA_COMMAND:
862 		if (!PS_ParseToken (ps, PSF_ALLOW_NEWLINES|PSF_TO_LOWER, &charToken)) {
863 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
864 			GUI_PrintError ("ERROR: invalid/missing arguments for '%s'!\n", keyName);
865 			return qFalse;
866 		}
867 
868 		newAction->command = GUI_AllocTag (strlen(charToken)+2, qTrue, GUITAG_SCRATCH);
869 		Q_snprintfz (newAction->command, strlen(charToken)+2, "%s\n", charToken);
870 		break;
871 
872 	case EVA_IF:
873 		break;
874 
875 	case EVA_LOCAL_SOUND:
876 		if (!PS_ParseToken (ps, PSF_ALLOW_NEWLINES|PSF_TO_LOWER, &charToken)) {
877 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
878 			GUI_PrintError ("ERROR: invalid/missing arguments for '%s'!\n", keyName);
879 			return qFalse;
880 		}
881 
882 		newAction->localSound = GUI_AllocTag (sizeof (eva_localSound_t), qTrue, GUITAG_SCRATCH);
883 
884 		Com_NormalizePath (newAction->localSound->name, sizeof (newAction->localSound->name), charToken);
885 
886 		// FIXME: Make a register?
887 		if (!PS_ParseDataType (ps, 0, PSDT_FLOAT, &newAction->localSound->volume, 1)) {
888 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
889 			GUI_PrintError ("ERROR: invalid/missing arguments for '%s'!\n", keyName);
890 			return qFalse;
891 		}
892 		break;
893 
894 	case EVA_NAMED_EVENT:
895 		// Get the "[window::]event" token in lower-case for faster lookup
896 		if (!PS_ParseToken (ps, PSF_ALLOW_NEWLINES|PSF_TO_LOWER, &charToken)) {
897 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
898 			GUI_PrintError ("ERROR: invalid/missing arguments for '%s'!\n", keyName);
899 			return qFalse;
900 		}
901 
902 		newAction->named = GUI_AllocTag (sizeof (eva_named_t), qTrue, GUITAG_SCRATCH);
903 
904 		// Parse "[window::]event"
905 		Q_strncpyz (target, charToken, sizeof (target));
906 		p = strstr (target, "::");
907 		if (p) {
908 			// Make sure "window::<event>" exists
909 			if (!*(p+2)) {
910 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
911 				GUI_PrintError ("ERROR: invalid argument for '%s', contains '::' with no event name!\n", keyName);
912 				return qFalse;
913 			}
914 
915 			// "<window::>event"
916 			Q_strncpyz (newAction->named->destWindowName, target, sizeof (newAction->named->destWindowName));
917 			p = strstr (newAction->named->destWindowName, "::");
918 			*p = '\0';
919 
920 			// "window::<event>"
921 			Q_strncpyz (newAction->named->eventName, p+2, sizeof (newAction->named->eventName));
922 		}
923 		else {
924 			// Default to this window
925 			Q_strncpyz (newAction->named->destWindowName, gui->name, sizeof (newAction->named->destWindowName));
926 
927 			// "<event>"
928 			Q_strncpyz (newAction->named->eventName, target, sizeof (newAction->named->eventName));
929 		}
930 		break;
931 
932 	case EVA_RESET_TIME:
933 		if (!PS_ParseDataType (ps, 0, PSDT_INTEGER, &newAction->resetTime, 1)) {
934 			GUI_PrintPos (PRNT_WARNING, ps, fileName, gui);
935 			GUI_PrintWarning ("WARNING: invalid/missing arguments for '%s', assuming '0'\n", keyName);
936 			newAction->resetTime = 0;
937 		}
938 		break;
939 
940 	case EVA_SET:
941 		// Get the "[window::]register" token in lower-case for faster lookup
942 		if (!PS_ParseToken (ps, PSF_TO_LOWER, &charToken)) {
943 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
944 			GUI_PrintError ("ERROR: invalid/missing arguments for '%s'!\n", keyName);
945 			return qFalse;
946 		}
947 
948 		newAction->set = GUI_AllocTag (sizeof (eva_set_t), qTrue, GUITAG_SCRATCH);
949 
950 		// Parse "[window::]register" destination
951 		Q_strncpyz (target, charToken, sizeof (target));
952 		p = strstr (target, "::");
953 		if (p) {
954 			// Make sure "window::<register>" exists
955 			if (!*(p+2)) {
956 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
957 				GUI_PrintError ("ERROR: invalid argument for '%s', contains '::' with no flag name!\n", keyName);
958 				return qFalse;
959 			}
960 
961 			// "<window::>register"
962 			Q_strncpyz (newAction->set->destWindowName, target, sizeof (newAction->set->destWindowName));
963 			p = strstr (newAction->set->destWindowName, "::");
964 			*p = '\0';
965 
966 			// "window::<register>"
967 			Q_strncpyz (newAction->set->destVarName, p+2, sizeof (newAction->set->destVarName));
968 		}
969 		else {
970 			// Default to this window
971 			Q_strncpyz (newAction->set->destWindowName, gui->name, sizeof (newAction->set->destWindowName));
972 
973 			// "<register>"
974 			Q_strncpyz (newAction->set->destVarName, target, sizeof (newAction->set->destVarName));
975 		}
976 
977 		// Find the destination register type
978 		for (setDest=gui_setDests ; setDest->name ; setDest++) {
979 			if (!strcmp (newAction->set->destVarName, setDest->name))
980 				break;
981 		}
982 		if (!setDest) {
983 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
984 			GUI_PrintError ("ERROR: invalid '%s' variable '%s'!\n", keyName, newAction->set->destVarName);
985 			return qFalse;
986 		}
987 
988 		// Store destination parms
989 		newAction->set->destNumVecs = setDest->destNumVecs;
990 		newAction->set->destRegister = setDest->destRegister;
991 		newAction->set->destType = setDest->destType;
992 		newAction->set->destWindowType = setDest->destWindowType;
993 
994 		newAction->set->destType |= EVA_SETDEST_STORAGE;
995 
996 		// Check if the source is a defineFloat/defineVec
997 		if (!PS_ParseToken (ps, PSF_TO_LOWER, &charToken)) {
998 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
999 			GUI_PrintError ("ERROR: invalid/missing arguments for '%s'!\n", keyName);
1000 			return qFalse;
1001 		}
1002 
1003 		if (charToken[0] == '$') {
1004 			// Parse "[window::]var"
1005 			Q_strncpyz (target, &charToken[1], sizeof (target));
1006 			p = strstr (target, "::");
1007 			if (p) {
1008 				if (!*(p+2)) {
1009 					GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1010 					GUI_PrintError ("ERROR: invalid argument for '%s', contains '::' with no flag name!\n", keyName);
1011 					return qFalse;
1012 				}
1013 
1014 				// "<window::>var"
1015 				Q_strncpyz (newAction->set->srcWindowName, target, sizeof (newAction->set->srcWindowName));
1016 				p = strstr (newAction->set->srcWindowName, "::");
1017 				*p = '\0';
1018 
1019 				// "window::<var>"
1020 				Q_strncpyz (newAction->set->srcName, p+2, sizeof (newAction->set->srcName));
1021 
1022 				// Check if we're looking for a guiVar
1023 				if (!strcmp (newAction->set->srcWindowName, "guivar")) {
1024 					newAction->set->srcType = EVA_SETSRC_GUIVAR;
1025 					break;
1026 				}
1027 				else {
1028 					// Nope, it's a defineFloat/defineVec
1029 					newAction->set->srcType = EVA_SETSRC_DEF;
1030 					break;
1031 				}
1032 			}
1033 			else {
1034 				// Default to this window
1035 				Q_strncpyz (newAction->set->srcWindowName, gui->name, sizeof (newAction->set->srcWindowName));
1036 
1037 				// "<var>"
1038 				Q_strncpyz (newAction->set->srcName, target, sizeof (newAction->set->srcName));
1039 
1040 				// defineFloat/defineVec
1041 				newAction->set->srcType = EVA_SETSRC_DEF;
1042 				break;
1043 			}
1044 		}
1045 
1046 		// Not a pointer, parse the var setValue
1047 		PS_UndoParse (ps);
1048 		if (!PS_ParseDataType (ps, 0, PSDT_FLOAT, &newAction->set->srcStorage[0], setDest->destNumVecs)) {
1049 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1050 			GUI_PrintError ("ERROR: invalid/missing arguments for '%s'!\n", keyName);
1051 			return qFalse;
1052 		}
1053 
1054 		// Store source parms
1055 		newAction->set->srcType = EVA_SETSRC_STORAGE;
1056 		break;
1057 
1058 	case EVA_STOP_TRANSITIONS:
1059 		break;
1060 
1061 	case EVA_TRANSITION:
1062 		break;
1063 	}
1064 
1065 	// Final ';'
1066 	if (!gotSemicolon && (!PS_ParseToken (ps, PSF_ALLOW_NEWLINES|PSF_TO_LOWER, &charToken) || strcmp (charToken, ";"))) {
1067 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1068 		GUI_PrintError ("ERROR: expecting ';' after %s <args>, got '%s'!\n", keyName, charToken);
1069 		return qFalse;
1070 	}
1071 
1072 	newAction->type = type;
1073 	return qTrue;
1074 }
1075 
1076 
1077 /*
1078 ==================
1079 itemDef_newEvent
1080 ==================
1081 */
itemDef_newEvent(evType_t type,char * fileName,gui_t * gui,parse_t * ps,char * keyName)1082 static qBool itemDef_newEvent (evType_t type, char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1083 {
1084 	event_t		*newEvent;
1085 	char		actionName[MAX_PS_TOKCHARS];
1086 	evaType_t	action;
1087 	evAction_t	*actionList;
1088 	char		*token;
1089 	int			len;
1090 	qBool		gotSemicolon;
1091 	int			i;
1092 
1093 	// Allocate a spot
1094 	if (gui->numEvents+1 >= MAX_GUI_EVENTS) {
1095 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1096 		GUI_PrintError ("ERROR: too many events!\n");
1097 		return qFalse;
1098 	}
1099 	newEvent = &gui->eventList[gui->numEvents];
1100 	memset (&gui->eventList[gui->numEvents], 0, sizeof (event_t));
1101 	newEvent->type = type;
1102 
1103 	// Parse arguments
1104 	switch (type) {
1105 	case WEV_NAMED:
1106 		if (!PS_ParseToken (ps, PSF_ALLOW_NEWLINES|PSF_TO_LOWER, &token) || !strcmp (token, "{")) {
1107 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1108 			GUI_PrintError ("ERROR: invalid/missing arguments for '%s'!\n", keyName);
1109 			return qFalse;
1110 		}
1111 
1112 		newEvent->named = GUI_StrDup (token, GUITAG_SCRATCH);
1113 		break;
1114 
1115 	case WEV_TIME:
1116 		if (!PS_ParseDataType (ps, PSF_ALLOW_NEWLINES, PSDT_INTEGER, &len, 1)) {
1117 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1118 			GUI_PrintError ("ERROR: invalid/missing arguments for '%s'!\n", keyName);
1119 			return qFalse;
1120 		}
1121 		newEvent->onTime = len;
1122 		break;
1123 	}
1124 
1125 	// Make sure the event doesn't already exist
1126 	for (i=0 ; i<gui->numEvents ; i++) {
1127 		if (gui->eventList[i].type != type)
1128 			continue;
1129 
1130 		// You can have multiple numbers of these if the args don't match
1131 		switch (gui->eventList[i].type) {
1132 		case WEV_NAMED:
1133 			if (!strcmp (gui->eventList[i].named, newEvent->named)) {
1134 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1135 				GUI_PrintError ("ERROR: event '%s' already exists (with the same arguments) for this window!\n", keyName);
1136 				return qFalse;
1137 			}
1138 			break;
1139 
1140 		case WEV_TIME:
1141 			if (gui->eventList[i].onTime == newEvent->onTime) {
1142 				GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1143 				GUI_PrintError ("ERROR: event '%s' already exists (with the same arguments) for this window!\n", keyName);
1144 				return qFalse;
1145 			}
1146 			break;
1147 
1148 		default:
1149 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1150 			GUI_PrintError ("ERROR: event '%s' already exists for this window!\n", keyName);
1151 			return qFalse;
1152 		}
1153 	}
1154 
1155 	// Next is the opening brace
1156 	if (!PS_ParseToken (ps, PSF_ALLOW_NEWLINES|PSF_TO_LOWER, &token) || strcmp (token, "{")) {
1157 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1158 		GUI_PrintError ("ERROR: expecting '{' after %s <args>, got '%s'!\n", keyName, token);
1159 		return qFalse;
1160 	}
1161 
1162 	// Storage space for children
1163 	newEvent->numActions = 0;
1164 	newEvent->actionList = GUI_AllocTag (sizeof (evAction_t) * MAX_EVENT_ACTIONS, qTrue, GUITAG_SCRATCH);
1165 
1166 	// Parse the actions
1167 	for ( ; ; ) {
1168 		if (!PS_ParseToken (ps, PSF_ALLOW_NEWLINES|PSF_TO_LOWER, &token) || !strcmp (token, "}"))
1169 			break;
1170 
1171 		// Store the name and trim the ';' if found
1172 		// FIXME: start at the end, skipping whitespace until ';' is hit.
1173 		Q_strncpyz (actionName, token, sizeof (actionName));
1174 		len = strlen (actionName);
1175 		if (actionName[len-1] == ';') {
1176 			actionName[len-1] = '\0';
1177 			gotSemicolon = qTrue;
1178 		}
1179 		else {
1180 			gotSemicolon = qFalse;
1181 		}
1182 
1183 		// Find out the type
1184 		if (!strcmp (actionName, "close"))
1185 			action = EVA_CLOSE;
1186 		else if (!strcmp (actionName, "command"))
1187 			action = EVA_COMMAND;
1188 		else if (!strcmp (actionName, "if"))
1189 			action = EVA_IF;
1190 		else if (!strcmp (actionName, "localsound"))
1191 			action = EVA_LOCAL_SOUND;
1192 		else if (!strcmp (actionName, "namedevent"))
1193 			action = EVA_NAMED_EVENT;
1194 		else if (!strcmp (actionName, "resettime"))
1195 			action = EVA_RESET_TIME;
1196 		else if (!strcmp (actionName, "set"))
1197 			action = EVA_SET;
1198 		else if (!strcmp (actionName, "stoptransitions"))
1199 			action = EVA_STOP_TRANSITIONS;
1200 		else if (!strcmp (actionName, "transition"))
1201 			action = EVA_TRANSITION;
1202 		else {
1203 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1204 			GUI_PrintError ("ERROR: unknown action '%s'!\n", actionName);
1205 			return qFalse;
1206 		}
1207 
1208 		// Parse it
1209 		if (!event_newAction (&newEvent->actionList[newEvent->numActions], action, fileName, gui, ps, actionName, gotSemicolon))
1210 			return qFalse;
1211 
1212 		// Done
1213 		newEvent->numActions++;
1214 	}
1215 
1216 	// Closing brace
1217 	if (strcmp (token, "}")) {
1218 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1219 		GUI_PrintError ("ERROR: expecting '}' after %s <args>, got '%s'!\n", keyName, token);
1220 		return qFalse;
1221 	}
1222 
1223 	// Store events
1224 	actionList = newEvent->actionList;
1225 	if (newEvent->numActions) {
1226 		newEvent->actionList = GUI_AllocTag (sizeof (evAction_t) * newEvent->numActions, qFalse, GUITAG_SCRATCH);
1227 		memcpy (newEvent->actionList, actionList, sizeof (evAction_t) * newEvent->numActions);
1228 		Mem_Free (actionList);
1229 	}
1230 	else
1231 		newEvent->actionList = NULL;
1232 
1233 	// Done
1234 	gui->numEvents++;
1235 	return qTrue;
1236 }
1237 
itemDef_onAction(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1238 static qBool itemDef_onAction (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1239 {
1240 	return itemDef_newEvent (WEV_ACTION, fileName, gui, ps, keyName);
1241 }
itemDef_onEsc(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1242 static qBool itemDef_onEsc (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1243 {
1244 	return itemDef_newEvent (WEV_ESCAPE, fileName, gui, ps, keyName);
1245 }
itemDef_onFrame(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1246 static qBool itemDef_onFrame (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1247 {
1248 	return itemDef_newEvent (WEV_FRAME, fileName, gui, ps, keyName);
1249 }
itemDef_onInit(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1250 static qBool itemDef_onInit (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1251 {
1252 	return itemDef_newEvent (WEV_INIT, fileName, gui, ps, keyName);
1253 }
itemDef_onMouseEnter(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1254 static qBool itemDef_onMouseEnter (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1255 {
1256 	return itemDef_newEvent (WEV_MOUSE_ENTER, fileName, gui, ps, keyName);
1257 }
itemDef_onMouseExit(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1258 static qBool itemDef_onMouseExit (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1259 {
1260 	return itemDef_newEvent (WEV_MOUSE_EXIT, fileName, gui, ps, keyName);
1261 }
itemDef_onNamedEvent(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1262 static qBool itemDef_onNamedEvent (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1263 {
1264 	return itemDef_newEvent (WEV_NAMED, fileName, gui, ps, keyName);
1265 }
itemDef_onShutdown(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1266 static qBool itemDef_onShutdown (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1267 {
1268 	return itemDef_newEvent (WEV_SHUTDOWN, fileName, gui, ps, keyName);
1269 }
itemDef_onTime(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1270 static qBool itemDef_onTime (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1271 {
1272 	return itemDef_newEvent (WEV_TIME, fileName, gui, ps, keyName);
1273 }
1274 
1275 // ==========================================================================
1276 
1277 static guiParseKey_t	cl_itemDefKeyList[] = {
1278 	// Flags
1279 	{ "item",					&itemDef_item				},
1280 
1281 	// Orientation
1282 	{ "rect",					&itemDef_rect				},
1283 	{ "rotate",					&itemDef_rotate				},
1284 
1285 	// Background
1286 	{ "fill",					&itemDef_fill				},
1287 	{ "mat",					&itemDef_mat				},
1288 	{ "matcolor",				&itemDef_matColor			},
1289 	{ "matscalex",				&itemDef_matScaleX			},
1290 	{ "matscaley",				&itemDef_matScaleY			},
1291 
1292 	// Defines
1293 	{ "definefloat",			&itemDef_defineFloat		},
1294 	{ "definevec",				&itemDef_defineVec			},
1295 
1296 	// Registers
1297 	{ "modal",					&itemDef_modal				},
1298 	{ "noevents",				&itemDef_noEvents			},
1299 	{ "notime",					&itemDef_noTime				},
1300 	{ "visible",				&itemDef_visible			},
1301 	{ "wantenter",				&itemDef_wantEnter			},
1302 
1303 	// Events
1304 	{ "onaction",				&itemDef_onAction			},
1305 	{ "onesc",					&itemDef_onEsc				},
1306 	{ "onframe",				&itemDef_onFrame			},
1307 	{ "oninit",					&itemDef_onInit				},
1308 	{ "onmouseenter",			&itemDef_onMouseEnter		},
1309 	{ "onmouseexit",			&itemDef_onMouseExit		},
1310 	{ "onnamedevent",			&itemDef_onNamedEvent		},
1311 	{ "ontime",					&itemDef_onTime				},
1312 
1313 	{ NULL,						NULL						}
1314 };
1315 
1316 /*
1317 =============================================================================
1318 
1319 	BINDDEF PARSING
1320 
1321 =============================================================================
1322 */
1323 
1324 /*
1325 ==================
1326 bindDef_bind
1327 ==================
1328 */
bindDef_bind(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1329 static qBool bindDef_bind (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1330 {
1331 	char		*str;
1332 	keyNum_t	keyNum;
1333 
1334 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &str)) {
1335 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1336 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1337 		return qFalse;
1338 	}
1339 
1340 	keyNum = Key_StringToKeynum (str);
1341 	if (keyNum == -1) {
1342 		Com_Printf (0, "\"%s\" isn't a valid key\n", str);
1343 		return qFalse;
1344 	}
1345 
1346 	gui->s.bindDef->keyNum = keyNum;
1347 	return qTrue;
1348 }
1349 
1350 // ==========================================================================
1351 
1352 static guiParseKey_t	cl_bindDefKeyList[] = {
1353 	{ "bind",					&bindDef_bind				},
1354 	{ NULL,						NULL						}
1355 };
1356 
1357 /*
1358 =============================================================================
1359 
1360 	CHECKDEF PARSING
1361 
1362 =============================================================================
1363 */
1364 
1365 /*
1366 ==================
1367 checkDef_liveUpdate
1368 ==================
1369 */
checkDef_liveUpdate(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1370 static qBool checkDef_liveUpdate (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1371 {
1372 	qBool	liveUpdate;
1373 
1374 	if (!PS_ParseDataType (ps, 0, PSDT_BOOLEAN, &liveUpdate, 1)) {
1375 		GUI_DevPrintPos (PRNT_WARNING, ps, fileName, gui);
1376 		GUI_DevPrintf (PRNT_WARNING, ps, fileName, gui, "WARNING: missing '%s' paramter(s), using default\n");
1377 		liveUpdate = qTrue;
1378 	}
1379 
1380 	gui->s.checkDef->liveUpdate = liveUpdate;
1381 	return qTrue;
1382 }
1383 
1384 
1385 /*
1386 ==================
1387 checkDef_offMat
1388 ==================
1389 */
checkDef_offMat(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1390 static qBool checkDef_offMat (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1391 {
1392 	char	*str;
1393 
1394 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &str)) {
1395 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1396 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1397 		return qFalse;
1398 	}
1399 
1400 	Com_NormalizePath (gui->s.checkDef->offMatName, sizeof(gui->s.checkDef->offMatName), str);
1401 	return qTrue;
1402 }
1403 
1404 
1405 /*
1406 ==================
1407 checkDef_onMat
1408 ==================
1409 */
checkDef_onMat(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1410 static qBool checkDef_onMat (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1411 {
1412 	char	*str;
1413 
1414 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &str)) {
1415 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1416 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1417 		return qFalse;
1418 	}
1419 
1420 	Com_NormalizePath (gui->s.checkDef->onMatName, sizeof(gui->s.checkDef->onMatName), str);
1421 	return qTrue;
1422 }
1423 
1424 
1425 /*
1426 ==================
1427 checkDef_values
1428 ==================
1429 */
checkDef_values(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1430 static qBool checkDef_values (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1431 {
1432 	char	*str;
1433 	char	*p;
1434 
1435 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &str)) {
1436 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1437 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1438 		return qFalse;
1439 	}
1440 
1441 	// Only has two values
1442 	p = strchr (str, ';');
1443 	if (!*p) {
1444 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1445 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1446 		return qFalse;
1447 	}
1448 	*p = '\0';
1449 	gui->s.checkDef->values[0] = GUI_StrDup (str, GUITAG_SCRATCH);
1450 
1451 	// Second value
1452 	p++;
1453 	if (!*p) {
1454 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1455 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1456 		return qFalse;
1457 	}
1458 	gui->s.checkDef->values[1] = GUI_StrDup (p, GUITAG_SCRATCH);
1459 
1460 	return qTrue;
1461 }
1462 
1463 
1464 /*
1465 ==================
1466 checkDef_cvar
1467 ==================
1468 */
checkDef_cvar(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1469 static qBool checkDef_cvar (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1470 {
1471 	char	*str;
1472 
1473 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &str)) {
1474 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1475 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1476 		return qFalse;
1477 	}
1478 
1479 	if (!GUI_CvarValidate (str)) {
1480 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1481 		GUI_PrintError ("ERROR: invalid cvar name for '%s'\n", keyName);
1482 		return qFalse;
1483 	}
1484 
1485 	gui->s.checkDef->cvar = Cvar_Exists (str);
1486 	if (!gui->s.checkDef->cvar) {
1487 		GUI_DevPrintf (PRNT_WARNING, ps, fileName, gui, "WARNING: cvar '%s' does not exist, creating\n", str);
1488 		gui->s.checkDef->cvar = Cvar_Register (str, "0", 0);
1489 	}
1490 
1491 	return qTrue;
1492 }
1493 
1494 // ==========================================================================
1495 
1496 static guiParseKey_t	cl_checkDefKeyList[] = {
1497 	{ "liveupdate",				&checkDef_liveUpdate		},
1498 	{ "offmat",					&checkDef_offMat			},
1499 	{ "onmat",					&checkDef_onMat				},
1500 	{ "values",					&checkDef_values			},
1501 	{ "cvar",					&checkDef_cvar				},
1502 	{ NULL,						&checkDef_cvar				}
1503 };
1504 
1505 /*
1506 =============================================================================
1507 
1508 	CHOICEDEF PARSING
1509 
1510 =============================================================================
1511 */
1512 
1513 // ==========================================================================
1514 
1515 static guiParseKey_t	cl_choiceDefKeyList[] = {
1516 	{ "liveupdate",				NULL						},
1517 	{ "choices",				NULL						},
1518 	{ "choicetype",				NULL						},
1519 	{ "currentchoice",			NULL						},
1520 	{ "values",					NULL						},
1521 	{ "cvar",					NULL						},
1522 	{ NULL,						NULL						}
1523 };
1524 
1525 /*
1526 =============================================================================
1527 
1528 	EDITDEF PARSING
1529 
1530 =============================================================================
1531 */
1532 
1533 // ==========================================================================
1534 
1535 static guiParseKey_t	cl_editDefKeyList[] = {
1536 	{ "liveupdate",				NULL						},
1537 	{ "maxchars",				NULL						},
1538 	{ "numeric",				NULL						},
1539 	{ "wrap",					NULL						},
1540 	{ "readonly",				NULL						},
1541 	{ "source",					NULL						},
1542 	{ "password",				NULL						},
1543 	{ "cvar",					NULL						},
1544 	{ NULL,						NULL						}
1545 };
1546 
1547 /*
1548 =============================================================================
1549 
1550 	LISTDEF PARSING
1551 
1552 =============================================================================
1553 */
1554 
1555 /*
1556 ==================
1557 listDef_scrollBar
1558 ==================
1559 */
listDef_scrollBar(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1560 static qBool listDef_scrollBar (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1561 {
1562 	if (!PS_ParseDataType (ps, 0, PSDT_BOOLEAN, gui->s.listDef->scrollBar, 2)) {
1563 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1564 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1565 		return qFalse;
1566 	}
1567 
1568 	return qTrue;
1569 }
1570 
1571 // ==========================================================================
1572 
1573 static guiParseKey_t	cl_listDefKeyList[] = {
1574 	{ "scrollbar",				&listDef_scrollBar			},
1575 	{ NULL,						NULL						}
1576 };
1577 
1578 /*
1579 =============================================================================
1580 
1581 	RENDERDEF PARSING
1582 
1583 =============================================================================
1584 */
1585 
1586 // ==========================================================================
1587 
1588 static guiParseKey_t	cl_renderDefKeyList[] = {
1589 	{ "lightcolor",				NULL						},
1590 	{ "lightorigin",			NULL						},
1591 	{ "model",					NULL						},
1592 	{ "modelcolor",				NULL						},
1593 	{ "modelrotate",			NULL						},
1594 	{ "vieworigin",				NULL						},
1595 	{ "viewangles",				NULL						},
1596 	{ NULL,						NULL						}
1597 };
1598 
1599 /*
1600 =============================================================================
1601 
1602 	SLIDERDEF PARSING
1603 
1604 =============================================================================
1605 */
1606 
1607 // ==========================================================================
1608 
1609 static guiParseKey_t	cl_sliderDefKeyList[] = {
1610 	{ "liveupdate",				NULL						},
1611 	{ "low",					NULL						},
1612 	{ "high",					NULL						},
1613 	{ "step",					NULL						},
1614 	{ "vertical",				NULL						},
1615 	{ "thumbshader",			NULL						},
1616 	{ "cvar",					NULL						},
1617 	{ NULL,						NULL						}
1618 };
1619 
1620 /*
1621 =============================================================================
1622 
1623 	TEXTDEF PARSING
1624 
1625 =============================================================================
1626 */
1627 
1628 /*
1629 ==================
1630 textDef_font
1631 ==================
1632 */
textDef_font(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1633 static qBool textDef_font (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1634 {
1635 	char	*str;
1636 
1637 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &str)) {
1638 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1639 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1640 		return qFalse;
1641 	}
1642 
1643 	Com_NormalizePath (gui->s.textDef->fontName, sizeof (gui->s.textDef->fontName), str);
1644 	return qTrue;
1645 }
1646 
1647 
1648 /*
1649 ==================
1650 textDef_text
1651 ==================
1652 */
textDef_text(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1653 static qBool textDef_text (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1654 {
1655 	char	*token;
1656 	int		len;
1657 
1658 	if (!PS_ParseToken (ps, PSF_CONVERT_NEWLINE, &token)) {
1659 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1660 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1661 		return qFalse;
1662 	}
1663 
1664 	// Check length
1665 	len = strlen (token);
1666 	if (len >= MAX_TEXTDEF_STRLEN-1) {
1667 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1668 		GUI_PrintError ("ERROR: parameter too long for '%s'\n", keyName);
1669 		return qFalse;
1670 	}
1671 
1672 	gui->s.textDef->textString = GUI_StrDup (token, GUITAG_SCRATCH);
1673 	gui->s.textDef->textStringLen = len;
1674 	return qTrue;
1675 }
1676 
textDef_textAlign(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1677 static qBool textDef_textAlign (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1678 {
1679 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_TEXT_ALIGN], qTrue, 1);
1680 }
textDef_textColor(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1681 static qBool textDef_textColor (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1682 {
1683 	return GUI_ParseVectorRegister (fileName, gui, ps, keyName, &gui->s.vecRegisters[VR_TEXT_COLOR]);
1684 }
textDef_textHoverColor(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1685 static qBool textDef_textHoverColor (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1686 {
1687 	return GUI_ParseVectorRegister (fileName, gui, ps, keyName, &gui->s.vecRegisters[VR_TEXT_HOVERCOLOR]);
1688 }
textDef_textScale(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1689 static qBool textDef_textScale (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1690 {
1691 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_TEXT_SCALE], qTrue, 1);
1692 }
textDef_textShadow(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1693 static qBool textDef_textShadow (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1694 {
1695 	return GUI_ParseFloatRegister (fileName, gui, ps, keyName, &gui->s.floatRegisters[FR_TEXT_SHADOW], qFalse, 1);
1696 }
1697 
1698 // ==========================================================================
1699 
1700 static guiParseKey_t	cl_textDefKeyList[] = {
1701 	{ "font",					&textDef_font				},
1702 	{ "text",					&textDef_text				},
1703 	{ "textalign",				&textDef_textAlign			},
1704 	{ "textcolor",				&textDef_textColor			},
1705 	{ "texthovercolor",			&textDef_textHoverColor		},
1706 	{ "textscale",				&textDef_textScale			},
1707 	{ "textshadow",				&textDef_textShadow			},
1708 	{ NULL,						NULL						}
1709 };
1710 
1711 /*
1712 =============================================================================
1713 
1714 	GUIDEF PARSING
1715 
1716 =============================================================================
1717 */
1718 
1719 /*
1720 ==================
1721 guiDef_cursorMat
1722 ==================
1723 */
guiDef_cursorMat(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1724 static qBool guiDef_cursorMat (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1725 {
1726 	char	*str;
1727 
1728 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &str)) {
1729 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1730 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1731 		return qFalse;
1732 	}
1733 
1734 	Q_strncpyz (gui->shared->cursor.s.matName, str, sizeof (gui->shared->cursor.s.matName));
1735 	gui->shared->cursor.s.visible = qTrue;
1736 	gui->flags |= WFL_CURSOR;
1737 	return qTrue;
1738 }
1739 
1740 
1741 /*
1742 ==================
1743 guiDef_cursorColor
1744 ==================
1745 */
guiDef_cursorColor(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1746 static qBool guiDef_cursorColor (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1747 {
1748 	vec4_t	color;
1749 
1750 	if (!PS_ParseDataType (ps, 0, PSDT_FLOAT, &color[0], 4)) {
1751 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1752 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1753 		return qFalse;
1754 	}
1755 
1756 	ColorNormalizef (color, gui->shared->cursor.s.color);
1757 	gui->shared->cursor.s.color[3] = color[3];
1758 	return qTrue;
1759 }
1760 
1761 
1762 /*
1763 ==================
1764 guiDef_cursorHeight
1765 ==================
1766 */
guiDef_cursorHeight(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1767 static qBool guiDef_cursorHeight (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1768 {
1769 	float	height;
1770 
1771 	if (!PS_ParseDataType (ps, 0, PSDT_FLOAT, &height, 1)) {
1772 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1773 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1774 		return qFalse;
1775 	}
1776 
1777 	gui->shared->cursor.s.size[1] = height;
1778 	return qTrue;
1779 }
1780 
1781 
1782 /*
1783 ==================
1784 guiDef_cursorWidth
1785 ==================
1786 */
guiDef_cursorWidth(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1787 static qBool guiDef_cursorWidth (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1788 {
1789 	float	width;
1790 
1791 	if (!PS_ParseDataType (ps, 0, PSDT_FLOAT, &width, 1)) {
1792 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1793 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1794 		return qFalse;
1795 	}
1796 
1797 	gui->shared->cursor.s.size[0] = width;
1798 	return qTrue;
1799 }
1800 
1801 
1802 /*
1803 ==================
1804 guiDef_cursorPos
1805 ==================
1806 */
guiDef_cursorPos(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1807 static qBool guiDef_cursorPos (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1808 {
1809 	vec2_t	pos;
1810 
1811 	if (!PS_ParseDataType (ps, 0, PSDT_FLOAT, &pos[0], 2)) {
1812 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1813 		GUI_PrintError ("ERROR: invalid/missing parameters for '%s'\n", keyName);
1814 		return qFalse;
1815 	}
1816 
1817 	Vec2Copy (pos, gui->shared->cursor.s.pos);
1818 	return qTrue;
1819 }
1820 
1821 
1822 /*
1823 ==================
1824 guiDef_cursorVisible
1825 ==================
1826 */
guiDef_cursorVisible(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1827 static qBool guiDef_cursorVisible (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1828 {
1829 	qBool	visible;
1830 
1831 	if (!PS_ParseDataType (ps, 0, PSDT_BOOLEAN, &visible, 1)) {
1832 		GUI_DevPrintPos (PRNT_WARNING, ps, fileName, gui);
1833 		GUI_DevPrintf (PRNT_WARNING, ps, fileName, gui, "WARNING: missing '%s' paramter(s), using default\n");
1834 		visible = qTrue;
1835 	}
1836 
1837 	gui->shared->cursor.s.visible = visible;
1838 	return qTrue;
1839 }
1840 
1841 
1842 static guiParseKey_t	cl_guiDefKeyList[] = {
1843 	{ "cursormat",				&guiDef_cursorMat			},
1844 	{ "cursorcolor",			&guiDef_cursorColor			},
1845 	{ "cursorheight",			&guiDef_cursorHeight		},
1846 	{ "cursorwidth",			&guiDef_cursorWidth			},
1847 	{ "cursorpos",				&guiDef_cursorPos			},
1848 	{ "cursorvisible",			&guiDef_cursorVisible		},
1849 	{ NULL,						NULL						}
1850 };
1851 
1852 /*
1853 =============================================================================
1854 
1855 	WINDOWDEF PARSING
1856 
1857 =============================================================================
1858 */
1859 
1860 qBool GUI_NewWindowDef (char *fileName, gui_t *gui, parse_t *ps, char *keyName);
1861 static guiParseKey_t	cl_windowDefKeyList[] = {
1862 	// Window types
1863 	{ "windowdef",				&GUI_NewWindowDef			},
1864 	{ "binddef",				&GUI_NewWindowDef			},
1865 	{ "checkdef",				&GUI_NewWindowDef			},
1866 	{ "choicedef",				&GUI_NewWindowDef			},
1867 	{ "editdef",				&GUI_NewWindowDef			},
1868 	{ "listdef",				&GUI_NewWindowDef			},
1869 	{ "renderdef",				&GUI_NewWindowDef			},
1870 	{ "sliderdef",				&GUI_NewWindowDef			},
1871 	{ "textdef",				&GUI_NewWindowDef			},
1872 	{ NULL,						NULL						}
1873 };
1874 
1875 static const char		*cl_windowDefTypes[] = {
1876 	"guidef",		// WTP_GUI,
1877 	"windowdef",	// WTP_GENERIC,
1878 
1879 	"binddef",		// WTP_BIND,
1880 	"checkdef",		// WTP_CHECKBOX,
1881 	"choicedef",	// WTP_CHOICE,
1882 	"editdef",		// WTP_EDIT,
1883 	"listdef",		// WTP_LIST,
1884 	"renderdef",	// WTP_RENDER,
1885 	"sliderdef",	// WTP_SLIDER,
1886 	"textdef",		// WTP_TEXT
1887 
1888 	NULL,
1889 };
1890 
1891 /*
1892 ==================
1893 GUI_NewWindowDef
1894 ==================
1895 */
GUI_NewWindowDef(char * fileName,gui_t * gui,parse_t * ps,char * keyName)1896 qBool GUI_NewWindowDef (char *fileName, gui_t *gui, parse_t *ps, char *keyName)
1897 {
1898 	char			windowName[MAX_GUI_NAMELEN];
1899 	gui_t			*newGUI, *owner;
1900 	char			*token;
1901 	guiType_t		type;
1902 	gui_t			*childList;
1903 	event_t			*eventList;
1904 	defineFloat_t	*defFloatList;
1905 	defineVec_t		*defVecList;
1906 
1907 	// First is the name
1908 	if (!PS_ParseToken (ps, PSF_TO_LOWER, &token)) {
1909 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1910 		GUI_PrintError ("ERROR: expecting <name> after %s, got '%s'!\n", keyName, token);
1911 		return qFalse;
1912 	}
1913 	if (strlen(token)+1 >= MAX_GUI_NAMELEN) {
1914 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1915 		GUI_PrintError ("ERROR: %s '%s' name too long!\n", keyName, token);
1916 		return qFalse;
1917 	}
1918 	Q_strncpyz (windowName, token, sizeof (windowName));
1919 
1920 	// Check for duplicates
1921 	if (gui && GUI_FindWindow (gui->owner, windowName)) {
1922 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1923 		GUI_PrintError ("ERROR: %s '%s' name already in use!\n", keyName, token);
1924 		return qFalse;
1925 	}
1926 
1927 	// Make sure the name is allowed
1928 	if (!strcmp (windowName, "guivar")) {
1929 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1930 		GUI_PrintError ("ERROR: %s '%s' name not allowed!\n", keyName, token);
1931 		return qFalse;
1932 	}
1933 	if (strchr (windowName, '$') || strstr (windowName, "::")) {
1934 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1935 		GUI_PrintError ("ERROR: %s '%s' name must not contain '$' or '::'!\n", keyName, token);
1936 		return qFalse;
1937 	}
1938 
1939 	// Next is the opening brace
1940 	if (!PS_ParseToken (ps, PSF_ALLOW_NEWLINES|PSF_TO_LOWER, &token) || strcmp (token, "{")) {
1941 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1942 		GUI_PrintError ("ERROR: expecting '{' after %s <name>, got '%s'!\n", keyName, token);
1943 		return qFalse;
1944 	}
1945 
1946 	// Find out the type
1947 	// This should always be valid since we only reach this point through keyFunc's
1948 	for (type=0 ; type<WTP_MAX; type++) {
1949 		if (!strcmp (cl_windowDefTypes[type], keyName))
1950 			break;
1951 	}
1952 
1953 	// Allocate a space
1954 	if (gui) {
1955 		// Add to the parent
1956 		if (gui->numChildren+1 >= MAX_GUI_CHILDREN) {
1957 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1958 			GUI_PrintError ("ERROR: too many children!\n");
1959 			return qFalse;
1960 		}
1961 		newGUI = &gui->childList[gui->numChildren];
1962 		newGUI->parent = gui;
1963 		newGUI->shared = gui->shared;
1964 		Q_strncpyz (newGUI->name, windowName, sizeof (newGUI->name));
1965 
1966 		// Find the owner
1967 		for (owner=gui ; owner ; owner=owner->parent)
1968 			newGUI->owner = owner;
1969 
1970 		// Increment parent children
1971 		gui->numChildren++;
1972 	}
1973 	else {
1974 		// This is a parent
1975 		if (cl_numGUI+1 >= MAX_GUIS) {
1976 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
1977 			GUI_PrintError ("ERROR: too many GUIs!\n");
1978 			return qFalse;
1979 		}
1980 		newGUI = &cl_guiList[cl_numGUI];
1981 		memset (&cl_guiList[cl_numGUI], 0, sizeof (gui_t));
1982 		Q_strncpyz (newGUI->name, windowName, sizeof (newGUI->name));
1983 
1984 		newGUI->shared = &cl_guiSharedInfo[cl_numGUI];
1985 		memset (&cl_guiSharedInfo[cl_numGUI], 0, sizeof (guiShared_t));
1986 		Vec4Set (newGUI->shared->cursor.s.color, 1, 1, 1, 1);
1987 		newGUI->shared->cursor.s.visible = qTrue;
1988 
1989 		newGUI->owner = newGUI;
1990 
1991 		cl_numGUI++;
1992 	}
1993 
1994 	// Allocate space and set default values
1995 	newGUI->type = type;
1996 	Vec4Set (newGUI->s.vecRegisters[VR_MAT_COLOR].storage, 1, 1, 1, 1);
1997 	newGUI->s.floatRegisters[FR_MAT_SCALE_X].storage = 1;
1998 	newGUI->s.floatRegisters[FR_MAT_SCALE_Y].storage = 1;
1999 	newGUI->s.floatRegisters[FR_VISIBLE].storage = 1;
2000 
2001 	switch (type) {
2002 	case WTP_GUI:
2003 		break;
2004 
2005 	case WTP_GENERIC:
2006 		break;
2007 
2008 	case WTP_BIND:
2009 		newGUI->flags |= WFL_ITEM;
2010 		newGUI->s.bindDef = GUI_AllocTag (sizeof (bindDef_t) * 2, qTrue, GUITAG_SCRATCH);
2011 		newGUI->d.bindDef = newGUI->s.bindDef + 1;
2012 		break;
2013 
2014 	case WTP_CHECKBOX:
2015 		newGUI->flags |= WFL_ITEM;
2016 		newGUI->s.checkDef = GUI_AllocTag (sizeof (checkDef_t) * 2, qTrue, GUITAG_SCRATCH);
2017 		newGUI->d.checkDef = newGUI->s.checkDef + 1;
2018 
2019 		Q_strncpyz (newGUI->s.checkDef->offMatName, "guis/assets/textures/items/check_off.tga", sizeof (newGUI->s.checkDef->offMatName));
2020 		Q_strncpyz (newGUI->s.checkDef->onMatName, "guis/assets/textures/items/check_on.tga", sizeof (newGUI->s.checkDef->onMatName));
2021 		break;
2022 
2023 	case WTP_CHOICE:
2024 		newGUI->flags |= WFL_ITEM;
2025 		newGUI->s.choiceDef = GUI_AllocTag (sizeof (choiceDef_t) * 2, qTrue, GUITAG_SCRATCH);
2026 		newGUI->d.choiceDef = newGUI->s.choiceDef + 1;
2027 		break;
2028 
2029 	case WTP_EDIT:
2030 		newGUI->flags |= WFL_ITEM;
2031 		newGUI->s.editDef = GUI_AllocTag (sizeof (editDef_t) * 2, qTrue, GUITAG_SCRATCH);
2032 		newGUI->d.editDef = newGUI->s.editDef + 1;
2033 		break;
2034 
2035 	case WTP_LIST:
2036 		newGUI->flags |= WFL_ITEM;
2037 		newGUI->s.listDef = GUI_AllocTag (sizeof (listDef_t) * 2, qTrue, GUITAG_SCRATCH);
2038 		newGUI->d.listDef = newGUI->s.listDef + 1;
2039 
2040 		newGUI->s.listDef->scrollBar[0] = qTrue;
2041 		newGUI->s.listDef->scrollBar[1] = qTrue;
2042 		break;
2043 
2044 	case WTP_RENDER:
2045 		newGUI->flags |= WFL_ITEM;
2046 		newGUI->s.renderDef = GUI_AllocTag (sizeof (renderDef_t) * 2, qTrue, GUITAG_SCRATCH);
2047 		newGUI->d.renderDef = newGUI->s.renderDef + 1;
2048 		break;
2049 
2050 	case WTP_SLIDER:
2051 		newGUI->flags |= WFL_ITEM;
2052 		newGUI->s.sliderDef = GUI_AllocTag (sizeof (sliderDef_t) * 2, qTrue, GUITAG_SCRATCH);
2053 		newGUI->d.sliderDef = newGUI->s.sliderDef + 1;
2054 		break;
2055 
2056 	case WTP_TEXT:
2057 		newGUI->flags |= WFL_ITEM;
2058 		newGUI->s.textDef = GUI_AllocTag (sizeof (textDef_t) * 2, qTrue, GUITAG_SCRATCH);
2059 		newGUI->d.textDef = newGUI->s.textDef + 1;
2060 
2061 		Q_strncpyz (newGUI->s.textDef->fontName, "default", sizeof (newGUI->s.textDef->fontName));
2062 		Vec4Set (newGUI->s.vecRegisters[VR_TEXT_COLOR].storage, 1, 1, 1, 1);
2063 		newGUI->s.floatRegisters[FR_TEXT_SCALE].storage = 1;
2064 		break;
2065 	}
2066 
2067 	// Storage space for children
2068 	newGUI->numChildren = 0;
2069 	newGUI->childList = GUI_AllocTag (sizeof (gui_t) * MAX_GUI_CHILDREN, qTrue, GUITAG_SCRATCH);
2070 	newGUI->numEvents = 0;
2071 	newGUI->eventList = GUI_AllocTag (sizeof (event_t) * MAX_GUI_EVENTS, qTrue, GUITAG_SCRATCH);
2072 	newGUI->s.numDefFloats = 0;
2073 	newGUI->s.defFloatList = GUI_AllocTag (sizeof (defineFloat_t) * MAX_GUI_DEFINES, qTrue, GUITAG_SCRATCH);
2074 	newGUI->s.numDefVecs = 0;
2075 	newGUI->s.defVecList = GUI_AllocTag (sizeof (defineVec_t) * MAX_GUI_DEFINES, qTrue, GUITAG_SCRATCH);
2076 
2077 	// Parse the keys
2078 	for ( ; ; ) {
2079 		if (!PS_ParseToken (ps, PSF_ALLOW_NEWLINES|PSF_TO_LOWER, &token) || !strcmp (token, "}"))
2080 			break;
2081 
2082 		switch (type) {
2083 		case WTP_GUI:
2084 			if (!GUI_CallKeyFunc (fileName, newGUI, ps, cl_guiDefKeyList, cl_itemDefKeyList, cl_windowDefKeyList, token))
2085 				return qFalse;
2086 			break;
2087 		case WTP_GENERIC:
2088 			if (!GUI_CallKeyFunc (fileName, newGUI, ps, cl_itemDefKeyList, cl_windowDefKeyList, NULL, token))
2089 				return qFalse;
2090 			break;
2091 		case WTP_BIND:
2092 			if (!GUI_CallKeyFunc (fileName, newGUI, ps, cl_itemDefKeyList, cl_bindDefKeyList, NULL, token))
2093 				return qFalse;
2094 			break;
2095 		case WTP_CHECKBOX:
2096 			if (!GUI_CallKeyFunc (fileName, newGUI, ps, cl_itemDefKeyList, cl_checkDefKeyList, NULL, token))
2097 				return qFalse;
2098 			break;
2099 		case WTP_CHOICE:
2100 			if (!GUI_CallKeyFunc (fileName, newGUI, ps, cl_itemDefKeyList, cl_choiceDefKeyList, NULL, token))
2101 				return qFalse;
2102 			break;
2103 		case WTP_EDIT:
2104 			if (!GUI_CallKeyFunc (fileName, newGUI, ps, cl_itemDefKeyList, cl_editDefKeyList, NULL, token))
2105 				return qFalse;
2106 			break;
2107 		case WTP_LIST:
2108 			if (!GUI_CallKeyFunc (fileName, newGUI, ps, cl_itemDefKeyList, cl_listDefKeyList, NULL, token))
2109 				return qFalse;
2110 			break;
2111 		case WTP_RENDER:
2112 			if (!GUI_CallKeyFunc (fileName, newGUI, ps, cl_itemDefKeyList, cl_renderDefKeyList, NULL, token))
2113 				return qFalse;
2114 			break;
2115 		case WTP_SLIDER:
2116 			if (!GUI_CallKeyFunc (fileName, newGUI, ps, cl_itemDefKeyList, cl_sliderDefKeyList, NULL, token))
2117 				return qFalse;
2118 			break;
2119 		case WTP_TEXT:
2120 			if (!GUI_CallKeyFunc (fileName, newGUI, ps, cl_itemDefKeyList, cl_textDefKeyList, NULL, token))
2121 				return qFalse;
2122 			break;
2123 		}
2124 	}
2125 
2126 	// Final '}' closing brace
2127 	if (strcmp (token, "}")) {
2128 		GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
2129 		GUI_PrintError ("ERROR: expecting '}' after %s, got '%s'!\n", keyName, token);
2130 		return qFalse;
2131 	}
2132 
2133 	// Check for required values
2134 	switch (type) {
2135 	case WTP_CHECKBOX:
2136 		if (!newGUI->s.checkDef->cvar) {
2137 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
2138 			GUI_PrintError ("ERROR: missing required 'cvar' value!\n");
2139 			return qFalse;
2140 		}
2141 		if (!newGUI->s.checkDef->values[0] || !newGUI->s.checkDef->values[1]) {
2142 			GUI_PrintPos (PRNT_ERROR, ps, fileName, gui);
2143 			GUI_PrintError ("ERROR: missing required 'values' value!\n");
2144 			return qFalse;
2145 		}
2146 		break;
2147 	}
2148 
2149 	// Store children
2150 	childList = newGUI->childList;
2151 	if (newGUI->numChildren) {
2152 		newGUI->childList = GUI_AllocTag (sizeof (gui_t) * newGUI->numChildren, qFalse, GUITAG_SCRATCH);
2153 		memcpy (newGUI->childList, childList, sizeof (gui_t) * newGUI->numChildren);
2154 	}
2155 	else
2156 		newGUI->childList = NULL;
2157 	Mem_Free (childList);
2158 
2159 	// Store events
2160 	eventList = newGUI->eventList;
2161 	if (newGUI->numEvents) {
2162 		newGUI->eventList = GUI_AllocTag (sizeof (event_t) * newGUI->numEvents, qFalse, GUITAG_SCRATCH);
2163 		memcpy (newGUI->eventList, eventList, sizeof (event_t) * newGUI->numEvents);
2164 	}
2165 	else
2166 		newGUI->eventList = NULL;
2167 	Mem_Free (eventList);
2168 
2169 	// Store floats
2170 	defFloatList = newGUI->s.defFloatList;
2171 	if (newGUI->s.numDefFloats) {
2172 		newGUI->s.defFloatList = GUI_AllocTag (sizeof (defineFloat_t) * newGUI->s.numDefFloats, qFalse, GUITAG_SCRATCH);
2173 		memcpy (newGUI->s.defFloatList, defFloatList, sizeof (defineFloat_t) * newGUI->s.numDefFloats);
2174 
2175 		newGUI->d.defFloatList = GUI_AllocTag (sizeof (defineFloat_t) * newGUI->s.numDefFloats, qFalse, GUITAG_SCRATCH);
2176 		memcpy (newGUI->d.defFloatList, defFloatList, sizeof (defineFloat_t) * newGUI->d.numDefFloats);
2177 	}
2178 	else {
2179 		newGUI->s.defFloatList = NULL;
2180 		newGUI->d.defFloatList = NULL;
2181 	}
2182 	Mem_Free (defFloatList);
2183 
2184 	// Store vecs
2185 	defVecList = newGUI->s.defVecList;
2186 	if (newGUI->s.numDefVecs) {
2187 		newGUI->s.defVecList = GUI_AllocTag (sizeof (defineVec_t) * newGUI->s.numDefVecs, qFalse, GUITAG_SCRATCH);
2188 		memcpy (newGUI->s.defVecList, defVecList, sizeof (defineVec_t) * newGUI->s.numDefVecs);
2189 
2190 		newGUI->d.defVecList = GUI_AllocTag (sizeof (defineVec_t) * newGUI->s.numDefVecs, qFalse, GUITAG_SCRATCH);
2191 		memcpy (newGUI->d.defVecList, defVecList, sizeof (defineVec_t) * newGUI->d.numDefVecs);
2192 	}
2193 	else {
2194 		newGUI->s.defVecList = NULL;
2195 		newGUI->d.defVecList = NULL;
2196 	}
2197 	Mem_Free (defVecList);
2198 
2199 	// Done
2200 	return qTrue;
2201 }
2202 
2203 /*
2204 =============================================================================
2205 
2206 	GUI SCRIPT PARSING
2207 
2208 =============================================================================
2209 */
2210 
2211 /*
2212 ==================
2213 GUI_ParseScript
2214 ==================
2215 */
GUI_ParseScript(char * fixedName,guiPathType_t pathType)2216 static void GUI_ParseScript (char *fixedName, guiPathType_t pathType)
2217 {
2218 	char	keyName[MAX_PS_TOKCHARS];
2219 	char	*buf;
2220 	char	*token;
2221 	int		fileLen;
2222 	parse_t	*ps;
2223 
2224 	if (!fixedName)
2225 		return;
2226 
2227 	// Load the file
2228 	fileLen = FS_LoadFile (fixedName, (void **)&buf, "\n\0");
2229 	if (!buf || fileLen <= 0) {
2230 		GUI_PrintWarning ("WARNING: can't load '%s' -- %s\n", fixedName, (fileLen == -1) ? "not found" : "empty file");
2231 		return;
2232 	}
2233 
2234 	Com_Printf (0, "...loading '%s'\n", fixedName);
2235 
2236 	// Start parsing
2237 	ps = PS_StartSession (buf, PSP_COMMENT_BLOCK|PSP_COMMENT_LINE);
2238 
2239 	// Parse the script
2240 	for ( ; ; ) {
2241 		if (!PS_ParseToken (ps, PSF_ALLOW_NEWLINES|PSF_TO_LOWER, &token))
2242 			break;
2243 
2244 		// Search for a guiDef
2245 		if (strcmp (token, "guidef")) {
2246 			GUI_PrintPos (PRNT_ERROR, ps, fixedName, NULL);
2247 			GUI_PrintError ("ERROR: expecting 'guiDef' got '%s'!\n", token);
2248 			GUI_PrintError ("ERROR: removing GUI and halting on file due to errors!\n");
2249 			break;
2250 		}
2251 
2252 		// Found one, create it
2253 		Q_strncpyz (keyName, token, sizeof (keyName));
2254 		if (GUI_NewWindowDef (fixedName, NULL, ps, keyName)) {
2255 			// It parsed ok, store the pathType
2256 			cl_guiSharedInfo[cl_numGUI-1].pathType = pathType;
2257 			Mem_ChangeTag (cl_guiSysPool, GUITAG_SCRATCH, GUITAG_KEEP);
2258 		}
2259 		else {
2260 			// Failed to parse, halt!
2261 			GUI_PrintError ("ERROR: removing GUI and halting on file due to errors!\n");
2262 			memset (&cl_guiList[--cl_numGUI], 0, sizeof (gui_t));
2263 			break;
2264 		}
2265 	}
2266 
2267 	// Done
2268 	PS_AddErrorCount (ps, &cl_numGUIErrors, &cl_numGUIWarnings);
2269 	PS_EndSession (ps);
2270 	FS_FreeFile (buf);
2271 	GUI_FreeTag (GUITAG_SCRATCH);
2272 }
2273 
2274 /*
2275 =============================================================================
2276 
2277 	REGISTRATION
2278 
2279 =============================================================================
2280 */
2281 
2282 /*
2283 ==================
2284 GUI_TouchGUI
2285 ==================
2286 */
GUI_CantFindMedia(gui_t * gui,char * item,char * name)2287 static void GUI_CantFindMedia (gui_t *gui, char *item, char *name)
2288 {
2289 	if (gui && gui->name[0]) {
2290 		GUI_PrintWarning ("WARNING: GUI '%s': can't find %s '%s'\n", gui->name, item, name);
2291 		return;
2292 	}
2293 
2294 	GUI_PrintWarning ("WARNING: can't find %s '%s'\n", item, name);
2295 }
GUI_RegisterFloats(floatRegister_t * floats,int maxFloats)2296 static void GUI_RegisterFloats (floatRegister_t *floats, int maxFloats)
2297 {
2298 	int		i;
2299 
2300 	for (i=0 ; i<maxFloats ; i++) {
2301 		switch (floats[i].sourceType) {
2302 		case REG_SOURCE_SELF:
2303 			floats[i].var = &floats[i].storage;
2304 			break;
2305 		case REG_SOURCE_DEF:
2306 			floats[i].var = &floats[i].defFloatWindow->d.defFloatList[floats[i].defFloatIndex].value;
2307 			break;
2308 		case REG_SOURCE_GUIVAR:
2309 			floats[i].var = &floats[i].guiVar->floatVal;
2310 			break;
2311 		default:
2312 			assert (0);
2313 			break;
2314 		}
2315 	}
2316 }
GUI_RegisterVecs(vecRegister_t * vecs,int maxVecs)2317 static void GUI_RegisterVecs (vecRegister_t *vecs, int maxVecs)
2318 {
2319 	int		i;
2320 
2321 	for (i=0 ; i<maxVecs ; i++) {
2322 		switch (vecs[i].sourceType) {
2323 		case REG_SOURCE_SELF:
2324 			vecs[i].var = &vecs[i].storage[0];
2325 			break;
2326 		case REG_SOURCE_DEF:
2327 			vecs[i].var = &vecs[i].defVecWindow->d.defVecList[vecs[i].defVecIndex].value[0];
2328 			break;
2329 		case REG_SOURCE_GUIVAR:
2330 			vecs[i].var = &vecs[i].guiVar->vecVal[0];
2331 			break;
2332 		default:
2333 			assert (0);
2334 			break;
2335 		}
2336 	}
2337 }
GUI_r_TouchGUI(gui_t * gui)2338 static void GUI_r_TouchGUI (gui_t *gui)
2339 {
2340 	gui_t		*child;
2341 	event_t		*event;
2342 	evAction_t	*action;
2343 	int			i, j;
2344 	short		index;
2345 
2346 	// Load generic media
2347 	if (gui->flags & WFL_MATERIAL) {
2348 		gui->matShader = R_RegisterPic (gui->matName);
2349 		if (!gui->matShader)
2350 			GUI_CantFindMedia (gui, "Material", gui->matName);
2351 	}
2352 
2353 	GUI_RegisterFloats (gui->s.floatRegisters, FR_MAX);
2354 	GUI_RegisterVecs (gui->s.vecRegisters, VR_MAX);
2355 
2356 	// Load type-specific media
2357 	switch (gui->type) {
2358 	case WTP_GUI:
2359 		break;
2360 
2361 	case WTP_GENERIC:
2362 		break;
2363 
2364 	case WTP_BIND:
2365 		break;
2366 
2367 	case WTP_CHECKBOX:
2368 		// Find on/off materials
2369 		gui->s.checkDef->offMatPtr = R_RegisterPic (gui->s.checkDef->offMatName);
2370 		if (!gui->s.checkDef->offMatPtr) {
2371 			GUI_CantFindMedia (gui, "offMat", gui->s.checkDef->offMatName);
2372 			break;
2373 		}
2374 		gui->s.checkDef->onMatPtr = R_RegisterPic (gui->s.checkDef->onMatName);
2375 		if (!gui->s.checkDef->onMatPtr) {
2376 			GUI_CantFindMedia (gui, "onMat", gui->s.checkDef->onMatName);
2377 			break;
2378 		}
2379 		break;
2380 
2381 	case WTP_CHOICE:
2382 		break;
2383 
2384 	case WTP_EDIT:
2385 		break;
2386 
2387 	case WTP_LIST:
2388 		break;
2389 
2390 	case WTP_RENDER:
2391 		break;
2392 
2393 	case WTP_SLIDER:
2394 		break;
2395 
2396 	case WTP_TEXT:
2397 		// Find the font
2398 		gui->s.textDef->fontPtr = R_RegisterFont (gui->s.textDef->fontName);
2399 		if (!gui->s.textDef->fontPtr)
2400 			GUI_CantFindMedia (gui, "Font", gui->s.textDef->fontName);
2401 		break;
2402 	}
2403 
2404 	// Load event-action specific media
2405 	for (i=0, event=gui->eventList ; i<gui->numEvents ; event++, i++) {
2406 		for (j=0, action=event->actionList ; j<event->numActions ; action++, j++) {
2407 			switch (action->type) {
2408 			case EVA_CLOSE:
2409 				break;
2410 
2411 			case EVA_COMMAND:
2412 				break;
2413 
2414 			case EVA_IF:
2415 				break;
2416 
2417 			case EVA_LOCAL_SOUND:
2418 				// Find the sound
2419 				action->localSound->sound = Snd_RegisterSound (action->localSound->name);
2420 				if (!action->localSound->sound)
2421 					GUI_CantFindMedia (gui, "Sound", action->localSound->name);
2422 				break;
2423 
2424 			case EVA_NAMED_EVENT:
2425 				// Find the window
2426 				action->named->destWindowPtr = GUI_FindWindow (gui->owner, action->named->destWindowName);
2427 				if (!action->named->destWindowPtr) {
2428 					GUI_CantFindMedia (gui, "Window", action->named->destWindowName);
2429 					break;
2430 				}
2431 				break;
2432 
2433 			case EVA_RESET_TIME:
2434 				break;
2435 
2436 			case EVA_SET:
2437 				// Find the destination window
2438 				action->set->destWindowPtr = GUI_FindWindow (gui->owner, action->set->destWindowName);
2439 				if (!action->set->destWindowPtr) {
2440 					GUI_CantFindMedia (gui, "Window", action->set->destWindowName);
2441 					break;
2442 				}
2443 
2444 				// Check if it's allowed
2445 				if (action->set->destWindowType != WTP_MAX && action->set->destWindowPtr->type != action->set->destWindowType)  {
2446 					GUI_PrintError ("ERROR: Invalid set action destination '%s::%s'!\n", action->set->destWindowPtr->name, action->set->destVarName);
2447 					action->set->destWindowPtr = NULL;
2448 					break;
2449 				}
2450 
2451 				switch (action->set->srcType) {
2452 				case EVA_SETSRC_DEF:
2453 					// Find the source window
2454 					action->set->srcWindowPtr = GUI_FindWindow (gui->owner, action->set->srcWindowName);
2455 					if (!action->set->srcWindowPtr) {
2456 						GUI_CantFindMedia (gui, "Window", action->set->srcWindowName);
2457 						break;
2458 					}
2459 
2460 					// Find the source defineFloat/defineVec
2461 					if (action->set->destType & EVA_SETDEST_FLOAT)
2462 						index = GUI_FindDefFloat (action->set->srcWindowPtr, action->set->srcName);
2463 					else if (action->set->destType & EVA_SETDEST_VEC)
2464 						index = GUI_FindDefVec (action->set->srcWindowPtr, action->set->srcName);
2465 					if (index == -1) {
2466 						GUI_CantFindMedia (gui, "Define", action->set->srcName);
2467 						break;
2468 					}
2469 					break;
2470 
2471 				case EVA_SETSRC_GUIVAR:
2472 					// Register the GUIVar
2473 					if (action->set->destType & EVA_SETDEST_FLOAT)
2474 						action->set->srcGUIVar = GUIVar_Register (action->set->srcName, GVT_FLOAT);
2475 					else if (action->set->destType & EVA_SETDEST_VEC)
2476 						action->set->srcGUIVar = GUIVar_Register (action->set->srcName, GVT_VEC);
2477 					break;
2478 				}
2479 				break;
2480 
2481 			case EVA_STOP_TRANSITIONS:
2482 				break;
2483 
2484 			case EVA_TRANSITION:
2485 				break;
2486 			}
2487 		}
2488 	}
2489 
2490 	// Recurse down the children
2491 	for (i=0, child=gui->childList ; i<gui->numChildren ; child++, i++)
2492 		GUI_r_TouchGUI (child);
2493 }
GUI_TouchGUI(gui_t * gui)2494 static void GUI_TouchGUI (gui_t *gui)
2495 {
2496 	// Register cursor media
2497 	if (gui->flags & WFL_CURSOR) {
2498 		gui->shared->cursor.s.matPtr = R_RegisterPic (gui->shared->cursor.s.matName);
2499 		if (!gui->shared->cursor.s.matPtr)
2500 			GUI_CantFindMedia (gui, "cursorMat", gui->shared->cursor.s.matName);
2501 	}
2502 
2503 	// Register base media
2504 	GUI_r_TouchGUI (gui);
2505 }
2506 
2507 
2508 /*
2509 ==================
2510 GUI_RegisterGUI
2511 ==================
2512 */
GUI_RegisterGUI(char * name)2513 gui_t *GUI_RegisterGUI (char *name)
2514 {
2515 	gui_t	*gui;
2516 
2517 	// Find it
2518 	gui = GUI_FindGUI (name);
2519 	if (!gui)
2520 		return NULL;
2521 
2522 	// Touch it
2523 	GUI_TouchGUI (gui);
2524 	cl_guiRegTouched[gui-&cl_guiList[0]] = cl_guiRegFrameNum;
2525 
2526 	// Reset state
2527 	GUI_ResetGUIState (gui);
2528 	return gui;
2529 }
2530 
2531 
2532 /*
2533 ==================
2534 GUI_RegisterSounds
2535 
2536 On snd_restart this will be called.
2537 ==================
2538 */
GUI_RegisterSounds(void)2539 void GUI_RegisterSounds (void)
2540 {
2541 	// FIXME: k just register sounds again
2542 	GUI_EndRegistration ();
2543 }
2544 
2545 
2546 /*
2547 ==================
2548 GUI_BeginRegistration
2549 ==================
2550 */
GUI_BeginRegistration(void)2551 void GUI_BeginRegistration (void)
2552 {
2553 	cl_guiRegFrameNum++;
2554 }
2555 
2556 
2557 /*
2558 ==================
2559 GUI_EndRegistration
2560 ==================
2561 */
GUI_EndRegistration(void)2562 void GUI_EndRegistration (void)
2563 {
2564 	gui_t	*gui;
2565 	uint32	i;
2566 
2567 	// Register media specific to GUI windows
2568 	for (i=0, gui=cl_guiList ; i<cl_numGUI ; gui++, i++) {
2569 		if (cl_guiRegTouched[i] != cl_guiRegFrameNum
2570 		&& cl_guiRegFrames[i] != cl_guiRegFrameNum)
2571 			continue;	// Don't touch if already touched and if it wasn't scheduled for a touch
2572 
2573 		cl_guiRegTouched[i] = cl_guiRegFrameNum;
2574 		GUI_TouchGUI (gui);
2575 	}
2576 }
2577 
2578 /*
2579 =============================================================================
2580 
2581 	INIT / SHUTDOWN
2582 
2583 =============================================================================
2584 */
2585 
2586 static void *cmd_gui_list;
2587 static void *cmd_gui_namedEvent;
2588 static void	*cmd_gui_restart;
2589 static void *cmd_gui_test;
2590 
2591 /*
2592 ==================
2593 GUI_List_f
2594 ==================
2595 */
GUI_r_List_f(gui_t * window,uint32 depth)2596 static void GUI_r_List_f (gui_t *window, uint32 depth)
2597 {
2598 	gui_t	*child;
2599 	uint32	i;
2600 
2601 	for (i=0 ; i<depth ; i++)
2602 		Com_Printf (0, "   ");
2603 	Com_Printf (0, "%s (%i children)\n", window->name, window->numChildren);
2604 
2605 	// Recurse down the children
2606 	for (i=0, child=window->childList ; i<window->numChildren ; child++, i++)
2607 		GUI_r_List_f (child, depth+1);
2608 }
GUI_List_f(void)2609 static void GUI_List_f (void)
2610 {
2611 	gui_t	*gui;
2612 	uint32	i;
2613 
2614 	// List all GUIs and their child windows
2615 	for (i=0, gui=cl_guiList ; i<cl_numGUI ; gui++, i++) {
2616 		Com_Printf (0, "#%2i GUI %s (%i children)\n", i+1, gui->name, gui->numChildren);
2617 		GUI_r_List_f (gui, 0);
2618 	}
2619 }
2620 
2621 
2622 /*
2623 ==================
2624 GUI_NamedEvent_f
2625 ==================
2626 */
GUI_NamedEvent_f(void)2627 static void GUI_NamedEvent_f (void)
2628 {
2629 	if (Cmd_Argc () < 2) {
2630 		Com_Printf (0, "Usage: gui_namedEvent <event name>\n");
2631 		return;
2632 	}
2633 
2634 	GUI_NamedGlobalEvent (Cmd_Argv (1));
2635 }
2636 
2637 
2638 /*
2639 ==================
2640 GUI_Restart_f
2641 ==================
2642 */
GUI_Restart_f(void)2643 static void GUI_Restart_f (void)
2644 {
2645 	GUI_Shutdown ();
2646 	GUI_Init ();
2647 }
2648 
2649 
2650 /*
2651 ==================
2652 GUI_Test_f
2653 ==================
2654 */
GUI_Test_f(void)2655 static void GUI_Test_f (void)
2656 {
2657 	gui_t	*gui;
2658 
2659 	if (Cmd_Argc () < 2) {
2660 		Com_Printf (0, "Usage: gui_test <GUI name>\n");
2661 		return;
2662 	}
2663 
2664 	// Find it and touch it
2665 	gui = GUI_RegisterGUI (Cmd_Argv (1));
2666 	if (!gui) {
2667 		Com_Printf (0, "Not found...\n");
2668 		return;
2669 	}
2670 
2671 	// Open it
2672 	GUI_OpenGUI (gui);
2673 }
2674 
2675 
2676 /*
2677 ==================
2678 GUI_Init
2679 ==================
2680 */
GUI_Init(void)2681 void GUI_Init (void)
2682 {
2683 	char			*guiList[MAX_GUIS];
2684 	char			fixedName[MAX_QPATH];
2685 	uint32			numGUI, i;
2686 	guiPathType_t	pathType;
2687 	char			*name;
2688 	uint32			initTime;
2689 
2690 	initTime = Sys_UMilliseconds ();
2691 	Com_Printf (0, "\n---------- GUI Initialization ----------\n");
2692 
2693 	// Clear lists
2694 	cl_numGUI = 0;
2695 	memset (&cl_guiList[0], 0, sizeof (gui_t) * MAX_GUIS);
2696 	memset (&cl_guiSharedInfo[0], 0, sizeof (guiShared_t) * MAX_GUIS);
2697 
2698 	// Console commands
2699 	cmd_gui_list		= Cmd_AddCommand ("gui_list",		GUI_List_f,			"List GUIs in memory");
2700 	cmd_gui_namedEvent	= Cmd_AddCommand ("gui_namedEvent",	GUI_NamedEvent_f,	"Triggers a named event on all open GUIs (for debugging)");
2701 	cmd_gui_restart		= Cmd_AddCommand ("gui_restart",	GUI_Restart_f,		"Restart the GUI system");
2702 	cmd_gui_test		= Cmd_AddCommand ("gui_test",		GUI_Test_f,			"Test the specified GUI");
2703 
2704 	// Cvars
2705 	gui_developer			= Cvar_Register ("gui_developer",				"0",		0);
2706 	gui_debugBounds			= Cvar_Register ("gui_debugBounds",				"0",		0);
2707 	gui_debugScale			= Cvar_Register ("gui_debugScale",				"0",		0);
2708 	gui_mouseFilter			= Cvar_Register ("gui_mouseFilter",				"1",		CVAR_ARCHIVE);
2709 	gui_mouseSensitivity	= Cvar_Register ("gui_mouseSensitivity",		"2",		CVAR_ARCHIVE);
2710 
2711 	// Load scripts
2712 	cl_numGUIErrors = 0;
2713 	cl_numGUIWarnings = 0;
2714 	numGUI = FS_FindFiles ("guis", "*guis/*.gui", "gui", guiList, MAX_GUIS, qTrue, qFalse);
2715 	for (i=0 ; i<numGUI ; i++) {
2716 		// Fix the path
2717 		Com_NormalizePath (fixedName, sizeof (fixedName), guiList[i]);
2718 
2719 		// Skip the path
2720 		name = strstr (fixedName, "/guis/");
2721 		if (!name)
2722 			continue;
2723 		name++;	// Skip the initial '/'
2724 
2725 		// Base dir GUI?
2726 		if (strstr (guiList[i], BASE_MODDIRNAME "/"))
2727 			pathType = GUIPT_BASEDIR;
2728 		else
2729 			pathType = GUIPT_MODDIR;
2730 
2731 		// Parse it
2732 		GUI_ParseScript (name, pathType);
2733 	}
2734 	FS_FreeFileList (guiList, numGUI);
2735 
2736 	// Free auxillery (scratch space) tags
2737 	GUI_FreeTag (GUITAG_SCRATCH);
2738 
2739 	// Var init
2740 	GUIVar_Init ();
2741 
2742 	Com_Printf (0, "----------------------------------------\n");
2743 
2744 	// Check memory integrity
2745 	Mem_CheckPoolIntegrity (cl_guiSysPool);
2746 
2747 	Com_Printf (0, "GUI - %i error(s), %i warning(s)\n", cl_numGUIErrors, cl_numGUIWarnings);
2748 	Com_Printf (0, "%u GUIs loaded in %ums\n", cl_numGUI, Sys_UMilliseconds()-initTime);
2749 	Com_Printf (0, "----------------------------------------\n");
2750 }
2751 
2752 
2753 /*
2754 ==================
2755 GUI_Shutdown
2756 
2757 Only called by gui_restart (for development purposes generally).
2758 ==================
2759 */
GUI_Shutdown(void)2760 void GUI_Shutdown (void)
2761 {
2762 	// Close all open GUIs
2763 	GUI_CloseAllGUIs ();
2764 
2765 	// Shutdown GUI vars
2766 	GUIVar_Shutdown ();
2767 
2768 	// Remove commands
2769 	Cmd_RemoveCommand ("gui_list", cmd_gui_list);
2770 	Cmd_RemoveCommand ("gui_namedEvent", cmd_gui_namedEvent);
2771 	Cmd_RemoveCommand ("gui_restart", cmd_gui_restart);
2772 	Cmd_RemoveCommand ("gui_test", cmd_gui_test);
2773 
2774 	// Release all used memory
2775 	Mem_FreePool (cl_guiSysPool);
2776 }
2777