aboutsummaryrefslogtreecommitdiffstats
path: root/code/q3_ui/ui_qmenu.c
diff options
context:
space:
mode:
Diffstat (limited to 'code/q3_ui/ui_qmenu.c')
-rwxr-xr-xcode/q3_ui/ui_qmenu.c3492
1 files changed, 1746 insertions, 1746 deletions
diff --git a/code/q3_ui/ui_qmenu.c b/code/q3_ui/ui_qmenu.c
index 400448a..a6ec29e 100755
--- a/code/q3_ui/ui_qmenu.c
+++ b/code/q3_ui/ui_qmenu.c
@@ -1,1746 +1,1746 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-//
-/**********************************************************************
- UI_QMENU.C
-
- Quake's menu framework system.
-**********************************************************************/
-#include "ui_local.h"
-
-sfxHandle_t menu_in_sound;
-sfxHandle_t menu_move_sound;
-sfxHandle_t menu_out_sound;
-sfxHandle_t menu_buzz_sound;
-sfxHandle_t menu_null_sound;
-sfxHandle_t weaponChangeSound;
-
-static qhandle_t sliderBar;
-static qhandle_t sliderButton_0;
-static qhandle_t sliderButton_1;
-
-vec4_t menu_text_color = {1.0f, 1.0f, 1.0f, 1.0f};
-vec4_t menu_dim_color = {0.0f, 0.0f, 0.0f, 0.75f};
-vec4_t color_black = {0.00f, 0.00f, 0.00f, 1.00f};
-vec4_t color_white = {1.00f, 1.00f, 1.00f, 1.00f};
-vec4_t color_yellow = {1.00f, 1.00f, 0.00f, 1.00f};
-vec4_t color_blue = {0.00f, 0.00f, 1.00f, 1.00f};
-vec4_t color_lightOrange = {1.00f, 0.68f, 0.00f, 1.00f };
-vec4_t color_orange = {1.00f, 0.43f, 0.00f, 1.00f};
-vec4_t color_red = {1.00f, 0.00f, 0.00f, 1.00f};
-vec4_t color_dim = {0.00f, 0.00f, 0.00f, 0.25f};
-
-// current color scheme
-vec4_t pulse_color = {1.00f, 1.00f, 1.00f, 1.00f};
-vec4_t text_color_disabled = {0.50f, 0.50f, 0.50f, 1.00f}; // light gray
-vec4_t text_color_normal = {1.00f, 0.43f, 0.00f, 1.00f}; // light orange
-vec4_t text_color_highlight = {1.00f, 1.00f, 0.00f, 1.00f}; // bright yellow
-vec4_t listbar_color = {1.00f, 0.43f, 0.00f, 0.30f}; // transluscent orange
-vec4_t text_color_status = {1.00f, 1.00f, 1.00f, 1.00f}; // bright white
-
-// action widget
-static void Action_Init( menuaction_s *a );
-static void Action_Draw( menuaction_s *a );
-
-// radio button widget
-static void RadioButton_Init( menuradiobutton_s *rb );
-static void RadioButton_Draw( menuradiobutton_s *rb );
-static sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key );
-
-// slider widget
-static void Slider_Init( menuslider_s *s );
-static sfxHandle_t Slider_Key( menuslider_s *s, int key );
-static void Slider_Draw( menuslider_s *s );
-
-// spin control widget
-static void SpinControl_Init( menulist_s *s );
-static void SpinControl_Draw( menulist_s *s );
-static sfxHandle_t SpinControl_Key( menulist_s *l, int key );
-
-// text widget
-static void Text_Init( menutext_s *b );
-static void Text_Draw( menutext_s *b );
-
-// scrolllist widget
-static void ScrollList_Init( menulist_s *l );
-sfxHandle_t ScrollList_Key( menulist_s *l, int key );
-
-// proportional text widget
-static void PText_Init( menutext_s *b );
-static void PText_Draw( menutext_s *b );
-
-// proportional banner text widget
-static void BText_Init( menutext_s *b );
-static void BText_Draw( menutext_s *b );
-
-/*
-=================
-Text_Init
-=================
-*/
-static void Text_Init( menutext_s *t )
-{
- t->generic.flags |= QMF_INACTIVE;
-}
-
-/*
-=================
-Text_Draw
-=================
-*/
-static void Text_Draw( menutext_s *t )
-{
- int x;
- int y;
- char buff[512];
- float* color;
-
- x = t->generic.x;
- y = t->generic.y;
-
- buff[0] = '\0';
-
- // possible label
- if (t->generic.name)
- strcpy(buff,t->generic.name);
-
- // possible value
- if (t->string)
- strcat(buff,t->string);
-
- if (t->generic.flags & QMF_GRAYED)
- color = text_color_disabled;
- else
- color = t->color;
-
- UI_DrawString( x, y, buff, t->style, color );
-}
-
-/*
-=================
-BText_Init
-=================
-*/
-static void BText_Init( menutext_s *t )
-{
- t->generic.flags |= QMF_INACTIVE;
-}
-
-/*
-=================
-BText_Draw
-=================
-*/
-static void BText_Draw( menutext_s *t )
-{
- int x;
- int y;
- float* color;
-
- x = t->generic.x;
- y = t->generic.y;
-
- if (t->generic.flags & QMF_GRAYED)
- color = text_color_disabled;
- else
- color = t->color;
-
- UI_DrawBannerString( x, y, t->string, t->style, color );
-}
-
-/*
-=================
-PText_Init
-=================
-*/
-static void PText_Init( menutext_s *t )
-{
- int x;
- int y;
- int w;
- int h;
- float sizeScale;
-
- sizeScale = UI_ProportionalSizeScale( t->style );
-
- x = t->generic.x;
- y = t->generic.y;
- w = UI_ProportionalStringWidth( t->string ) * sizeScale;
- h = PROP_HEIGHT * sizeScale;
-
- if( t->generic.flags & QMF_RIGHT_JUSTIFY ) {
- x -= w;
- }
- else if( t->generic.flags & QMF_CENTER_JUSTIFY ) {
- x -= w / 2;
- }
-
- t->generic.left = x - PROP_GAP_WIDTH * sizeScale;
- t->generic.right = x + w + PROP_GAP_WIDTH * sizeScale;
- t->generic.top = y;
- t->generic.bottom = y + h;
-}
-
-/*
-=================
-PText_Draw
-=================
-*/
-static void PText_Draw( menutext_s *t )
-{
- int x;
- int y;
- float * color;
- int style;
-
- x = t->generic.x;
- y = t->generic.y;
-
- if (t->generic.flags & QMF_GRAYED)
- color = text_color_disabled;
- else
- color = t->color;
-
- style = t->style;
- if( t->generic.flags & QMF_PULSEIFFOCUS ) {
- if( Menu_ItemAtCursor( t->generic.parent ) == t ) {
- style |= UI_PULSE;
- }
- else {
- style |= UI_INVERSE;
- }
- }
-
- UI_DrawProportionalString( x, y, t->string, style, color );
-}
-
-/*
-=================
-Bitmap_Init
-=================
-*/
-void Bitmap_Init( menubitmap_s *b )
-{
- int x;
- int y;
- int w;
- int h;
-
- x = b->generic.x;
- y = b->generic.y;
- w = b->width;
- h = b->height;
- if( w < 0 ) {
- w = -w;
- }
- if( h < 0 ) {
- h = -h;
- }
-
- if (b->generic.flags & QMF_RIGHT_JUSTIFY)
- {
- x = x - w;
- }
- else if (b->generic.flags & QMF_CENTER_JUSTIFY)
- {
- x = x - w/2;
- }
-
- b->generic.left = x;
- b->generic.right = x + w;
- b->generic.top = y;
- b->generic.bottom = y + h;
-
- b->shader = 0;
- b->focusshader = 0;
-}
-
-/*
-=================
-Bitmap_Draw
-=================
-*/
-void Bitmap_Draw( menubitmap_s *b )
-{
- float x;
- float y;
- float w;
- float h;
- vec4_t tempcolor;
- float* color;
-
- x = b->generic.x;
- y = b->generic.y;
- w = b->width;
- h = b->height;
-
- if (b->generic.flags & QMF_RIGHT_JUSTIFY)
- {
- x = x - w;
- }
- else if (b->generic.flags & QMF_CENTER_JUSTIFY)
- {
- x = x - w/2;
- }
-
- // used to refresh shader
- if (b->generic.name && !b->shader)
- {
- b->shader = trap_R_RegisterShaderNoMip( b->generic.name );
- if (!b->shader && b->errorpic)
- b->shader = trap_R_RegisterShaderNoMip( b->errorpic );
- }
-
- if (b->focuspic && !b->focusshader)
- b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );
-
- if (b->generic.flags & QMF_GRAYED)
- {
- if (b->shader)
- {
- trap_R_SetColor( colorMdGrey );
- UI_DrawHandlePic( x, y, w, h, b->shader );
- trap_R_SetColor( NULL );
- }
- }
- else
- {
- if (b->shader)
- UI_DrawHandlePic( x, y, w, h, b->shader );
-
- // bk001204 - parentheses
- if ( ( (b->generic.flags & QMF_PULSE)
- || (b->generic.flags & QMF_PULSEIFFOCUS) )
- && (Menu_ItemAtCursor( b->generic.parent ) == b))
- {
- if (b->focuscolor)
- {
- tempcolor[0] = b->focuscolor[0];
- tempcolor[1] = b->focuscolor[1];
- tempcolor[2] = b->focuscolor[2];
- color = tempcolor;
- }
- else
- color = pulse_color;
- color[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR);
-
- trap_R_SetColor( color );
- UI_DrawHandlePic( x, y, w, h, b->focusshader );
- trap_R_SetColor( NULL );
- }
- else if ((b->generic.flags & QMF_HIGHLIGHT) || ((b->generic.flags & QMF_HIGHLIGHT_IF_FOCUS) && (Menu_ItemAtCursor( b->generic.parent ) == b)))
- {
- if (b->focuscolor)
- {
- trap_R_SetColor( b->focuscolor );
- UI_DrawHandlePic( x, y, w, h, b->focusshader );
- trap_R_SetColor( NULL );
- }
- else
- UI_DrawHandlePic( x, y, w, h, b->focusshader );
- }
- }
-}
-
-/*
-=================
-Action_Init
-=================
-*/
-static void Action_Init( menuaction_s *a )
-{
- int len;
-
- // calculate bounds
- if (a->generic.name)
- len = strlen(a->generic.name);
- else
- len = 0;
-
- // left justify text
- a->generic.left = a->generic.x;
- a->generic.right = a->generic.x + len*BIGCHAR_WIDTH;
- a->generic.top = a->generic.y;
- a->generic.bottom = a->generic.y + BIGCHAR_HEIGHT;
-}
-
-/*
-=================
-Action_Draw
-=================
-*/
-static void Action_Draw( menuaction_s *a )
-{
- int x, y;
- int style;
- float* color;
-
- style = 0;
- color = menu_text_color;
- if ( a->generic.flags & QMF_GRAYED )
- {
- color = text_color_disabled;
- }
- else if (( a->generic.flags & QMF_PULSEIFFOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition ))
- {
- color = text_color_highlight;
- style = UI_PULSE;
- }
- else if (( a->generic.flags & QMF_HIGHLIGHT_IF_FOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition ))
- {
- color = text_color_highlight;
- }
- else if ( a->generic.flags & QMF_BLINK )
- {
- style = UI_BLINK;
- color = text_color_highlight;
- }
-
- x = a->generic.x;
- y = a->generic.y;
-
- UI_DrawString( x, y, a->generic.name, UI_LEFT|style, color );
-
- if ( a->generic.parent->cursor == a->generic.menuPosition )
- {
- // draw cursor
- UI_DrawChar( x - BIGCHAR_WIDTH, y, 13, UI_LEFT|UI_BLINK, color);
- }
-}
-
-/*
-=================
-RadioButton_Init
-=================
-*/
-static void RadioButton_Init( menuradiobutton_s *rb )
-{
- int len;
-
- // calculate bounds
- if (rb->generic.name)
- len = strlen(rb->generic.name);
- else
- len = 0;
-
- rb->generic.left = rb->generic.x - (len+1)*SMALLCHAR_WIDTH;
- rb->generic.right = rb->generic.x + 6*SMALLCHAR_WIDTH;
- rb->generic.top = rb->generic.y;
- rb->generic.bottom = rb->generic.y + SMALLCHAR_HEIGHT;
-}
-
-/*
-=================
-RadioButton_Key
-=================
-*/
-static sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key )
-{
- switch (key)
- {
- case K_MOUSE1:
- if (!(rb->generic.flags & QMF_HASMOUSEFOCUS))
- break;
-
- case K_JOY1:
- case K_JOY2:
- case K_JOY3:
- case K_JOY4:
- case K_ENTER:
- case K_KP_ENTER:
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- rb->curvalue = !rb->curvalue;
- if ( rb->generic.callback )
- rb->generic.callback( rb, QM_ACTIVATED );
-
- return (menu_move_sound);
- }
-
- // key not handled
- return 0;
-}
-
-/*
-=================
-RadioButton_Draw
-=================
-*/
-static void RadioButton_Draw( menuradiobutton_s *rb )
-{
- int x;
- int y;
- float *color;
- int style;
- qboolean focus;
-
- x = rb->generic.x;
- y = rb->generic.y;
-
- focus = (rb->generic.parent->cursor == rb->generic.menuPosition);
-
- if ( rb->generic.flags & QMF_GRAYED )
- {
- color = text_color_disabled;
- style = UI_LEFT|UI_SMALLFONT;
- }
- else if ( focus )
- {
- color = text_color_highlight;
- style = UI_LEFT|UI_PULSE|UI_SMALLFONT;
- }
- else
- {
- color = text_color_normal;
- style = UI_LEFT|UI_SMALLFONT;
- }
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( rb->generic.left, rb->generic.top, rb->generic.right-rb->generic.left+1, rb->generic.bottom-rb->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- if ( rb->generic.name )
- UI_DrawString( x - SMALLCHAR_WIDTH, y, rb->generic.name, UI_RIGHT|UI_SMALLFONT, color );
-
- if ( !rb->curvalue )
- {
- UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_off);
- UI_DrawString( x + SMALLCHAR_WIDTH + 16, y, "off", style, color );
- }
- else
- {
- UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_on );
- UI_DrawString( x + SMALLCHAR_WIDTH + 16, y, "on", style, color );
- }
-}
-
-/*
-=================
-Slider_Init
-=================
-*/
-static void Slider_Init( menuslider_s *s )
-{
- int len;
-
- // calculate bounds
- if (s->generic.name)
- len = strlen(s->generic.name);
- else
- len = 0;
-
- s->generic.left = s->generic.x - (len+1)*SMALLCHAR_WIDTH;
- s->generic.right = s->generic.x + (SLIDER_RANGE+2+1)*SMALLCHAR_WIDTH;
- s->generic.top = s->generic.y;
- s->generic.bottom = s->generic.y + SMALLCHAR_HEIGHT;
-}
-
-/*
-=================
-Slider_Key
-=================
-*/
-static sfxHandle_t Slider_Key( menuslider_s *s, int key )
-{
- sfxHandle_t sound;
- int x;
- int oldvalue;
-
- switch (key)
- {
- case K_MOUSE1:
- x = uis.cursorx - s->generic.x - 2*SMALLCHAR_WIDTH;
- oldvalue = s->curvalue;
- s->curvalue = (x/(float)(SLIDER_RANGE*SMALLCHAR_WIDTH)) * (s->maxvalue-s->minvalue) + s->minvalue;
-
- if (s->curvalue < s->minvalue)
- s->curvalue = s->minvalue;
- else if (s->curvalue > s->maxvalue)
- s->curvalue = s->maxvalue;
- if (s->curvalue != oldvalue)
- sound = menu_move_sound;
- else
- sound = 0;
- break;
-
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- if (s->curvalue > s->minvalue)
- {
- s->curvalue--;
- sound = menu_move_sound;
- }
- else
- sound = menu_buzz_sound;
- break;
-
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- if (s->curvalue < s->maxvalue)
- {
- s->curvalue++;
- sound = menu_move_sound;
- }
- else
- sound = menu_buzz_sound;
- break;
-
- default:
- // key not handled
- sound = 0;
- break;
- }
-
- if ( sound && s->generic.callback )
- s->generic.callback( s, QM_ACTIVATED );
-
- return (sound);
-}
-
-#if 1
-/*
-=================
-Slider_Draw
-=================
-*/
-static void Slider_Draw( menuslider_s *s ) {
- int x;
- int y;
- int style;
- float *color;
- int button;
- qboolean focus;
-
- x = s->generic.x;
- y = s->generic.y;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- if( s->generic.flags & QMF_GRAYED ) {
- color = text_color_disabled;
- style = UI_SMALLFONT;
- }
- else if( focus ) {
- color = text_color_highlight;
- style = UI_SMALLFONT | UI_PULSE;
- }
- else {
- color = text_color_normal;
- style = UI_SMALLFONT;
- }
-
- // draw label
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color );
-
- // draw slider
- UI_SetColor( color );
- UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y, 96, 16, sliderBar );
- UI_SetColor( NULL );
-
- // clamp thumb
- if( s->maxvalue > s->minvalue ) {
- s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
- if( s->range < 0 ) {
- s->range = 0;
- }
- else if( s->range > 1) {
- s->range = 1;
- }
- }
- else {
- s->range = 0;
- }
-
- // draw thumb
- if( style & UI_PULSE) {
- button = sliderButton_1;
- }
- else {
- button = sliderButton_0;
- }
-
- UI_DrawHandlePic( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ) - 2, y - 2, 12, 20, button );
-}
-#else
-/*
-=================
-Slider_Draw
-=================
-*/
-static void Slider_Draw( menuslider_s *s )
-{
- float *color;
- int style;
- int i;
- int x;
- int y;
- qboolean focus;
-
- x = s->generic.x;
- y = s->generic.y;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- style = UI_SMALLFONT;
- if ( s->generic.flags & QMF_GRAYED )
- {
- color = text_color_disabled;
- }
- else if (focus)
- {
- color = text_color_highlight;
- style |= UI_PULSE;
- }
- else
- {
- color = text_color_normal;
- }
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- // draw label
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color );
-
- // draw slider
- UI_DrawChar( x + SMALLCHAR_WIDTH, y, 128, UI_LEFT|style, color);
- for ( i = 0; i < SLIDER_RANGE; i++ )
- UI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 129, UI_LEFT|style, color);
- UI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 130, UI_LEFT|style, color);
-
- // clamp thumb
- if (s->maxvalue > s->minvalue)
- {
- s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
- if ( s->range < 0)
- s->range = 0;
- else if ( s->range > 1)
- s->range = 1;
- }
- else
- s->range = 0;
-
- // draw thumb
- if (style & UI_PULSE) {
- style &= ~UI_PULSE;
- style |= UI_BLINK;
- }
- UI_DrawChar( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ), y, 131, UI_LEFT|style, color);
-}
-#endif
-
-/*
-=================
-SpinControl_Init
-=================
-*/
-static void SpinControl_Init( menulist_s *s ) {
- int len;
- int l;
- const char* str;
-
- if (s->generic.name)
- len = strlen(s->generic.name) * SMALLCHAR_WIDTH;
- else
- len = 0;
-
- s->generic.left = s->generic.x - SMALLCHAR_WIDTH - len;
-
- len = s->numitems = 0;
- while ( (str = s->itemnames[s->numitems]) != 0 )
- {
- l = strlen(str);
- if (l > len)
- len = l;
-
- s->numitems++;
- }
-
- s->generic.top = s->generic.y;
- s->generic.right = s->generic.x + (len+1)*SMALLCHAR_WIDTH;
- s->generic.bottom = s->generic.y + SMALLCHAR_HEIGHT;
-}
-
-/*
-=================
-SpinControl_Key
-=================
-*/
-static sfxHandle_t SpinControl_Key( menulist_s *s, int key )
-{
- sfxHandle_t sound;
-
- sound = 0;
- switch (key)
- {
- case K_MOUSE1:
- s->curvalue++;
- if (s->curvalue >= s->numitems)
- s->curvalue = 0;
- sound = menu_move_sound;
- break;
-
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- if (s->curvalue > 0)
- {
- s->curvalue--;
- sound = menu_move_sound;
- }
- else
- sound = menu_buzz_sound;
- break;
-
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- if (s->curvalue < s->numitems-1)
- {
- s->curvalue++;
- sound = menu_move_sound;
- }
- else
- sound = menu_buzz_sound;
- break;
- }
-
- if ( sound && s->generic.callback )
- s->generic.callback( s, QM_ACTIVATED );
-
- return (sound);
-}
-
-/*
-=================
-SpinControl_Draw
-=================
-*/
-static void SpinControl_Draw( menulist_s *s )
-{
- float *color;
- int x,y;
- int style;
- qboolean focus;
-
- x = s->generic.x;
- y = s->generic.y;
-
- style = UI_SMALLFONT;
- focus = (s->generic.parent->cursor == s->generic.menuPosition);
-
- if ( s->generic.flags & QMF_GRAYED )
- color = text_color_disabled;
- else if ( focus )
- {
- color = text_color_highlight;
- style |= UI_PULSE;
- }
- else if ( s->generic.flags & QMF_BLINK )
- {
- color = text_color_highlight;
- style |= UI_BLINK;
- }
- else
- color = text_color_normal;
-
- if ( focus )
- {
- // draw cursor
- UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
- UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
- }
-
- UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
- UI_DrawString( x + SMALLCHAR_WIDTH, y, s->itemnames[s->curvalue], style|UI_LEFT, color );
-}
-
-/*
-=================
-ScrollList_Init
-=================
-*/
-static void ScrollList_Init( menulist_s *l )
-{
- int w;
-
- l->oldvalue = 0;
- l->curvalue = 0;
- l->top = 0;
-
- if( !l->columns ) {
- l->columns = 1;
- l->seperation = 0;
- }
- else if( !l->seperation ) {
- l->seperation = 3;
- }
-
- w = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH;
-
- l->generic.left = l->generic.x;
- l->generic.top = l->generic.y;
- l->generic.right = l->generic.x + w;
- l->generic.bottom = l->generic.y + l->height * SMALLCHAR_HEIGHT;
-
- if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
- l->generic.left -= w / 2;
- l->generic.right -= w / 2;
- }
-}
-
-/*
-=================
-ScrollList_Key
-=================
-*/
-sfxHandle_t ScrollList_Key( menulist_s *l, int key )
-{
- int x;
- int y;
- int w;
- int i;
- int j;
- int c;
- int cursorx;
- int cursory;
- int column;
- int index;
-
- switch (key)
- {
- case K_MOUSE1:
- if (l->generic.flags & QMF_HASMOUSEFOCUS)
- {
- // check scroll region
- x = l->generic.x;
- y = l->generic.y;
- w = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH;
- if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
- x -= w / 2;
- }
- if (UI_CursorInRect( x, y, w, l->height*SMALLCHAR_HEIGHT ))
- {
- cursorx = (uis.cursorx - x)/SMALLCHAR_WIDTH;
- column = cursorx / (l->width + l->seperation);
- cursory = (uis.cursory - y)/SMALLCHAR_HEIGHT;
- index = column * l->height + cursory;
- if (l->top + index < l->numitems)
- {
- l->oldvalue = l->curvalue;
- l->curvalue = l->top + index;
-
- if (l->oldvalue != l->curvalue && l->generic.callback)
- {
- l->generic.callback( l, QM_GOTFOCUS );
- return (menu_move_sound);
- }
- }
- }
-
- // absorbed, silent sound effect
- return (menu_null_sound);
- }
- break;
-
- case K_KP_HOME:
- case K_HOME:
- l->oldvalue = l->curvalue;
- l->curvalue = 0;
- l->top = 0;
-
- if (l->oldvalue != l->curvalue && l->generic.callback)
- {
- l->generic.callback( l, QM_GOTFOCUS );
- return (menu_move_sound);
- }
- return (menu_buzz_sound);
-
- case K_KP_END:
- case K_END:
- l->oldvalue = l->curvalue;
- l->curvalue = l->numitems-1;
- if( l->columns > 1 ) {
- c = (l->curvalue / l->height + 1) * l->height;
- l->top = c - (l->columns * l->height);
- }
- else {
- l->top = l->curvalue - (l->height - 1);
- }
- if (l->top < 0)
- l->top = 0;
-
- if (l->oldvalue != l->curvalue && l->generic.callback)
- {
- l->generic.callback( l, QM_GOTFOCUS );
- return (menu_move_sound);
- }
- return (menu_buzz_sound);
-
- case K_PGUP:
- case K_KP_PGUP:
- if( l->columns > 1 ) {
- return menu_null_sound;
- }
-
- if (l->curvalue > 0)
- {
- l->oldvalue = l->curvalue;
- l->curvalue -= l->height-1;
- if (l->curvalue < 0)
- l->curvalue = 0;
- l->top = l->curvalue;
- if (l->top < 0)
- l->top = 0;
-
- if (l->generic.callback)
- l->generic.callback( l, QM_GOTFOCUS );
-
- return (menu_move_sound);
- }
- return (menu_buzz_sound);
-
- case K_PGDN:
- case K_KP_PGDN:
- if( l->columns > 1 ) {
- return menu_null_sound;
- }
-
- if (l->curvalue < l->numitems-1)
- {
- l->oldvalue = l->curvalue;
- l->curvalue += l->height-1;
- if (l->curvalue > l->numitems-1)
- l->curvalue = l->numitems-1;
- l->top = l->curvalue - (l->height-1);
- if (l->top < 0)
- l->top = 0;
-
- if (l->generic.callback)
- l->generic.callback( l, QM_GOTFOCUS );
-
- return (menu_move_sound);
- }
- return (menu_buzz_sound);
-
- case K_KP_UPARROW:
- case K_UPARROW:
- if( l->curvalue == 0 ) {
- return menu_buzz_sound;
- }
-
- l->oldvalue = l->curvalue;
- l->curvalue--;
-
- if( l->curvalue < l->top ) {
- if( l->columns == 1 ) {
- l->top--;
- }
- else {
- l->top -= l->height;
- }
- }
-
- if( l->generic.callback ) {
- l->generic.callback( l, QM_GOTFOCUS );
- }
-
- return (menu_move_sound);
-
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- if( l->curvalue == l->numitems - 1 ) {
- return menu_buzz_sound;
- }
-
- l->oldvalue = l->curvalue;
- l->curvalue++;
-
- if( l->curvalue >= l->top + l->columns * l->height ) {
- if( l->columns == 1 ) {
- l->top++;
- }
- else {
- l->top += l->height;
- }
- }
-
- if( l->generic.callback ) {
- l->generic.callback( l, QM_GOTFOCUS );
- }
-
- return menu_move_sound;
-
- case K_KP_LEFTARROW:
- case K_LEFTARROW:
- if( l->columns == 1 ) {
- return menu_null_sound;
- }
-
- if( l->curvalue < l->height ) {
- return menu_buzz_sound;
- }
-
- l->oldvalue = l->curvalue;
- l->curvalue -= l->height;
-
- if( l->curvalue < l->top ) {
- l->top -= l->height;
- }
-
- if( l->generic.callback ) {
- l->generic.callback( l, QM_GOTFOCUS );
- }
-
- return menu_move_sound;
-
- case K_KP_RIGHTARROW:
- case K_RIGHTARROW:
- if( l->columns == 1 ) {
- return menu_null_sound;
- }
-
- c = l->curvalue + l->height;
-
- if( c >= l->numitems ) {
- return menu_buzz_sound;
- }
-
- l->oldvalue = l->curvalue;
- l->curvalue = c;
-
- if( l->curvalue > l->top + l->columns * l->height - 1 ) {
- l->top += l->height;
- }
-
- if( l->generic.callback ) {
- l->generic.callback( l, QM_GOTFOCUS );
- }
-
- return menu_move_sound;
- }
-
- // cycle look for ascii key inside list items
- if ( !Q_isprint( key ) )
- return (0);
-
- // force to lower for case insensitive compare
- if ( Q_isupper( key ) )
- {
- key -= 'A' - 'a';
- }
-
- // iterate list items
- for (i=1; i<=l->numitems; i++)
- {
- j = (l->curvalue + i) % l->numitems;
- c = l->itemnames[j][0];
- if ( Q_isupper( c ) )
- {
- c -= 'A' - 'a';
- }
-
- if (c == key)
- {
- // set current item, mimic windows listbox scroll behavior
- if (j < l->top)
- {
- // behind top most item, set this as new top
- l->top = j;
- }
- else if (j > l->top+l->height-1)
- {
- // past end of list box, do page down
- l->top = (j+1) - l->height;
- }
-
- if (l->curvalue != j)
- {
- l->oldvalue = l->curvalue;
- l->curvalue = j;
- if (l->generic.callback)
- l->generic.callback( l, QM_GOTFOCUS );
- return ( menu_move_sound );
- }
-
- return (menu_buzz_sound);
- }
- }
-
- return (menu_buzz_sound);
-}
-
-/*
-=================
-ScrollList_Draw
-=================
-*/
-void ScrollList_Draw( menulist_s *l )
-{
- int x;
- int u;
- int y;
- int i;
- int base;
- int column;
- float* color;
- qboolean hasfocus;
- int style;
-
- hasfocus = (l->generic.parent->cursor == l->generic.menuPosition);
-
- x = l->generic.x;
- for( column = 0; column < l->columns; column++ ) {
- y = l->generic.y;
- base = l->top + column * l->height;
- for( i = base; i < base + l->height; i++) {
- if (i >= l->numitems)
- break;
-
- if (i == l->curvalue)
- {
- u = x - 2;
- if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
- u -= (l->width * SMALLCHAR_WIDTH) / 2 + 1;
- }
-
- UI_FillRect(u,y,l->width*SMALLCHAR_WIDTH,SMALLCHAR_HEIGHT+2,listbar_color);
- color = text_color_highlight;
-
- if (hasfocus)
- style = UI_PULSE|UI_LEFT|UI_SMALLFONT;
- else
- style = UI_LEFT|UI_SMALLFONT;
- }
- else
- {
- color = text_color_normal;
- style = UI_LEFT|UI_SMALLFONT;
- }
- if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
- style |= UI_CENTER;
- }
-
- UI_DrawString(
- x,
- y,
- l->itemnames[i],
- style,
- color);
-
- y += SMALLCHAR_HEIGHT;
- }
- x += (l->width + l->seperation) * SMALLCHAR_WIDTH;
- }
-}
-
-/*
-=================
-Menu_AddItem
-=================
-*/
-void Menu_AddItem( menuframework_s *menu, void *item )
-{
- menucommon_s *itemptr;
-
- if (menu->nitems >= MAX_MENUITEMS)
- trap_Error ("Menu_AddItem: excessive items");
-
- menu->items[menu->nitems] = item;
- ((menucommon_s*)menu->items[menu->nitems])->parent = menu;
- ((menucommon_s*)menu->items[menu->nitems])->menuPosition = menu->nitems;
- ((menucommon_s*)menu->items[menu->nitems])->flags &= ~QMF_HASMOUSEFOCUS;
-
- // perform any item specific initializations
- itemptr = (menucommon_s*)item;
- if (!(itemptr->flags & QMF_NODEFAULTINIT))
- {
- switch (itemptr->type)
- {
- case MTYPE_ACTION:
- Action_Init((menuaction_s*)item);
- break;
-
- case MTYPE_FIELD:
- MenuField_Init((menufield_s*)item);
- break;
-
- case MTYPE_SPINCONTROL:
- SpinControl_Init((menulist_s*)item);
- break;
-
- case MTYPE_RADIOBUTTON:
- RadioButton_Init((menuradiobutton_s*)item);
- break;
-
- case MTYPE_SLIDER:
- Slider_Init((menuslider_s*)item);
- break;
-
- case MTYPE_BITMAP:
- Bitmap_Init((menubitmap_s*)item);
- break;
-
- case MTYPE_TEXT:
- Text_Init((menutext_s*)item);
- break;
-
- case MTYPE_SCROLLLIST:
- ScrollList_Init((menulist_s*)item);
- break;
-
- case MTYPE_PTEXT:
- PText_Init((menutext_s*)item);
- break;
-
- case MTYPE_BTEXT:
- BText_Init((menutext_s*)item);
- break;
-
- default:
- trap_Error( va("Menu_Init: unknown type %d", itemptr->type) );
- }
- }
-
- menu->nitems++;
-}
-
-/*
-=================
-Menu_CursorMoved
-=================
-*/
-void Menu_CursorMoved( menuframework_s *m )
-{
- void (*callback)( void *self, int notification );
-
- if (m->cursor_prev == m->cursor)
- return;
-
- if (m->cursor_prev >= 0 && m->cursor_prev < m->nitems)
- {
- callback = ((menucommon_s*)(m->items[m->cursor_prev]))->callback;
- if (callback)
- callback(m->items[m->cursor_prev],QM_LOSTFOCUS);
- }
-
- if (m->cursor >= 0 && m->cursor < m->nitems)
- {
- callback = ((menucommon_s*)(m->items[m->cursor]))->callback;
- if (callback)
- callback(m->items[m->cursor],QM_GOTFOCUS);
- }
-}
-
-/*
-=================
-Menu_SetCursor
-=================
-*/
-void Menu_SetCursor( menuframework_s *m, int cursor )
-{
- if (((menucommon_s*)(m->items[cursor]))->flags & (QMF_GRAYED|QMF_INACTIVE))
- {
- // cursor can't go there
- return;
- }
-
- m->cursor_prev = m->cursor;
- m->cursor = cursor;
-
- Menu_CursorMoved( m );
-}
-
-/*
-=================
-Menu_SetCursorToItem
-=================
-*/
-void Menu_SetCursorToItem( menuframework_s *m, void* ptr )
-{
- int i;
-
- for (i=0; i<m->nitems; i++)
- {
- if (m->items[i] == ptr)
- {
- Menu_SetCursor( m, i );
- return;
- }
- }
-}
-
-/*
-** Menu_AdjustCursor
-**
-** This function takes the given menu, the direction, and attempts
-** to adjust the menu's cursor so that it's at the next available
-** slot.
-*/
-void Menu_AdjustCursor( menuframework_s *m, int dir ) {
- menucommon_s *item = NULL;
- qboolean wrapped = qfalse;
-
-wrap:
- while ( m->cursor >= 0 && m->cursor < m->nitems ) {
- item = ( menucommon_s * ) m->items[m->cursor];
- if (( item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE) ) ) {
- m->cursor += dir;
- }
- else {
- break;
- }
- }
-
- if ( dir == 1 ) {
- if ( m->cursor >= m->nitems ) {
- if ( m->wrapAround ) {
- if ( wrapped ) {
- m->cursor = m->cursor_prev;
- return;
- }
- m->cursor = 0;
- wrapped = qtrue;
- goto wrap;
- }
- m->cursor = m->cursor_prev;
- }
- }
- else {
- if ( m->cursor < 0 ) {
- if ( m->wrapAround ) {
- if ( wrapped ) {
- m->cursor = m->cursor_prev;
- return;
- }
- m->cursor = m->nitems - 1;
- wrapped = qtrue;
- goto wrap;
- }
- m->cursor = m->cursor_prev;
- }
- }
-}
-
-/*
-=================
-Menu_Draw
-=================
-*/
-void Menu_Draw( menuframework_s *menu )
-{
- int i;
- menucommon_s *itemptr;
-
- // draw menu
- for (i=0; i<menu->nitems; i++)
- {
- itemptr = (menucommon_s*)menu->items[i];
-
- if (itemptr->flags & QMF_HIDDEN)
- continue;
-
- if (itemptr->ownerdraw)
- {
- // total subclassing, owner draws everything
- itemptr->ownerdraw( itemptr );
- }
- else
- {
- switch (itemptr->type)
- {
- case MTYPE_RADIOBUTTON:
- RadioButton_Draw( (menuradiobutton_s*)itemptr );
- break;
-
- case MTYPE_FIELD:
- MenuField_Draw( (menufield_s*)itemptr );
- break;
-
- case MTYPE_SLIDER:
- Slider_Draw( (menuslider_s*)itemptr );
- break;
-
- case MTYPE_SPINCONTROL:
- SpinControl_Draw( (menulist_s*)itemptr );
- break;
-
- case MTYPE_ACTION:
- Action_Draw( (menuaction_s*)itemptr );
- break;
-
- case MTYPE_BITMAP:
- Bitmap_Draw( (menubitmap_s*)itemptr );
- break;
-
- case MTYPE_TEXT:
- Text_Draw( (menutext_s*)itemptr );
- break;
-
- case MTYPE_SCROLLLIST:
- ScrollList_Draw( (menulist_s*)itemptr );
- break;
-
- case MTYPE_PTEXT:
- PText_Draw( (menutext_s*)itemptr );
- break;
-
- case MTYPE_BTEXT:
- BText_Draw( (menutext_s*)itemptr );
- break;
-
- default:
- trap_Error( va("Menu_Draw: unknown type %d", itemptr->type) );
- }
- }
-#ifndef NDEBUG
- if( uis.debug ) {
- int x;
- int y;
- int w;
- int h;
-
- if( !( itemptr->flags & QMF_INACTIVE ) ) {
- x = itemptr->left;
- y = itemptr->top;
- w = itemptr->right - itemptr->left + 1;
- h = itemptr->bottom - itemptr->top + 1;
-
- if (itemptr->flags & QMF_HASMOUSEFOCUS) {
- UI_DrawRect(x, y, w, h, colorYellow );
- }
- else {
- UI_DrawRect(x, y, w, h, colorWhite );
- }
- }
- }
-#endif
- }
-
- itemptr = Menu_ItemAtCursor( menu );
- if ( itemptr && itemptr->statusbar)
- itemptr->statusbar( ( void * ) itemptr );
-}
-
-/*
-=================
-Menu_ItemAtCursor
-=================
-*/
-void *Menu_ItemAtCursor( menuframework_s *m )
-{
- if ( m->cursor < 0 || m->cursor >= m->nitems )
- return 0;
-
- return m->items[m->cursor];
-}
-
-/*
-=================
-Menu_ActivateItem
-=================
-*/
-sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item ) {
- if ( item->callback ) {
- item->callback( item, QM_ACTIVATED );
- if( !( item->flags & QMF_SILENT ) ) {
- return menu_move_sound;
- }
- }
-
- return 0;
-}
-
-/*
-=================
-Menu_DefaultKey
-=================
-*/
-sfxHandle_t Menu_DefaultKey( menuframework_s *m, int key )
-{
- sfxHandle_t sound = 0;
- menucommon_s *item;
- int cursor_prev;
-
- // menu system keys
- switch ( key )
- {
- case K_MOUSE2:
- case K_ESCAPE:
- UI_PopMenu();
- return menu_out_sound;
- }
-
- if (!m || !m->nitems)
- return 0;
-
- // route key stimulus to widget
- item = Menu_ItemAtCursor( m );
- if (item && !(item->flags & (QMF_GRAYED|QMF_INACTIVE)))
- {
- switch (item->type)
- {
- case MTYPE_SPINCONTROL:
- sound = SpinControl_Key( (menulist_s*)item, key );
- break;
-
- case MTYPE_RADIOBUTTON:
- sound = RadioButton_Key( (menuradiobutton_s*)item, key );
- break;
-
- case MTYPE_SLIDER:
- sound = Slider_Key( (menuslider_s*)item, key );
- break;
-
- case MTYPE_SCROLLLIST:
- sound = ScrollList_Key( (menulist_s*)item, key );
- break;
-
- case MTYPE_FIELD:
- sound = MenuField_Key( (menufield_s*)item, &key );
- break;
- }
-
- if (sound) {
- // key was handled
- return sound;
- }
- }
-
- // default handling
- switch ( key )
- {
-#ifndef NDEBUG
- case K_F11:
- uis.debug ^= 1;
- break;
-
- case K_F12:
- trap_Cmd_ExecuteText(EXEC_APPEND, "screenshot\n");
- break;
-#endif
- case K_KP_UPARROW:
- case K_UPARROW:
- cursor_prev = m->cursor;
- m->cursor_prev = m->cursor;
- m->cursor--;
- Menu_AdjustCursor( m, -1 );
- if ( cursor_prev != m->cursor ) {
- Menu_CursorMoved( m );
- sound = menu_move_sound;
- }
- break;
-
- case K_TAB:
- case K_KP_DOWNARROW:
- case K_DOWNARROW:
- cursor_prev = m->cursor;
- m->cursor_prev = m->cursor;
- m->cursor++;
- Menu_AdjustCursor( m, 1 );
- if ( cursor_prev != m->cursor ) {
- Menu_CursorMoved( m );
- sound = menu_move_sound;
- }
- break;
-
- case K_MOUSE1:
- case K_MOUSE3:
- if (item)
- if ((item->flags & QMF_HASMOUSEFOCUS) && !(item->flags & (QMF_GRAYED|QMF_INACTIVE)))
- return (Menu_ActivateItem( m, item ));
- break;
-
- case K_JOY1:
- case K_JOY2:
- case K_JOY3:
- case K_JOY4:
- case K_AUX1:
- case K_AUX2:
- case K_AUX3:
- case K_AUX4:
- case K_AUX5:
- case K_AUX6:
- case K_AUX7:
- case K_AUX8:
- case K_AUX9:
- case K_AUX10:
- case K_AUX11:
- case K_AUX12:
- case K_AUX13:
- case K_AUX14:
- case K_AUX15:
- case K_AUX16:
- case K_KP_ENTER:
- case K_ENTER:
- if (item)
- if (!(item->flags & (QMF_MOUSEONLY|QMF_GRAYED|QMF_INACTIVE)))
- return (Menu_ActivateItem( m, item ));
- break;
- }
-
- return sound;
-}
-
-/*
-=================
-Menu_Cache
-=================
-*/
-void Menu_Cache( void )
-{
- uis.charset = trap_R_RegisterShaderNoMip( "gfx/2d/bigchars" );
- uis.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" );
- uis.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" );
- uis.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" );
- uis.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
- uis.rb_on = trap_R_RegisterShaderNoMip( "menu/art/switch_on" );
- uis.rb_off = trap_R_RegisterShaderNoMip( "menu/art/switch_off" );
-
- uis.whiteShader = trap_R_RegisterShaderNoMip( "white" );
- if ( uis.glconfig.hardwareType == GLHW_RAGEPRO ) {
- // the blend effect turns to shit with the normal
- uis.menuBackShader = trap_R_RegisterShaderNoMip( "menubackRagePro" );
- } else {
- uis.menuBackShader = trap_R_RegisterShaderNoMip( "menuback" );
- }
- uis.menuBackNoLogoShader = trap_R_RegisterShaderNoMip( "menubacknologo" );
-
- menu_in_sound = trap_S_RegisterSound( "sound/misc/menu1.wav", qfalse );
- menu_move_sound = trap_S_RegisterSound( "sound/misc/menu2.wav", qfalse );
- menu_out_sound = trap_S_RegisterSound( "sound/misc/menu3.wav", qfalse );
- menu_buzz_sound = trap_S_RegisterSound( "sound/misc/menu4.wav", qfalse );
- weaponChangeSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );
-
- // need a nonzero sound, make an empty sound for this
- menu_null_sound = -1;
-
- sliderBar = trap_R_RegisterShaderNoMip( "menu/art/slider2" );
- sliderButton_0 = trap_R_RegisterShaderNoMip( "menu/art/sliderbutt_0" );
- sliderButton_1 = trap_R_RegisterShaderNoMip( "menu/art/sliderbutt_1" );
-}
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+/**********************************************************************
+ UI_QMENU.C
+
+ Quake's menu framework system.
+**********************************************************************/
+#include "ui_local.h"
+
+sfxHandle_t menu_in_sound;
+sfxHandle_t menu_move_sound;
+sfxHandle_t menu_out_sound;
+sfxHandle_t menu_buzz_sound;
+sfxHandle_t menu_null_sound;
+sfxHandle_t weaponChangeSound;
+
+static qhandle_t sliderBar;
+static qhandle_t sliderButton_0;
+static qhandle_t sliderButton_1;
+
+vec4_t menu_text_color = {1.0f, 1.0f, 1.0f, 1.0f};
+vec4_t menu_dim_color = {0.0f, 0.0f, 0.0f, 0.75f};
+vec4_t color_black = {0.00f, 0.00f, 0.00f, 1.00f};
+vec4_t color_white = {1.00f, 1.00f, 1.00f, 1.00f};
+vec4_t color_yellow = {1.00f, 1.00f, 0.00f, 1.00f};
+vec4_t color_blue = {0.00f, 0.00f, 1.00f, 1.00f};
+vec4_t color_lightOrange = {1.00f, 0.68f, 0.00f, 1.00f };
+vec4_t color_orange = {1.00f, 0.43f, 0.00f, 1.00f};
+vec4_t color_red = {1.00f, 0.00f, 0.00f, 1.00f};
+vec4_t color_dim = {0.00f, 0.00f, 0.00f, 0.25f};
+
+// current color scheme
+vec4_t pulse_color = {1.00f, 1.00f, 1.00f, 1.00f};
+vec4_t text_color_disabled = {0.50f, 0.50f, 0.50f, 1.00f}; // light gray
+vec4_t text_color_normal = {1.00f, 0.43f, 0.00f, 1.00f}; // light orange
+vec4_t text_color_highlight = {1.00f, 1.00f, 0.00f, 1.00f}; // bright yellow
+vec4_t listbar_color = {1.00f, 0.43f, 0.00f, 0.30f}; // transluscent orange
+vec4_t text_color_status = {1.00f, 1.00f, 1.00f, 1.00f}; // bright white
+
+// action widget
+static void Action_Init( menuaction_s *a );
+static void Action_Draw( menuaction_s *a );
+
+// radio button widget
+static void RadioButton_Init( menuradiobutton_s *rb );
+static void RadioButton_Draw( menuradiobutton_s *rb );
+static sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key );
+
+// slider widget
+static void Slider_Init( menuslider_s *s );
+static sfxHandle_t Slider_Key( menuslider_s *s, int key );
+static void Slider_Draw( menuslider_s *s );
+
+// spin control widget
+static void SpinControl_Init( menulist_s *s );
+static void SpinControl_Draw( menulist_s *s );
+static sfxHandle_t SpinControl_Key( menulist_s *l, int key );
+
+// text widget
+static void Text_Init( menutext_s *b );
+static void Text_Draw( menutext_s *b );
+
+// scrolllist widget
+static void ScrollList_Init( menulist_s *l );
+sfxHandle_t ScrollList_Key( menulist_s *l, int key );
+
+// proportional text widget
+static void PText_Init( menutext_s *b );
+static void PText_Draw( menutext_s *b );
+
+// proportional banner text widget
+static void BText_Init( menutext_s *b );
+static void BText_Draw( menutext_s *b );
+
+/*
+=================
+Text_Init
+=================
+*/
+static void Text_Init( menutext_s *t )
+{
+ t->generic.flags |= QMF_INACTIVE;
+}
+
+/*
+=================
+Text_Draw
+=================
+*/
+static void Text_Draw( menutext_s *t )
+{
+ int x;
+ int y;
+ char buff[512];
+ float* color;
+
+ x = t->generic.x;
+ y = t->generic.y;
+
+ buff[0] = '\0';
+
+ // possible label
+ if (t->generic.name)
+ strcpy(buff,t->generic.name);
+
+ // possible value
+ if (t->string)
+ strcat(buff,t->string);
+
+ if (t->generic.flags & QMF_GRAYED)
+ color = text_color_disabled;
+ else
+ color = t->color;
+
+ UI_DrawString( x, y, buff, t->style, color );
+}
+
+/*
+=================
+BText_Init
+=================
+*/
+static void BText_Init( menutext_s *t )
+{
+ t->generic.flags |= QMF_INACTIVE;
+}
+
+/*
+=================
+BText_Draw
+=================
+*/
+static void BText_Draw( menutext_s *t )
+{
+ int x;
+ int y;
+ float* color;
+
+ x = t->generic.x;
+ y = t->generic.y;
+
+ if (t->generic.flags & QMF_GRAYED)
+ color = text_color_disabled;
+ else
+ color = t->color;
+
+ UI_DrawBannerString( x, y, t->string, t->style, color );
+}
+
+/*
+=================
+PText_Init
+=================
+*/
+static void PText_Init( menutext_s *t )
+{
+ int x;
+ int y;
+ int w;
+ int h;
+ float sizeScale;
+
+ sizeScale = UI_ProportionalSizeScale( t->style );
+
+ x = t->generic.x;
+ y = t->generic.y;
+ w = UI_ProportionalStringWidth( t->string ) * sizeScale;
+ h = PROP_HEIGHT * sizeScale;
+
+ if( t->generic.flags & QMF_RIGHT_JUSTIFY ) {
+ x -= w;
+ }
+ else if( t->generic.flags & QMF_CENTER_JUSTIFY ) {
+ x -= w / 2;
+ }
+
+ t->generic.left = x - PROP_GAP_WIDTH * sizeScale;
+ t->generic.right = x + w + PROP_GAP_WIDTH * sizeScale;
+ t->generic.top = y;
+ t->generic.bottom = y + h;
+}
+
+/*
+=================
+PText_Draw
+=================
+*/
+static void PText_Draw( menutext_s *t )
+{
+ int x;
+ int y;
+ float * color;
+ int style;
+
+ x = t->generic.x;
+ y = t->generic.y;
+
+ if (t->generic.flags & QMF_GRAYED)
+ color = text_color_disabled;
+ else
+ color = t->color;
+
+ style = t->style;
+ if( t->generic.flags & QMF_PULSEIFFOCUS ) {
+ if( Menu_ItemAtCursor( t->generic.parent ) == t ) {
+ style |= UI_PULSE;
+ }
+ else {
+ style |= UI_INVERSE;
+ }
+ }
+
+ UI_DrawProportionalString( x, y, t->string, style, color );
+}
+
+/*
+=================
+Bitmap_Init
+=================
+*/
+void Bitmap_Init( menubitmap_s *b )
+{
+ int x;
+ int y;
+ int w;
+ int h;
+
+ x = b->generic.x;
+ y = b->generic.y;
+ w = b->width;
+ h = b->height;
+ if( w < 0 ) {
+ w = -w;
+ }
+ if( h < 0 ) {
+ h = -h;
+ }
+
+ if (b->generic.flags & QMF_RIGHT_JUSTIFY)
+ {
+ x = x - w;
+ }
+ else if (b->generic.flags & QMF_CENTER_JUSTIFY)
+ {
+ x = x - w/2;
+ }
+
+ b->generic.left = x;
+ b->generic.right = x + w;
+ b->generic.top = y;
+ b->generic.bottom = y + h;
+
+ b->shader = 0;
+ b->focusshader = 0;
+}
+
+/*
+=================
+Bitmap_Draw
+=================
+*/
+void Bitmap_Draw( menubitmap_s *b )
+{
+ float x;
+ float y;
+ float w;
+ float h;
+ vec4_t tempcolor;
+ float* color;
+
+ x = b->generic.x;
+ y = b->generic.y;
+ w = b->width;
+ h = b->height;
+
+ if (b->generic.flags & QMF_RIGHT_JUSTIFY)
+ {
+ x = x - w;
+ }
+ else if (b->generic.flags & QMF_CENTER_JUSTIFY)
+ {
+ x = x - w/2;
+ }
+
+ // used to refresh shader
+ if (b->generic.name && !b->shader)
+ {
+ b->shader = trap_R_RegisterShaderNoMip( b->generic.name );
+ if (!b->shader && b->errorpic)
+ b->shader = trap_R_RegisterShaderNoMip( b->errorpic );
+ }
+
+ if (b->focuspic && !b->focusshader)
+ b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );
+
+ if (b->generic.flags & QMF_GRAYED)
+ {
+ if (b->shader)
+ {
+ trap_R_SetColor( colorMdGrey );
+ UI_DrawHandlePic( x, y, w, h, b->shader );
+ trap_R_SetColor( NULL );
+ }
+ }
+ else
+ {
+ if (b->shader)
+ UI_DrawHandlePic( x, y, w, h, b->shader );
+
+ // bk001204 - parentheses
+ if ( ( (b->generic.flags & QMF_PULSE)
+ || (b->generic.flags & QMF_PULSEIFFOCUS) )
+ && (Menu_ItemAtCursor( b->generic.parent ) == b))
+ {
+ if (b->focuscolor)
+ {
+ tempcolor[0] = b->focuscolor[0];
+ tempcolor[1] = b->focuscolor[1];
+ tempcolor[2] = b->focuscolor[2];
+ color = tempcolor;
+ }
+ else
+ color = pulse_color;
+ color[3] = 0.5+0.5*sin(uis.realtime/PULSE_DIVISOR);
+
+ trap_R_SetColor( color );
+ UI_DrawHandlePic( x, y, w, h, b->focusshader );
+ trap_R_SetColor( NULL );
+ }
+ else if ((b->generic.flags & QMF_HIGHLIGHT) || ((b->generic.flags & QMF_HIGHLIGHT_IF_FOCUS) && (Menu_ItemAtCursor( b->generic.parent ) == b)))
+ {
+ if (b->focuscolor)
+ {
+ trap_R_SetColor( b->focuscolor );
+ UI_DrawHandlePic( x, y, w, h, b->focusshader );
+ trap_R_SetColor( NULL );
+ }
+ else
+ UI_DrawHandlePic( x, y, w, h, b->focusshader );
+ }
+ }
+}
+
+/*
+=================
+Action_Init
+=================
+*/
+static void Action_Init( menuaction_s *a )
+{
+ int len;
+
+ // calculate bounds
+ if (a->generic.name)
+ len = strlen(a->generic.name);
+ else
+ len = 0;
+
+ // left justify text
+ a->generic.left = a->generic.x;
+ a->generic.right = a->generic.x + len*BIGCHAR_WIDTH;
+ a->generic.top = a->generic.y;
+ a->generic.bottom = a->generic.y + BIGCHAR_HEIGHT;
+}
+
+/*
+=================
+Action_Draw
+=================
+*/
+static void Action_Draw( menuaction_s *a )
+{
+ int x, y;
+ int style;
+ float* color;
+
+ style = 0;
+ color = menu_text_color;
+ if ( a->generic.flags & QMF_GRAYED )
+ {
+ color = text_color_disabled;
+ }
+ else if (( a->generic.flags & QMF_PULSEIFFOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition ))
+ {
+ color = text_color_highlight;
+ style = UI_PULSE;
+ }
+ else if (( a->generic.flags & QMF_HIGHLIGHT_IF_FOCUS ) && ( a->generic.parent->cursor == a->generic.menuPosition ))
+ {
+ color = text_color_highlight;
+ }
+ else if ( a->generic.flags & QMF_BLINK )
+ {
+ style = UI_BLINK;
+ color = text_color_highlight;
+ }
+
+ x = a->generic.x;
+ y = a->generic.y;
+
+ UI_DrawString( x, y, a->generic.name, UI_LEFT|style, color );
+
+ if ( a->generic.parent->cursor == a->generic.menuPosition )
+ {
+ // draw cursor
+ UI_DrawChar( x - BIGCHAR_WIDTH, y, 13, UI_LEFT|UI_BLINK, color);
+ }
+}
+
+/*
+=================
+RadioButton_Init
+=================
+*/
+static void RadioButton_Init( menuradiobutton_s *rb )
+{
+ int len;
+
+ // calculate bounds
+ if (rb->generic.name)
+ len = strlen(rb->generic.name);
+ else
+ len = 0;
+
+ rb->generic.left = rb->generic.x - (len+1)*SMALLCHAR_WIDTH;
+ rb->generic.right = rb->generic.x + 6*SMALLCHAR_WIDTH;
+ rb->generic.top = rb->generic.y;
+ rb->generic.bottom = rb->generic.y + SMALLCHAR_HEIGHT;
+}
+
+/*
+=================
+RadioButton_Key
+=================
+*/
+static sfxHandle_t RadioButton_Key( menuradiobutton_s *rb, int key )
+{
+ switch (key)
+ {
+ case K_MOUSE1:
+ if (!(rb->generic.flags & QMF_HASMOUSEFOCUS))
+ break;
+
+ case K_JOY1:
+ case K_JOY2:
+ case K_JOY3:
+ case K_JOY4:
+ case K_ENTER:
+ case K_KP_ENTER:
+ case K_KP_LEFTARROW:
+ case K_LEFTARROW:
+ case K_KP_RIGHTARROW:
+ case K_RIGHTARROW:
+ rb->curvalue = !rb->curvalue;
+ if ( rb->generic.callback )
+ rb->generic.callback( rb, QM_ACTIVATED );
+
+ return (menu_move_sound);
+ }
+
+ // key not handled
+ return 0;
+}
+
+/*
+=================
+RadioButton_Draw
+=================
+*/
+static void RadioButton_Draw( menuradiobutton_s *rb )
+{
+ int x;
+ int y;
+ float *color;
+ int style;
+ qboolean focus;
+
+ x = rb->generic.x;
+ y = rb->generic.y;
+
+ focus = (rb->generic.parent->cursor == rb->generic.menuPosition);
+
+ if ( rb->generic.flags & QMF_GRAYED )
+ {
+ color = text_color_disabled;
+ style = UI_LEFT|UI_SMALLFONT;
+ }
+ else if ( focus )
+ {
+ color = text_color_highlight;
+ style = UI_LEFT|UI_PULSE|UI_SMALLFONT;
+ }
+ else
+ {
+ color = text_color_normal;
+ style = UI_LEFT|UI_SMALLFONT;
+ }
+
+ if ( focus )
+ {
+ // draw cursor
+ UI_FillRect( rb->generic.left, rb->generic.top, rb->generic.right-rb->generic.left+1, rb->generic.bottom-rb->generic.top+1, listbar_color );
+ UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
+ }
+
+ if ( rb->generic.name )
+ UI_DrawString( x - SMALLCHAR_WIDTH, y, rb->generic.name, UI_RIGHT|UI_SMALLFONT, color );
+
+ if ( !rb->curvalue )
+ {
+ UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_off);
+ UI_DrawString( x + SMALLCHAR_WIDTH + 16, y, "off", style, color );
+ }
+ else
+ {
+ UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y + 2, 16, 16, uis.rb_on );
+ UI_DrawString( x + SMALLCHAR_WIDTH + 16, y, "on", style, color );
+ }
+}
+
+/*
+=================
+Slider_Init
+=================
+*/
+static void Slider_Init( menuslider_s *s )
+{
+ int len;
+
+ // calculate bounds
+ if (s->generic.name)
+ len = strlen(s->generic.name);
+ else
+ len = 0;
+
+ s->generic.left = s->generic.x - (len+1)*SMALLCHAR_WIDTH;
+ s->generic.right = s->generic.x + (SLIDER_RANGE+2+1)*SMALLCHAR_WIDTH;
+ s->generic.top = s->generic.y;
+ s->generic.bottom = s->generic.y + SMALLCHAR_HEIGHT;
+}
+
+/*
+=================
+Slider_Key
+=================
+*/
+static sfxHandle_t Slider_Key( menuslider_s *s, int key )
+{
+ sfxHandle_t sound;
+ int x;
+ int oldvalue;
+
+ switch (key)
+ {
+ case K_MOUSE1:
+ x = uis.cursorx - s->generic.x - 2*SMALLCHAR_WIDTH;
+ oldvalue = s->curvalue;
+ s->curvalue = (x/(float)(SLIDER_RANGE*SMALLCHAR_WIDTH)) * (s->maxvalue-s->minvalue) + s->minvalue;
+
+ if (s->curvalue < s->minvalue)
+ s->curvalue = s->minvalue;
+ else if (s->curvalue > s->maxvalue)
+ s->curvalue = s->maxvalue;
+ if (s->curvalue != oldvalue)
+ sound = menu_move_sound;
+ else
+ sound = 0;
+ break;
+
+ case K_KP_LEFTARROW:
+ case K_LEFTARROW:
+ if (s->curvalue > s->minvalue)
+ {
+ s->curvalue--;
+ sound = menu_move_sound;
+ }
+ else
+ sound = menu_buzz_sound;
+ break;
+
+ case K_KP_RIGHTARROW:
+ case K_RIGHTARROW:
+ if (s->curvalue < s->maxvalue)
+ {
+ s->curvalue++;
+ sound = menu_move_sound;
+ }
+ else
+ sound = menu_buzz_sound;
+ break;
+
+ default:
+ // key not handled
+ sound = 0;
+ break;
+ }
+
+ if ( sound && s->generic.callback )
+ s->generic.callback( s, QM_ACTIVATED );
+
+ return (sound);
+}
+
+#if 1
+/*
+=================
+Slider_Draw
+=================
+*/
+static void Slider_Draw( menuslider_s *s ) {
+ int x;
+ int y;
+ int style;
+ float *color;
+ int button;
+ qboolean focus;
+
+ x = s->generic.x;
+ y = s->generic.y;
+ focus = (s->generic.parent->cursor == s->generic.menuPosition);
+
+ if( s->generic.flags & QMF_GRAYED ) {
+ color = text_color_disabled;
+ style = UI_SMALLFONT;
+ }
+ else if( focus ) {
+ color = text_color_highlight;
+ style = UI_SMALLFONT | UI_PULSE;
+ }
+ else {
+ color = text_color_normal;
+ style = UI_SMALLFONT;
+ }
+
+ // draw label
+ UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color );
+
+ // draw slider
+ UI_SetColor( color );
+ UI_DrawHandlePic( x + SMALLCHAR_WIDTH, y, 96, 16, sliderBar );
+ UI_SetColor( NULL );
+
+ // clamp thumb
+ if( s->maxvalue > s->minvalue ) {
+ s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
+ if( s->range < 0 ) {
+ s->range = 0;
+ }
+ else if( s->range > 1) {
+ s->range = 1;
+ }
+ }
+ else {
+ s->range = 0;
+ }
+
+ // draw thumb
+ if( style & UI_PULSE) {
+ button = sliderButton_1;
+ }
+ else {
+ button = sliderButton_0;
+ }
+
+ UI_DrawHandlePic( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ) - 2, y - 2, 12, 20, button );
+}
+#else
+/*
+=================
+Slider_Draw
+=================
+*/
+static void Slider_Draw( menuslider_s *s )
+{
+ float *color;
+ int style;
+ int i;
+ int x;
+ int y;
+ qboolean focus;
+
+ x = s->generic.x;
+ y = s->generic.y;
+ focus = (s->generic.parent->cursor == s->generic.menuPosition);
+
+ style = UI_SMALLFONT;
+ if ( s->generic.flags & QMF_GRAYED )
+ {
+ color = text_color_disabled;
+ }
+ else if (focus)
+ {
+ color = text_color_highlight;
+ style |= UI_PULSE;
+ }
+ else
+ {
+ color = text_color_normal;
+ }
+
+ if ( focus )
+ {
+ // draw cursor
+ UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
+ UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
+ }
+
+ // draw label
+ UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, UI_RIGHT|style, color );
+
+ // draw slider
+ UI_DrawChar( x + SMALLCHAR_WIDTH, y, 128, UI_LEFT|style, color);
+ for ( i = 0; i < SLIDER_RANGE; i++ )
+ UI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 129, UI_LEFT|style, color);
+ UI_DrawChar( x + (i+2)*SMALLCHAR_WIDTH, y, 130, UI_LEFT|style, color);
+
+ // clamp thumb
+ if (s->maxvalue > s->minvalue)
+ {
+ s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue );
+ if ( s->range < 0)
+ s->range = 0;
+ else if ( s->range > 1)
+ s->range = 1;
+ }
+ else
+ s->range = 0;
+
+ // draw thumb
+ if (style & UI_PULSE) {
+ style &= ~UI_PULSE;
+ style |= UI_BLINK;
+ }
+ UI_DrawChar( (int)( x + 2*SMALLCHAR_WIDTH + (SLIDER_RANGE-1)*SMALLCHAR_WIDTH* s->range ), y, 131, UI_LEFT|style, color);
+}
+#endif
+
+/*
+=================
+SpinControl_Init
+=================
+*/
+static void SpinControl_Init( menulist_s *s ) {
+ int len;
+ int l;
+ const char* str;
+
+ if (s->generic.name)
+ len = strlen(s->generic.name) * SMALLCHAR_WIDTH;
+ else
+ len = 0;
+
+ s->generic.left = s->generic.x - SMALLCHAR_WIDTH - len;
+
+ len = s->numitems = 0;
+ while ( (str = s->itemnames[s->numitems]) != 0 )
+ {
+ l = strlen(str);
+ if (l > len)
+ len = l;
+
+ s->numitems++;
+ }
+
+ s->generic.top = s->generic.y;
+ s->generic.right = s->generic.x + (len+1)*SMALLCHAR_WIDTH;
+ s->generic.bottom = s->generic.y + SMALLCHAR_HEIGHT;
+}
+
+/*
+=================
+SpinControl_Key
+=================
+*/
+static sfxHandle_t SpinControl_Key( menulist_s *s, int key )
+{
+ sfxHandle_t sound;
+
+ sound = 0;
+ switch (key)
+ {
+ case K_MOUSE1:
+ s->curvalue++;
+ if (s->curvalue >= s->numitems)
+ s->curvalue = 0;
+ sound = menu_move_sound;
+ break;
+
+ case K_KP_LEFTARROW:
+ case K_LEFTARROW:
+ if (s->curvalue > 0)
+ {
+ s->curvalue--;
+ sound = menu_move_sound;
+ }
+ else
+ sound = menu_buzz_sound;
+ break;
+
+ case K_KP_RIGHTARROW:
+ case K_RIGHTARROW:
+ if (s->curvalue < s->numitems-1)
+ {
+ s->curvalue++;
+ sound = menu_move_sound;
+ }
+ else
+ sound = menu_buzz_sound;
+ break;
+ }
+
+ if ( sound && s->generic.callback )
+ s->generic.callback( s, QM_ACTIVATED );
+
+ return (sound);
+}
+
+/*
+=================
+SpinControl_Draw
+=================
+*/
+static void SpinControl_Draw( menulist_s *s )
+{
+ float *color;
+ int x,y;
+ int style;
+ qboolean focus;
+
+ x = s->generic.x;
+ y = s->generic.y;
+
+ style = UI_SMALLFONT;
+ focus = (s->generic.parent->cursor == s->generic.menuPosition);
+
+ if ( s->generic.flags & QMF_GRAYED )
+ color = text_color_disabled;
+ else if ( focus )
+ {
+ color = text_color_highlight;
+ style |= UI_PULSE;
+ }
+ else if ( s->generic.flags & QMF_BLINK )
+ {
+ color = text_color_highlight;
+ style |= UI_BLINK;
+ }
+ else
+ color = text_color_normal;
+
+ if ( focus )
+ {
+ // draw cursor
+ UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
+ UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
+ }
+
+ UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
+ UI_DrawString( x + SMALLCHAR_WIDTH, y, s->itemnames[s->curvalue], style|UI_LEFT, color );
+}
+
+/*
+=================
+ScrollList_Init
+=================
+*/
+static void ScrollList_Init( menulist_s *l )
+{
+ int w;
+
+ l->oldvalue = 0;
+ l->curvalue = 0;
+ l->top = 0;
+
+ if( !l->columns ) {
+ l->columns = 1;
+ l->seperation = 0;
+ }
+ else if( !l->seperation ) {
+ l->seperation = 3;
+ }
+
+ w = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH;
+
+ l->generic.left = l->generic.x;
+ l->generic.top = l->generic.y;
+ l->generic.right = l->generic.x + w;
+ l->generic.bottom = l->generic.y + l->height * SMALLCHAR_HEIGHT;
+
+ if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
+ l->generic.left -= w / 2;
+ l->generic.right -= w / 2;
+ }
+}
+
+/*
+=================
+ScrollList_Key
+=================
+*/
+sfxHandle_t ScrollList_Key( menulist_s *l, int key )
+{
+ int x;
+ int y;
+ int w;
+ int i;
+ int j;
+ int c;
+ int cursorx;
+ int cursory;
+ int column;
+ int index;
+
+ switch (key)
+ {
+ case K_MOUSE1:
+ if (l->generic.flags & QMF_HASMOUSEFOCUS)
+ {
+ // check scroll region
+ x = l->generic.x;
+ y = l->generic.y;
+ w = ( (l->width + l->seperation) * l->columns - l->seperation) * SMALLCHAR_WIDTH;
+ if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
+ x -= w / 2;
+ }
+ if (UI_CursorInRect( x, y, w, l->height*SMALLCHAR_HEIGHT ))
+ {
+ cursorx = (uis.cursorx - x)/SMALLCHAR_WIDTH;
+ column = cursorx / (l->width + l->seperation);
+ cursory = (uis.cursory - y)/SMALLCHAR_HEIGHT;
+ index = column * l->height + cursory;
+ if (l->top + index < l->numitems)
+ {
+ l->oldvalue = l->curvalue;
+ l->curvalue = l->top + index;
+
+ if (l->oldvalue != l->curvalue && l->generic.callback)
+ {
+ l->generic.callback( l, QM_GOTFOCUS );
+ return (menu_move_sound);
+ }
+ }
+ }
+
+ // absorbed, silent sound effect
+ return (menu_null_sound);
+ }
+ break;
+
+ case K_KP_HOME:
+ case K_HOME:
+ l->oldvalue = l->curvalue;
+ l->curvalue = 0;
+ l->top = 0;
+
+ if (l->oldvalue != l->curvalue && l->generic.callback)
+ {
+ l->generic.callback( l, QM_GOTFOCUS );
+ return (menu_move_sound);
+ }
+ return (menu_buzz_sound);
+
+ case K_KP_END:
+ case K_END:
+ l->oldvalue = l->curvalue;
+ l->curvalue = l->numitems-1;
+ if( l->columns > 1 ) {
+ c = (l->curvalue / l->height + 1) * l->height;
+ l->top = c - (l->columns * l->height);
+ }
+ else {
+ l->top = l->curvalue - (l->height - 1);
+ }
+ if (l->top < 0)
+ l->top = 0;
+
+ if (l->oldvalue != l->curvalue && l->generic.callback)
+ {
+ l->generic.callback( l, QM_GOTFOCUS );
+ return (menu_move_sound);
+ }
+ return (menu_buzz_sound);
+
+ case K_PGUP:
+ case K_KP_PGUP:
+ if( l->columns > 1 ) {
+ return menu_null_sound;
+ }
+
+ if (l->curvalue > 0)
+ {
+ l->oldvalue = l->curvalue;
+ l->curvalue -= l->height-1;
+ if (l->curvalue < 0)
+ l->curvalue = 0;
+ l->top = l->curvalue;
+ if (l->top < 0)
+ l->top = 0;
+
+ if (l->generic.callback)
+ l->generic.callback( l, QM_GOTFOCUS );
+
+ return (menu_move_sound);
+ }
+ return (menu_buzz_sound);
+
+ case K_PGDN:
+ case K_KP_PGDN:
+ if( l->columns > 1 ) {
+ return menu_null_sound;
+ }
+
+ if (l->curvalue < l->numitems-1)
+ {
+ l->oldvalue = l->curvalue;
+ l->curvalue += l->height-1;
+ if (l->curvalue > l->numitems-1)
+ l->curvalue = l->numitems-1;
+ l->top = l->curvalue - (l->height-1);
+ if (l->top < 0)
+ l->top = 0;
+
+ if (l->generic.callback)
+ l->generic.callback( l, QM_GOTFOCUS );
+
+ return (menu_move_sound);
+ }
+ return (menu_buzz_sound);
+
+ case K_KP_UPARROW:
+ case K_UPARROW:
+ if( l->curvalue == 0 ) {
+ return menu_buzz_sound;
+ }
+
+ l->oldvalue = l->curvalue;
+ l->curvalue--;
+
+ if( l->curvalue < l->top ) {
+ if( l->columns == 1 ) {
+ l->top--;
+ }
+ else {
+ l->top -= l->height;
+ }
+ }
+
+ if( l->generic.callback ) {
+ l->generic.callback( l, QM_GOTFOCUS );
+ }
+
+ return (menu_move_sound);
+
+ case K_KP_DOWNARROW:
+ case K_DOWNARROW:
+ if( l->curvalue == l->numitems - 1 ) {
+ return menu_buzz_sound;
+ }
+
+ l->oldvalue = l->curvalue;
+ l->curvalue++;
+
+ if( l->curvalue >= l->top + l->columns * l->height ) {
+ if( l->columns == 1 ) {
+ l->top++;
+ }
+ else {
+ l->top += l->height;
+ }
+ }
+
+ if( l->generic.callback ) {
+ l->generic.callback( l, QM_GOTFOCUS );
+ }
+
+ return menu_move_sound;
+
+ case K_KP_LEFTARROW:
+ case K_LEFTARROW:
+ if( l->columns == 1 ) {
+ return menu_null_sound;
+ }
+
+ if( l->curvalue < l->height ) {
+ return menu_buzz_sound;
+ }
+
+ l->oldvalue = l->curvalue;
+ l->curvalue -= l->height;
+
+ if( l->curvalue < l->top ) {
+ l->top -= l->height;
+ }
+
+ if( l->generic.callback ) {
+ l->generic.callback( l, QM_GOTFOCUS );
+ }
+
+ return menu_move_sound;
+
+ case K_KP_RIGHTARROW:
+ case K_RIGHTARROW:
+ if( l->columns == 1 ) {
+ return menu_null_sound;
+ }
+
+ c = l->curvalue + l->height;
+
+ if( c >= l->numitems ) {
+ return menu_buzz_sound;
+ }
+
+ l->oldvalue = l->curvalue;
+ l->curvalue = c;
+
+ if( l->curvalue > l->top + l->columns * l->height - 1 ) {
+ l->top += l->height;
+ }
+
+ if( l->generic.callback ) {
+ l->generic.callback( l, QM_GOTFOCUS );
+ }
+
+ return menu_move_sound;
+ }
+
+ // cycle look for ascii key inside list items
+ if ( !Q_isprint( key ) )
+ return (0);
+
+ // force to lower for case insensitive compare
+ if ( Q_isupper( key ) )
+ {
+ key -= 'A' - 'a';
+ }
+
+ // iterate list items
+ for (i=1; i<=l->numitems; i++)
+ {
+ j = (l->curvalue + i) % l->numitems;
+ c = l->itemnames[j][0];
+ if ( Q_isupper( c ) )
+ {
+ c -= 'A' - 'a';
+ }
+
+ if (c == key)
+ {
+ // set current item, mimic windows listbox scroll behavior
+ if (j < l->top)
+ {
+ // behind top most item, set this as new top
+ l->top = j;
+ }
+ else if (j > l->top+l->height-1)
+ {
+ // past end of list box, do page down
+ l->top = (j+1) - l->height;
+ }
+
+ if (l->curvalue != j)
+ {
+ l->oldvalue = l->curvalue;
+ l->curvalue = j;
+ if (l->generic.callback)
+ l->generic.callback( l, QM_GOTFOCUS );
+ return ( menu_move_sound );
+ }
+
+ return (menu_buzz_sound);
+ }
+ }
+
+ return (menu_buzz_sound);
+}
+
+/*
+=================
+ScrollList_Draw
+=================
+*/
+void ScrollList_Draw( menulist_s *l )
+{
+ int x;
+ int u;
+ int y;
+ int i;
+ int base;
+ int column;
+ float* color;
+ qboolean hasfocus;
+ int style;
+
+ hasfocus = (l->generic.parent->cursor == l->generic.menuPosition);
+
+ x = l->generic.x;
+ for( column = 0; column < l->columns; column++ ) {
+ y = l->generic.y;
+ base = l->top + column * l->height;
+ for( i = base; i < base + l->height; i++) {
+ if (i >= l->numitems)
+ break;
+
+ if (i == l->curvalue)
+ {
+ u = x - 2;
+ if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
+ u -= (l->width * SMALLCHAR_WIDTH) / 2 + 1;
+ }
+
+ UI_FillRect(u,y,l->width*SMALLCHAR_WIDTH,SMALLCHAR_HEIGHT+2,listbar_color);
+ color = text_color_highlight;
+
+ if (hasfocus)
+ style = UI_PULSE|UI_LEFT|UI_SMALLFONT;
+ else
+ style = UI_LEFT|UI_SMALLFONT;
+ }
+ else
+ {
+ color = text_color_normal;
+ style = UI_LEFT|UI_SMALLFONT;
+ }
+ if( l->generic.flags & QMF_CENTER_JUSTIFY ) {
+ style |= UI_CENTER;
+ }
+
+ UI_DrawString(
+ x,
+ y,
+ l->itemnames[i],
+ style,
+ color);
+
+ y += SMALLCHAR_HEIGHT;
+ }
+ x += (l->width + l->seperation) * SMALLCHAR_WIDTH;
+ }
+}
+
+/*
+=================
+Menu_AddItem
+=================
+*/
+void Menu_AddItem( menuframework_s *menu, void *item )
+{
+ menucommon_s *itemptr;
+
+ if (menu->nitems >= MAX_MENUITEMS)
+ trap_Error ("Menu_AddItem: excessive items");
+
+ menu->items[menu->nitems] = item;
+ ((menucommon_s*)menu->items[menu->nitems])->parent = menu;
+ ((menucommon_s*)menu->items[menu->nitems])->menuPosition = menu->nitems;
+ ((menucommon_s*)menu->items[menu->nitems])->flags &= ~QMF_HASMOUSEFOCUS;
+
+ // perform any item specific initializations
+ itemptr = (menucommon_s*)item;
+ if (!(itemptr->flags & QMF_NODEFAULTINIT))
+ {
+ switch (itemptr->type)
+ {
+ case MTYPE_ACTION:
+ Action_Init((menuaction_s*)item);
+ break;
+
+ case MTYPE_FIELD:
+ MenuField_Init((menufield_s*)item);
+ break;
+
+ case MTYPE_SPINCONTROL:
+ SpinControl_Init((menulist_s*)item);
+ break;
+
+ case MTYPE_RADIOBUTTON:
+ RadioButton_Init((menuradiobutton_s*)item);
+ break;
+
+ case MTYPE_SLIDER:
+ Slider_Init((menuslider_s*)item);
+ break;
+
+ case MTYPE_BITMAP:
+ Bitmap_Init((menubitmap_s*)item);
+ break;
+
+ case MTYPE_TEXT:
+ Text_Init((menutext_s*)item);
+ break;
+
+ case MTYPE_SCROLLLIST:
+ ScrollList_Init((menulist_s*)item);
+ break;
+
+ case MTYPE_PTEXT:
+ PText_Init((menutext_s*)item);
+ break;
+
+ case MTYPE_BTEXT:
+ BText_Init((menutext_s*)item);
+ break;
+
+ default:
+ trap_Error( va("Menu_Init: unknown type %d", itemptr->type) );
+ }
+ }
+
+ menu->nitems++;
+}
+
+/*
+=================
+Menu_CursorMoved
+=================
+*/
+void Menu_CursorMoved( menuframework_s *m )
+{
+ void (*callback)( void *self, int notification );
+
+ if (m->cursor_prev == m->cursor)
+ return;
+
+ if (m->cursor_prev >= 0 && m->cursor_prev < m->nitems)
+ {
+ callback = ((menucommon_s*)(m->items[m->cursor_prev]))->callback;
+ if (callback)
+ callback(m->items[m->cursor_prev],QM_LOSTFOCUS);
+ }
+
+ if (m->cursor >= 0 && m->cursor < m->nitems)
+ {
+ callback = ((menucommon_s*)(m->items[m->cursor]))->callback;
+ if (callback)
+ callback(m->items[m->cursor],QM_GOTFOCUS);
+ }
+}
+
+/*
+=================
+Menu_SetCursor
+=================
+*/
+void Menu_SetCursor( menuframework_s *m, int cursor )
+{
+ if (((menucommon_s*)(m->items[cursor]))->flags & (QMF_GRAYED|QMF_INACTIVE))
+ {
+ // cursor can't go there
+ return;
+ }
+
+ m->cursor_prev = m->cursor;
+ m->cursor = cursor;
+
+ Menu_CursorMoved( m );
+}
+
+/*
+=================
+Menu_SetCursorToItem
+=================
+*/
+void Menu_SetCursorToItem( menuframework_s *m, void* ptr )
+{
+ int i;
+
+ for (i=0; i<m->nitems; i++)
+ {
+ if (m->items[i] == ptr)
+ {
+ Menu_SetCursor( m, i );
+ return;
+ }
+ }
+}
+
+/*
+** Menu_AdjustCursor
+**
+** This function takes the given menu, the direction, and attempts
+** to adjust the menu's cursor so that it's at the next available
+** slot.
+*/
+void Menu_AdjustCursor( menuframework_s *m, int dir ) {
+ menucommon_s *item = NULL;
+ qboolean wrapped = qfalse;
+
+wrap:
+ while ( m->cursor >= 0 && m->cursor < m->nitems ) {
+ item = ( menucommon_s * ) m->items[m->cursor];
+ if (( item->flags & (QMF_GRAYED|QMF_MOUSEONLY|QMF_INACTIVE) ) ) {
+ m->cursor += dir;
+ }
+ else {
+ break;
+ }
+ }
+
+ if ( dir == 1 ) {
+ if ( m->cursor >= m->nitems ) {
+ if ( m->wrapAround ) {
+ if ( wrapped ) {
+ m->cursor = m->cursor_prev;
+ return;
+ }
+ m->cursor = 0;
+ wrapped = qtrue;
+ goto wrap;
+ }
+ m->cursor = m->cursor_prev;
+ }
+ }
+ else {
+ if ( m->cursor < 0 ) {
+ if ( m->wrapAround ) {
+ if ( wrapped ) {
+ m->cursor = m->cursor_prev;
+ return;
+ }
+ m->cursor = m->nitems - 1;
+ wrapped = qtrue;
+ goto wrap;
+ }
+ m->cursor = m->cursor_prev;
+ }
+ }
+}
+
+/*
+=================
+Menu_Draw
+=================
+*/
+void Menu_Draw( menuframework_s *menu )
+{
+ int i;
+ menucommon_s *itemptr;
+
+ // draw menu
+ for (i=0; i<menu->nitems; i++)
+ {
+ itemptr = (menucommon_s*)menu->items[i];
+
+ if (itemptr->flags & QMF_HIDDEN)
+ continue;
+
+ if (itemptr->ownerdraw)
+ {
+ // total subclassing, owner draws everything
+ itemptr->ownerdraw( itemptr );
+ }
+ else
+ {
+ switch (itemptr->type)
+ {
+ case MTYPE_RADIOBUTTON:
+ RadioButton_Draw( (menuradiobutton_s*)itemptr );
+ break;
+
+ case MTYPE_FIELD:
+ MenuField_Draw( (menufield_s*)itemptr );
+ break;
+
+ case MTYPE_SLIDER:
+ Slider_Draw( (menuslider_s*)itemptr );
+ break;
+
+ case MTYPE_SPINCONTROL:
+ SpinControl_Draw( (menulist_s*)itemptr );
+ break;
+
+ case MTYPE_ACTION:
+ Action_Draw( (menuaction_s*)itemptr );
+ break;
+
+ case MTYPE_BITMAP:
+ Bitmap_Draw( (menubitmap_s*)itemptr );
+ break;
+
+ case MTYPE_TEXT:
+ Text_Draw( (menutext_s*)itemptr );
+ break;
+
+ case MTYPE_SCROLLLIST:
+ ScrollList_Draw( (menulist_s*)itemptr );
+ break;
+
+ case MTYPE_PTEXT:
+ PText_Draw( (menutext_s*)itemptr );
+ break;
+
+ case MTYPE_BTEXT:
+ BText_Draw( (menutext_s*)itemptr );
+ break;
+
+ default:
+ trap_Error( va("Menu_Draw: unknown type %d", itemptr->type) );
+ }
+ }
+#ifndef NDEBUG
+ if( uis.debug ) {
+ int x;
+ int y;
+ int w;
+ int h;
+
+ if( !( itemptr->flags & QMF_INACTIVE ) ) {
+ x = itemptr->left;
+ y = itemptr->top;
+ w = itemptr->right - itemptr->left + 1;
+ h = itemptr->bottom - itemptr->top + 1;
+
+ if (itemptr->flags & QMF_HASMOUSEFOCUS) {
+ UI_DrawRect(x, y, w, h, colorYellow );
+ }
+ else {
+ UI_DrawRect(x, y, w, h, colorWhite );
+ }
+ }
+ }
+#endif
+ }
+
+ itemptr = Menu_ItemAtCursor( menu );
+ if ( itemptr && itemptr->statusbar)
+ itemptr->statusbar( ( void * ) itemptr );
+}
+
+/*
+=================
+Menu_ItemAtCursor
+=================
+*/
+void *Menu_ItemAtCursor( menuframework_s *m )
+{
+ if ( m->cursor < 0 || m->cursor >= m->nitems )
+ return 0;
+
+ return m->items[m->cursor];
+}
+
+/*
+=================
+Menu_ActivateItem
+=================
+*/
+sfxHandle_t Menu_ActivateItem( menuframework_s *s, menucommon_s* item ) {
+ if ( item->callback ) {
+ item->callback( item, QM_ACTIVATED );
+ if( !( item->flags & QMF_SILENT ) ) {
+ return menu_move_sound;
+ }
+ }
+
+ return 0;
+}
+
+/*
+=================
+Menu_DefaultKey
+=================
+*/
+sfxHandle_t Menu_DefaultKey( menuframework_s *m, int key )
+{
+ sfxHandle_t sound = 0;
+ menucommon_s *item;
+ int cursor_prev;
+
+ // menu system keys
+ switch ( key )
+ {
+ case K_MOUSE2:
+ case K_ESCAPE:
+ UI_PopMenu();
+ return menu_out_sound;
+ }
+
+ if (!m || !m->nitems)
+ return 0;
+
+ // route key stimulus to widget
+ item = Menu_ItemAtCursor( m );
+ if (item && !(item->flags & (QMF_GRAYED|QMF_INACTIVE)))
+ {
+ switch (item->type)
+ {
+ case MTYPE_SPINCONTROL:
+ sound = SpinControl_Key( (menulist_s*)item, key );
+ break;
+
+ case MTYPE_RADIOBUTTON:
+ sound = RadioButton_Key( (menuradiobutton_s*)item, key );
+ break;
+
+ case MTYPE_SLIDER:
+ sound = Slider_Key( (menuslider_s*)item, key );
+ break;
+
+ case MTYPE_SCROLLLIST:
+ sound = ScrollList_Key( (menulist_s*)item, key );
+ break;
+
+ case MTYPE_FIELD:
+ sound = MenuField_Key( (menufield_s*)item, &key );
+ break;
+ }
+
+ if (sound) {
+ // key was handled
+ return sound;
+ }
+ }
+
+ // default handling
+ switch ( key )
+ {
+#ifndef NDEBUG
+ case K_F11:
+ uis.debug ^= 1;
+ break;
+
+ case K_F12:
+ trap_Cmd_ExecuteText(EXEC_APPEND, "screenshot\n");
+ break;
+#endif
+ case K_KP_UPARROW:
+ case K_UPARROW:
+ cursor_prev = m->cursor;
+ m->cursor_prev = m->cursor;
+ m->cursor--;
+ Menu_AdjustCursor( m, -1 );
+ if ( cursor_prev != m->cursor ) {
+ Menu_CursorMoved( m );
+ sound = menu_move_sound;
+ }
+ break;
+
+ case K_TAB:
+ case K_KP_DOWNARROW:
+ case K_DOWNARROW:
+ cursor_prev = m->cursor;
+ m->cursor_prev = m->cursor;
+ m->cursor++;
+ Menu_AdjustCursor( m, 1 );
+ if ( cursor_prev != m->cursor ) {
+ Menu_CursorMoved( m );
+ sound = menu_move_sound;
+ }
+ break;
+
+ case K_MOUSE1:
+ case K_MOUSE3:
+ if (item)
+ if ((item->flags & QMF_HASMOUSEFOCUS) && !(item->flags & (QMF_GRAYED|QMF_INACTIVE)))
+ return (Menu_ActivateItem( m, item ));
+ break;
+
+ case K_JOY1:
+ case K_JOY2:
+ case K_JOY3:
+ case K_JOY4:
+ case K_AUX1:
+ case K_AUX2:
+ case K_AUX3:
+ case K_AUX4:
+ case K_AUX5:
+ case K_AUX6:
+ case K_AUX7:
+ case K_AUX8:
+ case K_AUX9:
+ case K_AUX10:
+ case K_AUX11:
+ case K_AUX12:
+ case K_AUX13:
+ case K_AUX14:
+ case K_AUX15:
+ case K_AUX16:
+ case K_KP_ENTER:
+ case K_ENTER:
+ if (item)
+ if (!(item->flags & (QMF_MOUSEONLY|QMF_GRAYED|QMF_INACTIVE)))
+ return (Menu_ActivateItem( m, item ));
+ break;
+ }
+
+ return sound;
+}
+
+/*
+=================
+Menu_Cache
+=================
+*/
+void Menu_Cache( void )
+{
+ uis.charset = trap_R_RegisterShaderNoMip( "gfx/2d/bigchars" );
+ uis.charsetProp = trap_R_RegisterShaderNoMip( "menu/art/font1_prop.tga" );
+ uis.charsetPropGlow = trap_R_RegisterShaderNoMip( "menu/art/font1_prop_glo.tga" );
+ uis.charsetPropB = trap_R_RegisterShaderNoMip( "menu/art/font2_prop.tga" );
+ uis.cursor = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
+ uis.rb_on = trap_R_RegisterShaderNoMip( "menu/art/switch_on" );
+ uis.rb_off = trap_R_RegisterShaderNoMip( "menu/art/switch_off" );
+
+ uis.whiteShader = trap_R_RegisterShaderNoMip( "white" );
+ if ( uis.glconfig.hardwareType == GLHW_RAGEPRO ) {
+ // the blend effect turns to shit with the normal
+ uis.menuBackShader = trap_R_RegisterShaderNoMip( "menubackRagePro" );
+ } else {
+ uis.menuBackShader = trap_R_RegisterShaderNoMip( "menuback" );
+ }
+ uis.menuBackNoLogoShader = trap_R_RegisterShaderNoMip( "menubacknologo" );
+
+ menu_in_sound = trap_S_RegisterSound( "sound/misc/menu1.wav", qfalse );
+ menu_move_sound = trap_S_RegisterSound( "sound/misc/menu2.wav", qfalse );
+ menu_out_sound = trap_S_RegisterSound( "sound/misc/menu3.wav", qfalse );
+ menu_buzz_sound = trap_S_RegisterSound( "sound/misc/menu4.wav", qfalse );
+ weaponChangeSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse );
+
+ // need a nonzero sound, make an empty sound for this
+ menu_null_sound = -1;
+
+ sliderBar = trap_R_RegisterShaderNoMip( "menu/art/slider2" );
+ sliderButton_0 = trap_R_RegisterShaderNoMip( "menu/art/sliderbutt_0" );
+ sliderButton_1 = trap_R_RegisterShaderNoMip( "menu/art/sliderbutt_1" );
+}
+