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