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