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