1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 //
23 /**********************************************************************
24 	UI_QMENU.C
25 
26 	Quake's menu framework system.
27 **********************************************************************/
28 #include "ui_local.h"
29 
30 sfxHandle_t menu_in_sound;
31 sfxHandle_t menu_move_sound;
32 sfxHandle_t menu_out_sound;
33 sfxHandle_t menu_buzz_sound;
34 sfxHandle_t menu_null_sound;
35 sfxHandle_t weaponChangeSound;
36 
37 static qhandle_t	sliderBar;
38 static qhandle_t	sliderButton_0;
39 static qhandle_t	sliderButton_1;
40 
41 vec4_t menu_text_color	    = {1.0f, 1.0f, 1.0f, 1.0f};
42 vec4_t menu_dim_color       = {0.0f, 0.0f, 0.0f, 0.75f};
43 vec4_t color_black	    = {0.00f, 0.00f, 0.00f, 1.00f};
44 vec4_t color_white	    = {1.00f, 1.00f, 1.00f, 1.00f};
45 vec4_t color_yellow	    = {1.00f, 1.00f, 0.00f, 1.00f};
46 vec4_t color_blue	    = {0.00f, 0.00f, 1.00f, 1.00f};
47 vec4_t color_lightOrange    = {1.00f, 0.68f, 0.00f, 1.00f };
48 vec4_t color_orange	    = {1.00f, 0.43f, 0.00f, 1.00f};
49 vec4_t color_red	    = {1.00f, 0.00f, 0.00f, 1.00f};
50 vec4_t color_dim	    = {0.00f, 0.00f, 0.00f, 0.25f};
51 
52 // current color scheme
53 vec4_t pulse_color          = {1.00f, 1.00f, 1.00f, 1.00f};
54 vec4_t text_color_disabled  = {0.50f, 0.50f, 0.50f, 1.00f};	// light gray
55 vec4_t text_color_normal    = {1.00f, 0.43f, 0.00f, 1.00f};	// light orange
56 vec4_t text_color_highlight = {1.00f, 1.00f, 0.00f, 1.00f};	// bright yellow
57 vec4_t listbar_color        = {1.00f, 0.43f, 0.00f, 0.30f};	// transluscent orange
58 vec4_t text_color_status    = {1.00f, 1.00f, 1.00f, 1.00f};	// bright white
59 
60 // action widget
61 static void	Action_Init( menuaction_s *a );
62 static void	Action_Draw( menuaction_s *a );
63 
64 // radio button widget
65 static void	RadioButton_Init( menuradiobutton_s *rb );
66 static void	RadioButton_Draw( menuradiobutton_s *rb );
67 static sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key );
68 
69 // slider widget
70 static void Slider_Init( menuslider_s *s );
71 static sfxHandle_t Slider_Key( menuslider_s *s, int key );
72 static void	Slider_Draw( menuslider_s *s );
73 
74 // spin control widget
75 static void	SpinControl_Init( menulist_s *s );
76 static void	SpinControl_Draw( menulist_s *s );
77 static sfxHandle_t SpinControl_Key( menulist_s *l, int key );
78 
79 // text widget
80 static void Text_Init( menutext_s *b );
81 static void Text_Draw( menutext_s *b );
82 
83 // scrolllist widget
84 static void	ScrollList_Init( menulist_s *l );
85 sfxHandle_t ScrollList_Key( menulist_s *l, int key );
86 
87 // proportional text widget
88 static void PText_Init( menutext_s *b );
89 static void PText_Draw( menutext_s *b );
90 
91 // proportional banner text widget
92 static void BText_Init( menutext_s *b );
93 static void BText_Draw( menutext_s *b );
94 
95 /*
96 =================
97 Text_Init
98 =================
99 */
Text_Init(menutext_s * t)100 static void Text_Init( menutext_s *t )
101 {
102 	t->generic.flags |= QMF_INACTIVE;
103 }
104 
105 /*
106 =================
107 Text_Draw
108 =================
109 */
Text_Draw(menutext_s * t)110 static void Text_Draw( menutext_s *t )
111 {
112 	int		x;
113 	int		y;
114 	char	buff[512];
115 	float*	color;
116 
117 	x = t->generic.x;
118 	y = t->generic.y;
119 
120 	buff[0] = '\0';
121 
122 	// possible label
123 	if (t->generic.name)
124 		strcpy(buff,t->generic.name);
125 
126 	// possible value
127 	if (t->string)
128 		strcat(buff,t->string);
129 
130 	if (t->generic.flags & QMF_GRAYED)
131 		color = text_color_disabled;
132 	else
133 		color = t->color;
134 
135 	UI_DrawString( x, y, buff, t->style, color );
136 }
137 
138 /*
139 =================
140 BText_Init
141 =================
142 */
BText_Init(menutext_s * t)143 static void BText_Init( menutext_s *t )
144 {
145 	t->generic.flags |= QMF_INACTIVE;
146 }
147 
148 /*
149 =================
150 BText_Draw
151 =================
152 */
BText_Draw(menutext_s * t)153 static void BText_Draw( menutext_s *t )
154 {
155 	int		x;
156 	int		y;
157 	float*	color;
158 
159 	x = t->generic.x;
160 	y = t->generic.y;
161 
162 	if (t->generic.flags & QMF_GRAYED)
163 		color = text_color_disabled;
164 	else
165 		color = t->color;
166 
167 	UI_DrawBannerString( x, y, t->string, t->style, color );
168 }
169 
170 /*
171 =================
172 PText_Init
173 =================
174 */
PText_Init(menutext_s * t)175 static void PText_Init( menutext_s *t )
176 {
177 	int	x;
178 	int	y;
179 	int	w;
180 	int	h;
181 	float	sizeScale;
182 
183 	sizeScale = UI_ProportionalSizeScale( t->style );
184 
185 	x = t->generic.x;
186 	y = t->generic.y;
187 	w = UI_ProportionalStringWidth( t->string ) * sizeScale;
188 	h =	PROP_HEIGHT * sizeScale;
189 
190 	if( t->generic.flags & QMF_RIGHT_JUSTIFY ) {
191 		x -= w;
192 	}
193 	else if( t->generic.flags & QMF_CENTER_JUSTIFY ) {
194 		x -= w / 2;
195 	}
196 
197 	t->generic.left   = x - PROP_GAP_WIDTH * sizeScale;
198 	t->generic.right  = x + w + PROP_GAP_WIDTH * sizeScale;
199 	t->generic.top    = y;
200 	t->generic.bottom = y + h;
201 }
202 
203 /*
204 =================
205 PText_Draw
206 =================
207 */
PText_Draw(menutext_s * t)208 static void PText_Draw( menutext_s *t )
209 {
210 	int		x;
211 	int		y;
212 	float *	color;
213 	int		style;
214 
215 	x = t->generic.x;
216 	y = t->generic.y;
217 
218 	if (t->generic.flags & QMF_GRAYED)
219 		color = text_color_disabled;
220 	else
221 		color = t->color;
222 
223 	style = t->style;
224 	if( t->generic.flags & QMF_PULSEIFFOCUS ) {
225 		if( Menu_ItemAtCursor( t->generic.parent ) == t ) {
226 			style |= UI_PULSE;
227 		}
228 		else {
229 			style |= UI_INVERSE;
230 		}
231 	}
232 
233 	UI_DrawProportionalString( x, y, t->string, style, color );
234 }
235 
236 /*
237 =================
238 Bitmap_Init
239 =================
240 */
Bitmap_Init(menubitmap_s * b)241 void Bitmap_Init( menubitmap_s *b )
242 {
243 	int	x;
244 	int	y;
245 	int	w;
246 	int	h;
247 
248 	x = b->generic.x;
249 	y = b->generic.y;
250 	w = b->width;
251 	h =	b->height;
252 	if( w < 0 ) {
253 		w = -w;
254 	}
255 	if( h < 0 ) {
256 		h = -h;
257 	}
258 
259 	if (b->generic.flags & QMF_RIGHT_JUSTIFY)
260 	{
261 		x = x - w;
262 	}
263 	else if (b->generic.flags & QMF_CENTER_JUSTIFY)
264 	{
265 		x = x - w/2;
266 	}
267 
268 	b->generic.left   = x;
269 	b->generic.right  = x + w;
270 	b->generic.top    = y;
271 	b->generic.bottom = y + h;
272 
273 	b->shader      = 0;
274 	b->focusshader = 0;
275 }
276 
277 /*
278 =================
279 Bitmap_Draw
280 =================
281 */
Bitmap_Draw(menubitmap_s * b)282 void Bitmap_Draw( menubitmap_s *b )
283 {
284 	float	x;
285 	float	y;
286 	float	w;
287 	float	h;
288 	vec4_t	tempcolor;
289 	float*	color;
290 
291 	x = b->generic.x;
292 	y = b->generic.y;
293 	w = b->width;
294 	h =	b->height;
295 
296 	if (b->generic.flags & QMF_RIGHT_JUSTIFY)
297 	{
298 		x = x - w;
299 	}
300 	else if (b->generic.flags & QMF_CENTER_JUSTIFY)
301 	{
302 		x = x - w/2;
303 	}
304 
305 	// used to refresh shader
306 	if (b->generic.name && !b->shader)
307 	{
308 		b->shader = trap_R_RegisterShaderNoMip( b->generic.name );
309 		if (!b->shader && b->errorpic)
310 			b->shader = trap_R_RegisterShaderNoMip( b->errorpic );
311 	}
312 
313 	if (b->focuspic && !b->focusshader)
314 		b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );
315 
316 	if (b->generic.flags & QMF_GRAYED)
317 	{
318 		if (b->shader)
319 		{
320 			trap_R_SetColor( colorMdGrey );
321 			UI_DrawHandlePic( x, y, w, h, b->shader );
322 			trap_R_SetColor( NULL );
323 		}
324 	}
325 	else
326 	{
327 		if (b->shader)
328 			UI_DrawHandlePic( x, y, w, h, b->shader );
329 
330 		if (  ( (b->generic.flags & QMF_PULSE)
331 			|| (b->generic.flags & QMF_PULSEIFFOCUS) )
332 		      && (Menu_ItemAtCursor( b->generic.parent ) == b))
333 		{
334 			if (b->focuscolor)
335 			{
336 				tempcolor[0] = b->focuscolor[0];
337 				tempcolor[1] = b->focuscolor[1];
338 				tempcolor[2] = b->focuscolor[2];
339 				color        = tempcolor;
340 			}
341 			else
342 				color = pulse_color;
343 			color[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR);
344 
345 			trap_R_SetColor( color );
346 			UI_DrawHandlePic( x, y, w, h, b->focusshader );
347 			trap_R_SetColor( NULL );
348 		}
349 		else if ((b->generic.flags & QMF_HIGHLIGHT) || ((b->generic.flags & QMF_HIGHLIGHT_IF_FOCUS) && (Menu_ItemAtCursor( b->generic.parent ) == b)))
350 		{
351 			if (b->focuscolor)
352 			{
353 				trap_R_SetColor( b->focuscolor );
354 				UI_DrawHandlePic( x, y, w, h, b->focusshader );
355 				trap_R_SetColor( NULL );
356 			}
357 			else
358 				UI_DrawHandlePic( x, y, w, h, b->focusshader );
359 		}
360 	}
361 }
362 
363 /*
364 =================
365 Action_Init
366 =================
367 */
Action_Init(menuaction_s * a)368 static void Action_Init( menuaction_s *a )
369 {
370 	int	len;
371 
372 	// calculate bounds
373 	if (a->generic.name)
374 		len = strlen(a->generic.name);
375 	else
376 		len = 0;
377 
378 	// left justify text
379 	a->generic.left   = a->generic.x;
380 	a->generic.right  = a->generic.x + len*BIGCHAR_WIDTH;
381 	a->generic.top    = a->generic.y;
382 	a->generic.bottom = a->generic.y + BIGCHAR_HEIGHT;
383 }
384 
385 /*
386 =================
387 Action_Draw
388 =================
389 */
Action_Draw(menuaction_s * a)390 static void Action_Draw( menuaction_s *a )
391 {
392 	int		x, y;
393 	int		style;
394 	float*	color;
395 
396 	style = 0;
397 	color = menu_text_color;
398 	if ( a->generic.flags & QMF_GRAYED )
399 	{
400 		color = text_color_disabled;
401 	}
402 	else if (( a->generic.flags & QMF_PULSEIFFOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition ))
403 	{
404 		color = text_color_highlight;
405 		style = UI_PULSE;
406 	}
407 	else if (( a->generic.flags & QMF_HIGHLIGHT_IF_FOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition ))
408 	{
409 		color = text_color_highlight;
410 	}
411 	else if ( a->generic.flags & QMF_BLINK )
412 	{
413 		style = UI_BLINK;
414 		color = text_color_highlight;
415 	}
416 
417 	x = a->generic.x;
418 	y = a->generic.y;
419 
420 	UI_DrawString( x, y, a->generic.name, UI_LEFT|style, color );
421 
422 	if ( a->generic.parent->cursor == a->generic.menuPosition )
423 	{
424 		// draw cursor
425 		UI_DrawChar( x - BIGCHAR_WIDTH, y, 13, UI_LEFT|UI_BLINK, color);
426 	}
427 }
428 
429 /*
430 =================
431 RadioButton_Init
432 =================
433 */
RadioButton_Init(menuradiobutton_s * rb)434 static void RadioButton_Init( menuradiobutton_s *rb )
435 {
436 	int	len;
437 
438 	// calculate bounds
439 	if (rb->generic.name)
440 		len = strlen(rb->generic.name);
441 	else
442 		len = 0;
443 
444 	rb->generic.left   = rb->generic.x - (len+1)*SMALLCHAR_WIDTH;
445 	rb->generic.right  = rb->generic.x + 6*SMALLCHAR_WIDTH;
446 	rb->generic.top    = rb->generic.y;
447 	rb->generic.bottom = rb->generic.y + SMALLCHAR_HEIGHT;
448 }
449 
450 /*
451 =================
452 RadioButton_Key
453 =================
454 */
RadioButton_Key(menuradiobutton_s * rb,int key)455 static sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key )
456 {
457 	switch (key)
458 	{
459 		case K_MOUSE1:
460 			if (!(rb->generic.flags & QMF_HASMOUSEFOCUS))
461 				break;
462 
463 		case K_JOY1:
464 		case K_JOY2:
465 		case K_JOY3:
466 		case K_JOY4:
467 		case K_ENTER:
468 		case K_KP_ENTER:
469 		case K_KP_LEFTARROW:
470 		case K_LEFTARROW:
471 		case K_KP_RIGHTARROW:
472 		case K_RIGHTARROW:
473 			rb->curvalue = !rb->curvalue;
474 			if ( rb->generic.callback )
475 				rb->generic.callback( rb, QM_ACTIVATED );
476 
477 			return (menu_move_sound);
478 	}
479 
480 	// key not handled
481 	return 0;
482 }
483 
484 /*
485 =================
486 RadioButton_Draw
487 =================
488 */
RadioButton_Draw(menuradiobutton_s * rb)489 static void RadioButton_Draw( menuradiobutton_s *rb )
490 {
491 	int	x;
492 	int y;
493 	float *color;
494 	int	style;
495 	qboolean focus;
496 
497 	x = rb->generic.x;
498 	y = rb->generic.y;
499 
500 	focus = (rb->generic.parent->cursor == rb->generic.menuPosition);
501 
502 	if ( rb->generic.flags & QMF_GRAYED )
503 	{
504 		color = text_color_disabled;
505 		style = UI_LEFT|UI_SMALLFONT;
506 	}
507 	else if ( focus )
508 	{
509 		color = text_color_highlight;
510 		style = UI_LEFT|UI_PULSE|UI_SMALLFONT;
511 	}
512 	else
513 	{
514 		color = text_color_normal;
515 		style = UI_LEFT|UI_SMALLFONT;
516 	}
517 
518 	if ( focus )
519 	{
520 		// draw cursor
521 		UI_FillRect( rb->generic.left, rb->generic.top, rb->generic.right-rb->generic.left+1, rb->generic.bottom-rb->generic.top+1, listbar_color );
522 		UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
523 	}
524 
525 	if ( rb->generic.name )
526 		UI_DrawString( x - SMALLCHAR_WIDTH, y, rb->generic.name, UI_RIGHT|UI_SMALLFONT, color );
527 
528 	if ( !rb->curvalue )
529 	{
530 		UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_off);
531 		UI_DrawString( x + SMALLCHAR_WIDTH + 16, y, "off", style, color );
532 	}
533 	else
534 	{
535 		UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_on );
536 		UI_DrawString( x + SMALLCHAR_WIDTH + 16, y, "on", style, color );
537 	}
538 }
539 
540 /*
541 =================
542 Slider_Init
543 =================
544 */
Slider_Init(menuslider_s * s)545 static void Slider_Init( menuslider_s *s )
546 {
547 	int len;
548 
549 	// calculate bounds
550 	if (s->generic.name)
551 		len = strlen(s->generic.name);
552 	else
553 		len = 0;
554 
555 	s->generic.left   = s->generic.x - (len+1)*SMALLCHAR_WIDTH;
556 	s->generic.right  = s->generic.x + (SLIDER_RANGE+2+1)*SMALLCHAR_WIDTH;
557 	s->generic.top    = s->generic.y;
558 	s->generic.bottom = s->generic.y + SMALLCHAR_HEIGHT;
559 }
560 
561 /*
562 =================
563 Slider_Key
564 =================
565 */
Slider_Key(menuslider_s * s,int key)566 static sfxHandle_t Slider_Key( menuslider_s *s, int key )
567 {
568 	sfxHandle_t	sound;
569 	int			x;
570 	int			oldvalue;
571 
572 	switch (key)
573 	{
574 		case K_MOUSE1:
575 			x           = uis.cursorx - s->generic.x - 2*SMALLCHAR_WIDTH;
576 			oldvalue    = s->curvalue;
577 			s->curvalue = (x/(float)(SLIDER_RANGE*SMALLCHAR_WIDTH)) * (s->maxvalue-s->minvalue) + s->minvalue;
578 
579 			if (s->curvalue < s->minvalue)
580 				s->curvalue = s->minvalue;
581 			else if (s->curvalue > s->maxvalue)
582 				s->curvalue = s->maxvalue;
583 			if (s->curvalue != oldvalue)
584 				sound = menu_move_sound;
585 			else
586 				sound = 0;
587 			break;
588 
589 		case K_KP_LEFTARROW:
590 		case K_LEFTARROW:
591 			if (s->curvalue > s->minvalue)
592 			{
593 				s->curvalue--;
594 				sound = menu_move_sound;
595 			}
596 			else
597 				sound = menu_buzz_sound;
598 			break;
599 
600 		case K_KP_RIGHTARROW:
601 		case K_RIGHTARROW:
602 			if (s->curvalue < s->maxvalue)
603 			{
604 				s->curvalue++;
605 				sound = menu_move_sound;
606 			}
607 			else
608 				sound = menu_buzz_sound;
609 			break;
610 
611 		default:
612 			// key not handled
613 			sound = 0;
614 			break;
615 	}
616 
617 	if ( sound && s->generic.callback )
618 		s->generic.callback( s, QM_ACTIVATED );
619 
620 	return (sound);
621 }
622 
623 #if 1
624 /*
625 =================
626 Slider_Draw
627 =================
628 */
Slider_Draw(menuslider_s * s)629 static void Slider_Draw( menuslider_s *s ) {
630 	int			x;
631 	int			y;
632 	int			style;
633 	float		*color;
634 	int			button;
635 	qboolean	focus;
636 
637 	x =	s->generic.x;
638 	y = s->generic.y;
639 	focus = (s->generic.parent->cursor == s->generic.menuPosition);
640 
641 	if( s->generic.flags & QMF_GRAYED ) {
642 		color = text_color_disabled;
643 		style = UI_SMALLFONT;
644 	}
645 	else if( focus ) {
646 		color  = text_color_highlight;
647 		style = UI_SMALLFONT | UI_PULSE;
648 	}
649 	else {
650 		color = text_color_normal;
651 		style = UI_SMALLFONT;
652 	}
653 
654 	// draw label
655 	UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color );
656 
657 	// draw slider
658 	UI_SetColor( color );
659 	UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y, 96, 16, sliderBar );
660 	UI_SetColor( NULL );
661 
662 	// clamp thumb
663 	if( s->maxvalue > s->minvalue )	{
664 		s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
665 		if( s->range < 0 ) {
666 			s->range = 0;
667 		}
668 		else if( s->range > 1) {
669 			s->range = 1;
670 		}
671 	}
672 	else {
673 		s->range = 0;
674 	}
675 
676 	// draw thumb
677 	if( style & UI_PULSE) {
678 		button = sliderButton_1;
679 	}
680 	else {
681 		button = sliderButton_0;
682 	}
683 
684 	UI_DrawHandlePic( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ) - 2, y - 2, 12, 20, button );
685 }
686 #else
687 /*
688 =================
689 Slider_Draw
690 =================
691 */
Slider_Draw(menuslider_s * s)692 static void Slider_Draw( menuslider_s *s )
693 {
694 	float *color;
695 	int	style;
696 	int	i;
697 	int x;
698 	int y;
699 	qboolean focus;
700 
701 	x =	s->generic.x;
702 	y = s->generic.y;
703 	focus = (s->generic.parent->cursor == s->generic.menuPosition);
704 
705 	style = UI_SMALLFONT;
706 	if ( s->generic.flags & QMF_GRAYED )
707 	{
708 		color = text_color_disabled;
709 	}
710 	else if (focus)
711 	{
712 		color  = text_color_highlight;
713 		style |= UI_PULSE;
714 	}
715 	else
716 	{
717 		color = text_color_normal;
718 	}
719 
720 	if ( focus )
721 	{
722 		// draw cursor
723 		UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
724 		UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
725 	}
726 
727 	// draw label
728 	UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color );
729 
730 	// draw slider
731 	UI_DrawChar( x + SMALLCHAR_WIDTH, y, 128, UI_LEFT|style, color);
732 	for ( i = 0; i < SLIDER_RANGE; i++ )
733 		UI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 129, UI_LEFT|style, color);
734 	UI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 130, UI_LEFT|style, color);
735 
736 	// clamp thumb
737 	if (s->maxvalue > s->minvalue)
738 	{
739 		s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
740 		if ( s->range < 0)
741 			s->range = 0;
742 		else if ( s->range > 1)
743 			s->range = 1;
744 	}
745 	else
746 		s->range = 0;
747 
748 	// draw thumb
749 	if (style & UI_PULSE) {
750 		style &= ~UI_PULSE;
751 		style |= UI_BLINK;
752 	}
753 	UI_DrawChar( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ), y, 131, UI_LEFT|style, color);
754 }
755 #endif
756 
757 /*
758 =================
759 SpinControl_Init
760 =================
761 */
SpinControl_Init(menulist_s * s)762 static void SpinControl_Init( menulist_s *s ) {
763 	int	len;
764 	int	l;
765 	const char* str;
766 
767 	if (s->generic.name)
768 		len = strlen(s->generic.name) * SMALLCHAR_WIDTH;
769 	else
770 		len = 0;
771 
772 	s->generic.left	= s->generic.x - SMALLCHAR_WIDTH - len;
773 
774 	len = s->numitems = 0;
775 	while ( (str = s->itemnames[s->numitems]) != 0 )
776 	{
777 		l = strlen(str);
778 		if (l > len)
779 			len = l;
780 
781 		s->numitems++;
782 	}
783 
784 	s->generic.top	  =	s->generic.y;
785 	s->generic.right  =	s->generic.x + (len+1)*SMALLCHAR_WIDTH;
786 	s->generic.bottom =	s->generic.y + SMALLCHAR_HEIGHT;
787 }
788 
789 /*
790 =================
791 SpinControl_Key
792 =================
793 */
SpinControl_Key(menulist_s * s,int key)794 static sfxHandle_t SpinControl_Key( menulist_s *s, int key )
795 {
796 	sfxHandle_t	sound;
797 
798 	sound = 0;
799 	switch (key)
800 	{
801 		case K_MOUSE1:
802 			s->curvalue++;
803 			if (s->curvalue >= s->numitems)
804 				s->curvalue = 0;
805 			sound = menu_move_sound;
806 			break;
807 
808 		case K_KP_LEFTARROW:
809 		case K_LEFTARROW:
810 			if (s->curvalue > 0)
811 			{
812 				s->curvalue--;
813 				sound = menu_move_sound;
814 			}
815 			else
816 				sound = menu_buzz_sound;
817 			break;
818 
819 		case K_KP_RIGHTARROW:
820 		case K_RIGHTARROW:
821 			if (s->curvalue < s->numitems-1)
822 			{
823 				s->curvalue++;
824 				sound = menu_move_sound;
825 			}
826 			else
827 				sound = menu_buzz_sound;
828 			break;
829 	}
830 
831 	if ( sound && s->generic.callback )
832 		s->generic.callback( s, QM_ACTIVATED );
833 
834 	return (sound);
835 }
836 
837 /*
838 =================
839 SpinControl_Draw
840 =================
841 */
SpinControl_Draw(menulist_s * s)842 static void SpinControl_Draw( menulist_s *s )
843 {
844 	float *color;
845 	int	x,y;
846 	int	style;
847 	qboolean focus;
848 
849 	x = s->generic.x;
850 	y =	s->generic.y;
851 
852 	style = UI_SMALLFONT;
853 	focus = (s->generic.parent->cursor == s->generic.menuPosition);
854 
855 	if ( s->generic.flags & QMF_GRAYED )
856 		color = text_color_disabled;
857 	else if ( focus )
858 	{
859 		color = text_color_highlight;
860 		style |= UI_PULSE;
861 	}
862 	else if ( s->generic.flags & QMF_BLINK )
863 	{
864 		color = text_color_highlight;
865 		style |= UI_BLINK;
866 	}
867 	else
868 		color = text_color_normal;
869 
870 	if ( focus )
871 	{
872 		// draw cursor
873 		UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
874 		UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
875 	}
876 
877 	UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
878 	UI_DrawString( x + SMALLCHAR_WIDTH, y, s->itemnames[s->curvalue], style|UI_LEFT, color );
879 }
880 
881 /*
882 =================
883 ScrollList_Init
884 =================
885 */
ScrollList_Init(menulist_s * l)886 static void ScrollList_Init( menulist_s *l )
887 {
888 	int		w;
889 
890 	l->oldvalue = 0;
891 	l->curvalue = 0;
892 	l->top      = 0;
893 
894 	if( !l->columns ) {
895 		l->columns = 1;
896 		l->seperation = 0;
897 	}
898 	else if( !l->seperation ) {
899 		l->seperation = 3;
900 	}
901 
902 	w = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH;
903 
904 	l->generic.left   =	l->generic.x;
905 	l->generic.top    = l->generic.y;
906 	l->generic.right  =	l->generic.x + w;
907 	l->generic.bottom =	l->generic.y + l->height * SMALLCHAR_HEIGHT;
908 
909 	if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
910 		l->generic.left -= w / 2;
911 		l->generic.right -= w / 2;
912 	}
913 }
914 
915 /*
916 =================
917 ScrollList_Key
918 =================
919 */
ScrollList_Key(menulist_s * l,int key)920 sfxHandle_t ScrollList_Key( menulist_s *l, int key )
921 {
922 	int	x;
923 	int	y;
924 	int	w;
925 	int	i;
926 	int	j;
927 	int	c;
928 	int	cursorx;
929 	int	cursory;
930 	int	column;
931 	int	index;
932 
933 	switch (key)
934 	{
935 		case K_MOUSE1:
936 			if (l->generic.flags & QMF_HASMOUSEFOCUS)
937 			{
938 				// check scroll region
939 				x = l->generic.x;
940 				y = l->generic.y;
941 				w = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH;
942 				if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
943 					x -= w / 2;
944 				}
945 				if (UI_CursorInRect( x, y, w, l->height*SMALLCHAR_HEIGHT ))
946 				{
947 					cursorx = (uis.cursorx - x)/SMALLCHAR_WIDTH;
948 					column = cursorx / (l->width + l->seperation);
949 					cursory = (uis.cursory - y)/SMALLCHAR_HEIGHT;
950 					index = column * l->height + cursory;
951 					if (l->top + index < l->numitems)
952 					{
953 						l->oldvalue = l->curvalue;
954 						l->curvalue = l->top + index;
955 
956 						if (l->oldvalue != l->curvalue && l->generic.callback)
957 						{
958 							l->generic.callback( l, QM_GOTFOCUS );
959 							return (menu_move_sound);
960 						}
961 					}
962 				}
963 
964 				// absorbed, silent sound effect
965 				return (menu_null_sound);
966 			}
967 			break;
968 
969 		case K_KP_HOME:
970 		case K_HOME:
971 			l->oldvalue = l->curvalue;
972 			l->curvalue = 0;
973 			l->top      = 0;
974 
975 			if (l->oldvalue != l->curvalue && l->generic.callback)
976 			{
977 				l->generic.callback( l, QM_GOTFOCUS );
978 				return (menu_move_sound);
979 			}
980 			return (menu_buzz_sound);
981 
982 		case K_KP_END:
983 		case K_END:
984 			l->oldvalue = l->curvalue;
985 			l->curvalue = l->numitems-1;
986 			if( l->columns > 1 ) {
987 				c = (l->curvalue / l->height + 1) * l->height;
988 				l->top = c - (l->columns * l->height);
989 			}
990 			else {
991 				l->top = l->curvalue - (l->height - 1);
992 			}
993 			if (l->top < 0)
994 				l->top = 0;
995 
996 			if (l->oldvalue != l->curvalue && l->generic.callback)
997 			{
998 				l->generic.callback( l, QM_GOTFOCUS );
999 				return (menu_move_sound);
1000 			}
1001 			return (menu_buzz_sound);
1002 
1003 		case K_PGUP:
1004 		case K_KP_PGUP:
1005 			if( l->columns > 1 ) {
1006 				return menu_null_sound;
1007 			}
1008 
1009 			if (l->curvalue > 0)
1010 			{
1011 				l->oldvalue = l->curvalue;
1012 				l->curvalue -= l->height-1;
1013 				if (l->curvalue < 0)
1014 					l->curvalue = 0;
1015 				l->top = l->curvalue;
1016 				if (l->top < 0)
1017 					l->top = 0;
1018 
1019 				if (l->generic.callback)
1020 					l->generic.callback( l, QM_GOTFOCUS );
1021 
1022 				return (menu_move_sound);
1023 			}
1024 			return (menu_buzz_sound);
1025 
1026 		case K_PGDN:
1027 		case K_KP_PGDN:
1028 			if( l->columns > 1 ) {
1029 				return menu_null_sound;
1030 			}
1031 
1032 			if (l->curvalue < l->numitems-1)
1033 			{
1034 				l->oldvalue = l->curvalue;
1035 				l->curvalue += l->height-1;
1036 				if (l->curvalue > l->numitems-1)
1037 					l->curvalue = l->numitems-1;
1038 				l->top = l->curvalue - (l->height-1);
1039 				if (l->top < 0)
1040 					l->top = 0;
1041 
1042 				if (l->generic.callback)
1043 					l->generic.callback( l, QM_GOTFOCUS );
1044 
1045 				return (menu_move_sound);
1046 			}
1047 			return (menu_buzz_sound);
1048 
1049 		case K_KP_UPARROW:
1050 		case K_UPARROW:
1051 			if( l->curvalue == 0 ) {
1052 				return menu_buzz_sound;
1053 			}
1054 
1055 			l->oldvalue = l->curvalue;
1056 			l->curvalue--;
1057 
1058 			if( l->curvalue < l->top ) {
1059 				if( l->columns == 1 ) {
1060 					l->top--;
1061 				}
1062 				else {
1063 					l->top -= l->height;
1064 				}
1065 			}
1066 
1067 			if( l->generic.callback ) {
1068 				l->generic.callback( l, QM_GOTFOCUS );
1069 			}
1070 
1071 			return (menu_move_sound);
1072 
1073 		case K_KP_DOWNARROW:
1074 		case K_DOWNARROW:
1075 			if( l->curvalue == l->numitems - 1 ) {
1076 				return menu_buzz_sound;
1077 			}
1078 
1079 			l->oldvalue = l->curvalue;
1080 			l->curvalue++;
1081 
1082 			if( l->curvalue >= l->top + l->columns * l->height ) {
1083 				if( l->columns == 1 ) {
1084 					l->top++;
1085 				}
1086 				else {
1087 					l->top += l->height;
1088 				}
1089 			}
1090 
1091 			if( l->generic.callback ) {
1092 				l->generic.callback( l, QM_GOTFOCUS );
1093 			}
1094 
1095 			return menu_move_sound;
1096 
1097 		case K_KP_LEFTARROW:
1098 		case K_LEFTARROW:
1099 			if( l->columns == 1 ) {
1100 				return menu_null_sound;
1101 			}
1102 
1103 			if( l->curvalue < l->height ) {
1104 				return menu_buzz_sound;
1105 			}
1106 
1107 			l->oldvalue = l->curvalue;
1108 			l->curvalue -= l->height;
1109 
1110 			if( l->curvalue < l->top ) {
1111 				l->top -= l->height;
1112 			}
1113 
1114 			if( l->generic.callback ) {
1115 				l->generic.callback( l, QM_GOTFOCUS );
1116 			}
1117 
1118 			return menu_move_sound;
1119 
1120 		case K_KP_RIGHTARROW:
1121 		case K_RIGHTARROW:
1122 			if( l->columns == 1 ) {
1123 				return menu_null_sound;
1124 			}
1125 
1126 			c = l->curvalue + l->height;
1127 
1128 			if( c >= l->numitems ) {
1129 				return menu_buzz_sound;
1130 			}
1131 
1132 			l->oldvalue = l->curvalue;
1133 			l->curvalue = c;
1134 
1135 			if( l->curvalue > l->top + l->columns * l->height - 1 ) {
1136 				l->top += l->height;
1137 			}
1138 
1139 			if( l->generic.callback ) {
1140 				l->generic.callback( l, QM_GOTFOCUS );
1141 			}
1142 
1143 			return menu_move_sound;
1144 	}
1145 
1146 	// cycle look for ascii key inside list items
1147 	if ( !Q_isprint( key ) )
1148 		return (0);
1149 
1150 	// force to lower for case insensitive compare
1151 	if ( Q_isupper( key ) )
1152 	{
1153 		key -= 'A' - 'a';
1154 	}
1155 
1156 	// iterate list items
1157 	for (i=1; i<=l->numitems; i++)
1158 	{
1159 		j = (l->curvalue + i) % l->numitems;
1160 		c = l->itemnames[j][0];
1161 		if ( Q_isupper( c ) )
1162 		{
1163 			c -= 'A' - 'a';
1164 		}
1165 
1166 		if (c == key)
1167 		{
1168 			// set current item, mimic windows listbox scroll behavior
1169 			if (j < l->top)
1170 			{
1171 				// behind top most item, set this as new top
1172 				l->top = j;
1173 			}
1174 			else if (j > l->top+l->height-1)
1175 			{
1176 				// past end of list box, do page down
1177 				l->top = (j+1) - l->height;
1178 			}
1179 
1180 			if (l->curvalue != j)
1181 			{
1182 				l->oldvalue = l->curvalue;
1183 				l->curvalue = j;
1184 				if (l->generic.callback)
1185 					l->generic.callback( l, QM_GOTFOCUS );
1186 				return ( menu_move_sound );
1187 			}
1188 
1189 			return (menu_buzz_sound);
1190 		}
1191 	}
1192 
1193 	return (menu_buzz_sound);
1194 }
1195 
1196 /*
1197 =================
1198 ScrollList_Draw
1199 =================
1200 */
ScrollList_Draw(menulist_s * l)1201 void ScrollList_Draw( menulist_s *l )
1202 {
1203 	int			x;
1204 	int			u;
1205 	int			y;
1206 	int			i;
1207 	int			base;
1208 	int			column;
1209 	float*		color;
1210 	qboolean	hasfocus;
1211 	int			style;
1212 
1213 	hasfocus = (l->generic.parent->cursor == l->generic.menuPosition);
1214 
1215 	x =	l->generic.x;
1216 	for( column = 0; column < l->columns; column++ ) {
1217 		y =	l->generic.y;
1218 		base = l->top + column * l->height;
1219 		for( i = base; i < base + l->height; i++) {
1220 			if (i >= l->numitems)
1221 				break;
1222 
1223 			if (i == l->curvalue)
1224 			{
1225 				u = x - 2;
1226 				if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
1227 					u -= (l->width * SMALLCHAR_WIDTH) / 2 + 1;
1228 				}
1229 
1230 				UI_FillRect(u,y,l->width*SMALLCHAR_WIDTH,SMALLCHAR_HEIGHT+2,listbar_color);
1231 				color = text_color_highlight;
1232 
1233 				if (hasfocus)
1234 					style = UI_PULSE|UI_LEFT|UI_SMALLFONT;
1235 				else
1236 					style = UI_LEFT|UI_SMALLFONT;
1237 			}
1238 			else
1239 			{
1240 				color = text_color_normal;
1241 				style = UI_LEFT|UI_SMALLFONT;
1242 			}
1243 			if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
1244 				style |= UI_CENTER;
1245 			}
1246 
1247 			UI_DrawString(
1248 				x,
1249 				y,
1250 				l->itemnames[i],
1251 				style,
1252 				color);
1253 
1254 			y += SMALLCHAR_HEIGHT;
1255 		}
1256 		x += (l->width + l->seperation) * SMALLCHAR_WIDTH;
1257 	}
1258 }
1259 
1260 /*
1261 =================
1262 Menu_AddItem
1263 =================
1264 */
Menu_AddItem(menuframework_s * menu,void * item)1265 void Menu_AddItem( menuframework_s *menu, void *item )
1266 {
1267 	menucommon_s	*itemptr;
1268 
1269 	if (menu->nitems >= MAX_MENUITEMS)
1270 		trap_Error ("Menu_AddItem: excessive items");
1271 
1272 	menu->items[menu->nitems] = item;
1273 	((menucommon_s*)menu->items[menu->nitems])->parent        = menu;
1274 	((menucommon_s*)menu->items[menu->nitems])->menuPosition  = menu->nitems;
1275 	((menucommon_s*)menu->items[menu->nitems])->flags        &= ~QMF_HASMOUSEFOCUS;
1276 
1277 	// perform any item specific initializations
1278 	itemptr = (menucommon_s*)item;
1279 	if (!(itemptr->flags & QMF_NODEFAULTINIT))
1280 	{
1281 		switch (itemptr->type)
1282 		{
1283 			case MTYPE_ACTION:
1284 				Action_Init((menuaction_s*)item);
1285 				break;
1286 
1287 			case MTYPE_FIELD:
1288 				MenuField_Init((menufield_s*)item);
1289 				break;
1290 
1291 			case MTYPE_SPINCONTROL:
1292 				SpinControl_Init((menulist_s*)item);
1293 				break;
1294 
1295 			case MTYPE_RADIOBUTTON:
1296 				RadioButton_Init((menuradiobutton_s*)item);
1297 				break;
1298 
1299 			case MTYPE_SLIDER:
1300 				Slider_Init((menuslider_s*)item);
1301 				break;
1302 
1303 			case MTYPE_BITMAP:
1304 				Bitmap_Init((menubitmap_s*)item);
1305 				break;
1306 
1307 			case MTYPE_TEXT:
1308 				Text_Init((menutext_s*)item);
1309 				break;
1310 
1311 			case MTYPE_SCROLLLIST:
1312 				ScrollList_Init((menulist_s*)item);
1313 				break;
1314 
1315 			case MTYPE_PTEXT:
1316 				PText_Init((menutext_s*)item);
1317 				break;
1318 
1319 			case MTYPE_BTEXT:
1320 				BText_Init((menutext_s*)item);
1321 				break;
1322 
1323 			default:
1324 				trap_Error( va("Menu_Init: unknown type %d", itemptr->type) );
1325 		}
1326 	}
1327 
1328 	menu->nitems++;
1329 }
1330 
1331 /*
1332 =================
1333 Menu_CursorMoved
1334 =================
1335 */
Menu_CursorMoved(menuframework_s * m)1336 void Menu_CursorMoved( menuframework_s *m )
1337 {
1338 	void (*callback)( void *self, int notification );
1339 
1340 	if (m->cursor_prev == m->cursor)
1341 		return;
1342 
1343 	if (m->cursor_prev >= 0 && m->cursor_prev < m->nitems)
1344 	{
1345 		callback = ((menucommon_s*)(m->items[m->cursor_prev]))->callback;
1346 		if (callback)
1347 			callback(m->items[m->cursor_prev],QM_LOSTFOCUS);
1348 	}
1349 
1350 	if (m->cursor >= 0 && m->cursor < m->nitems)
1351 	{
1352 		callback = ((menucommon_s*)(m->items[m->cursor]))->callback;
1353 		if (callback)
1354 			callback(m->items[m->cursor],QM_GOTFOCUS);
1355 	}
1356 }
1357 
1358 /*
1359 =================
1360 Menu_SetCursor
1361 =================
1362 */
Menu_SetCursor(menuframework_s * m,int cursor)1363 void Menu_SetCursor( menuframework_s *m, int cursor )
1364 {
1365 	if (((menucommon_s*)(m->items[cursor]))->flags & (QMF_GRAYED|QMF_INACTIVE))
1366 	{
1367 		// cursor can't go there
1368 		return;
1369 	}
1370 
1371 	m->cursor_prev = m->cursor;
1372 	m->cursor      = cursor;
1373 
1374 	Menu_CursorMoved( m );
1375 }
1376 
1377 /*
1378 =================
1379 Menu_SetCursorToItem
1380 =================
1381 */
Menu_SetCursorToItem(menuframework_s * m,void * ptr)1382 void Menu_SetCursorToItem( menuframework_s *m, void* ptr )
1383 {
1384 	int	i;
1385 
1386 	for (i=0; i<m->nitems; i++)
1387 	{
1388 		if (m->items[i] == ptr)
1389 		{
1390 			Menu_SetCursor( m, i );
1391 			return;
1392 		}
1393 	}
1394 }
1395 
1396 /*
1397 ** Menu_AdjustCursor
1398 **
1399 ** This function takes the given menu, the direction, and attempts
1400 ** to adjust the menu's cursor so that it's at the next available
1401 ** slot.
1402 */
Menu_AdjustCursor(menuframework_s * m,int dir)1403 void Menu_AdjustCursor( menuframework_s *m, int dir ) {
1404 	menucommon_s	*item = NULL;
1405 	qboolean		wrapped = qfalse;
1406 
1407 wrap:
1408 	while ( m->cursor >= 0 && m->cursor < m->nitems ) {
1409 		item = ( menucommon_s * ) m->items[m->cursor];
1410 		if (( item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE) ) ) {
1411 			m->cursor += dir;
1412 		}
1413 		else {
1414 			break;
1415 		}
1416 	}
1417 
1418 	if ( dir == 1 ) {
1419 		if ( m->cursor >= m->nitems ) {
1420 			if ( m->wrapAround ) {
1421 				if ( wrapped ) {
1422 					m->cursor = m->cursor_prev;
1423 					return;
1424 				}
1425 				m->cursor = 0;
1426 				wrapped = qtrue;
1427 				goto wrap;
1428 			}
1429 			m->cursor = m->cursor_prev;
1430 		}
1431 	}
1432 	else {
1433 		if ( m->cursor < 0 ) {
1434 			if ( m->wrapAround ) {
1435 				if ( wrapped ) {
1436 					m->cursor = m->cursor_prev;
1437 					return;
1438 				}
1439 				m->cursor = m->nitems - 1;
1440 				wrapped = qtrue;
1441 				goto wrap;
1442 			}
1443 			m->cursor = m->cursor_prev;
1444 		}
1445 	}
1446 }
1447 
1448 /*
1449 =================
1450 Menu_Draw
1451 =================
1452 */
Menu_Draw(menuframework_s * menu)1453 void Menu_Draw( menuframework_s *menu )
1454 {
1455 	int				i;
1456 	menucommon_s	*itemptr;
1457 
1458 	// draw menu
1459 	for (i=0; i<menu->nitems; i++)
1460 	{
1461 		itemptr = (menucommon_s*)menu->items[i];
1462 
1463 		if (itemptr->flags & QMF_HIDDEN)
1464 			continue;
1465 
1466 		if (itemptr->ownerdraw)
1467 		{
1468 			// total subclassing, owner draws everything
1469 			itemptr->ownerdraw( itemptr );
1470 		}
1471 		else
1472 		{
1473 			switch (itemptr->type)
1474 			{
1475 				case MTYPE_RADIOBUTTON:
1476 					RadioButton_Draw( (menuradiobutton_s*)itemptr );
1477 					break;
1478 
1479 				case MTYPE_FIELD:
1480 					MenuField_Draw( (menufield_s*)itemptr );
1481 					break;
1482 
1483 				case MTYPE_SLIDER:
1484 					Slider_Draw( (menuslider_s*)itemptr );
1485 					break;
1486 
1487 				case MTYPE_SPINCONTROL:
1488 					SpinControl_Draw( (menulist_s*)itemptr );
1489 					break;
1490 
1491 				case MTYPE_ACTION:
1492 					Action_Draw( (menuaction_s*)itemptr );
1493 					break;
1494 
1495 				case MTYPE_BITMAP:
1496 					Bitmap_Draw( (menubitmap_s*)itemptr );
1497 					break;
1498 
1499 				case MTYPE_TEXT:
1500 					Text_Draw( (menutext_s*)itemptr );
1501 					break;
1502 
1503 				case MTYPE_SCROLLLIST:
1504 					ScrollList_Draw( (menulist_s*)itemptr );
1505 					break;
1506 
1507 				case MTYPE_PTEXT:
1508 					PText_Draw( (menutext_s*)itemptr );
1509 					break;
1510 
1511 				case MTYPE_BTEXT:
1512 					BText_Draw( (menutext_s*)itemptr );
1513 					break;
1514 
1515 				default:
1516 					trap_Error( va("Menu_Draw: unknown type %d", itemptr->type) );
1517 			}
1518 		}
1519 #ifndef NDEBUG
1520 		if( uis.debug ) {
1521 			int	x;
1522 			int	y;
1523 			int	w;
1524 			int	h;
1525 
1526 			if( !( itemptr->flags & QMF_INACTIVE ) ) {
1527 				x = itemptr->left;
1528 				y = itemptr->top;
1529 				w = itemptr->right - itemptr->left + 1;
1530 				h =	itemptr->bottom - itemptr->top + 1;
1531 
1532 				if (itemptr->flags & QMF_HASMOUSEFOCUS) {
1533 					UI_DrawRect(x, y, w, h, colorYellow );
1534 				}
1535 				else {
1536 					UI_DrawRect(x, y, w, h, colorWhite );
1537 				}
1538 			}
1539 		}
1540 #endif
1541 	}
1542 
1543 	itemptr = Menu_ItemAtCursor( menu );
1544 	if ( itemptr && itemptr->statusbar)
1545 		itemptr->statusbar( ( void * ) itemptr );
1546 }
1547 
1548 /*
1549 =================
1550 Menu_ItemAtCursor
1551 =================
1552 */
Menu_ItemAtCursor(menuframework_s * m)1553 void *Menu_ItemAtCursor( menuframework_s *m )
1554 {
1555 	if ( m->cursor < 0 || m->cursor >= m->nitems )
1556 		return NULL;
1557 
1558 	return m->items[m->cursor];
1559 }
1560 
1561 /*
1562 =================
1563 Menu_ActivateItem
1564 =================
1565 */
Menu_ActivateItem(menuframework_s * s,menucommon_s * item)1566 sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item ) {
1567 	if ( item->callback ) {
1568 		item->callback( item, QM_ACTIVATED );
1569 		if( !( item->flags & QMF_SILENT ) ) {
1570 			return menu_move_sound;
1571 		}
1572 	}
1573 
1574 	return 0;
1575 }
1576 
1577 /*
1578 =================
1579 Menu_DefaultKey
1580 =================
1581 */
Menu_DefaultKey(menuframework_s * m,int key)1582 sfxHandle_t Menu_DefaultKey( menuframework_s *m, int key )
1583 {
1584 	sfxHandle_t		sound = 0;
1585 	menucommon_s	*item;
1586 	int				cursor_prev;
1587 
1588 	// menu system keys
1589 	switch ( key )
1590 	{
1591 		case K_MOUSE2:
1592 		case K_ESCAPE:
1593 			UI_PopMenu();
1594 			return menu_out_sound;
1595 	}
1596 
1597 	if (!m || !m->nitems)
1598 		return 0;
1599 
1600 	// route key stimulus to widget
1601 	item = Menu_ItemAtCursor( m );
1602 	if (item && !(item->flags & (QMF_GRAYED|QMF_INACTIVE)))
1603 	{
1604 		switch (item->type)
1605 		{
1606 			case MTYPE_SPINCONTROL:
1607 				sound = SpinControl_Key( (menulist_s*)item, key );
1608 				break;
1609 
1610 			case MTYPE_RADIOBUTTON:
1611 				sound = RadioButton_Key( (menuradiobutton_s*)item, key );
1612 				break;
1613 
1614 			case MTYPE_SLIDER:
1615 				sound = Slider_Key( (menuslider_s*)item, key );
1616 				break;
1617 
1618 			case MTYPE_SCROLLLIST:
1619 				sound = ScrollList_Key( (menulist_s*)item, key );
1620 				break;
1621 
1622 			case MTYPE_FIELD:
1623 				sound = MenuField_Key( (menufield_s*)item, &key );
1624 				break;
1625 		}
1626 
1627 		if (sound) {
1628 			// key was handled
1629 			return sound;
1630 		}
1631 	}
1632 
1633 	// default handling
1634 	switch ( key )
1635 	{
1636 #ifndef NDEBUG
1637 		case K_F11:
1638 			uis.debug ^= 1;
1639 			break;
1640 
1641 		case K_F12:
1642 			trap_Cmd_ExecuteText(EXEC_APPEND, "screenshot\n");
1643 			break;
1644 #endif
1645 		case K_KP_UPARROW:
1646 		case K_UPARROW:
1647 			cursor_prev    = m->cursor;
1648 			m->cursor_prev = m->cursor;
1649 			m->cursor--;
1650 			Menu_AdjustCursor( m, -1 );
1651 			if ( cursor_prev != m->cursor ) {
1652 				Menu_CursorMoved( m );
1653 				sound = menu_move_sound;
1654 			}
1655 			break;
1656 
1657 		case K_TAB:
1658 		case K_KP_DOWNARROW:
1659 		case K_DOWNARROW:
1660 			cursor_prev    = m->cursor;
1661 			m->cursor_prev = m->cursor;
1662 			m->cursor++;
1663 			Menu_AdjustCursor( m, 1 );
1664 			if ( cursor_prev != m->cursor ) {
1665 				Menu_CursorMoved( m );
1666 				sound = menu_move_sound;
1667 			}
1668 			break;
1669 
1670 		case K_MOUSE1:
1671 		case K_MOUSE3:
1672 			if (item)
1673 				if ((item->flags & QMF_HASMOUSEFOCUS) && !(item->flags & (QMF_GRAYED|QMF_INACTIVE)))
1674 					return (Menu_ActivateItem( m, item ));
1675 			break;
1676 
1677 		case K_JOY1:
1678 		case K_JOY2:
1679 		case K_JOY3:
1680 		case K_JOY4:
1681 		case K_AUX1:
1682 		case K_AUX2:
1683 		case K_AUX3:
1684 		case K_AUX4:
1685 		case K_AUX5:
1686 		case K_AUX6:
1687 		case K_AUX7:
1688 		case K_AUX8:
1689 		case K_AUX9:
1690 		case K_AUX10:
1691 		case K_AUX11:
1692 		case K_AUX12:
1693 		case K_AUX13:
1694 		case K_AUX14:
1695 		case K_AUX15:
1696 		case K_AUX16:
1697 		case K_KP_ENTER:
1698 		case K_ENTER:
1699 			if (item)
1700 				if (!(item->flags & (QMF_MOUSEONLY|QMF_GRAYED|QMF_INACTIVE)))
1701 					return (Menu_ActivateItem( m, item ));
1702 			break;
1703 	}
1704 
1705 	return sound;
1706 }
1707 
1708 /*
1709 =================
1710 Menu_Cache
1711 =================
1712 */
Menu_Cache(void)1713 void Menu_Cache( void )
1714 {
1715 	uis.charset			= trap_R_RegisterShaderNoMip( "gfx/2d/bigchars" );
1716 	uis.charsetProp		= trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" );
1717 	uis.charsetPropGlow	= trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" );
1718 	uis.charsetPropB	= trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" );
1719 	uis.cursor          = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
1720 	uis.rb_on           = trap_R_RegisterShaderNoMip( "menu/art/switch_on" );
1721 	uis.rb_off          = trap_R_RegisterShaderNoMip( "menu/art/switch_off" );
1722 
1723 	uis.whiteShader = trap_R_RegisterShaderNoMip( "white" );
1724 	if ( uis.glconfig.hardwareType == GLHW_RAGEPRO ) {
1725 		// the blend effect turns to shit with the normal
1726 		uis.menuBackShader	= trap_R_RegisterShaderNoMip( "menubackRagePro" );
1727 	} else {
1728 		uis.menuBackShader	= trap_R_RegisterShaderNoMip( "menuback" );
1729 	}
1730 	uis.menuBackNoLogoShader = trap_R_RegisterShaderNoMip( "menubacknologo" );
1731 
1732 	menu_in_sound	= trap_S_RegisterSound( "sound/misc/menu1.wav", qfalse );
1733 	menu_move_sound	= trap_S_RegisterSound( "sound/misc/menu2.wav", qfalse );
1734 	menu_out_sound	= trap_S_RegisterSound( "sound/misc/menu3.wav", qfalse );
1735 	menu_buzz_sound	= trap_S_RegisterSound( "sound/misc/menu4.wav", qfalse );
1736 	weaponChangeSound	= trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );
1737 
1738 	// need a nonzero sound, make an empty sound for this
1739 	menu_null_sound = -1;
1740 
1741 	sliderBar = trap_R_RegisterShaderNoMip( "menu/art/slider2" );
1742 	sliderButton_0 = trap_R_RegisterShaderNoMip( "menu/art/sliderbutt_0" );
1743 	sliderButton_1 = trap_R_RegisterShaderNoMip( "menu/art/sliderbutt_1" );
1744 }
1745 
1746