2020-08-31 18:50:41 +02:00
|
|
|
/*
|
|
|
|
Copyright (C) 1997-2001 Id Software, Inc.
|
|
|
|
|
|
|
|
This program 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.
|
|
|
|
|
|
|
|
This program 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 this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// ui_qmenu.c -- Quake menu framework
|
|
|
|
|
|
|
|
#include "extdll.h"
|
|
|
|
#include "basemenu.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "keydefs.h"
|
|
|
|
#include "menu_btnsbmp_table.h"
|
|
|
|
//CR
|
|
|
|
#include "ui_title_anim.h"
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
void DBG_AssertFunction( BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage )
|
|
|
|
{
|
|
|
|
if( fExpr ) return;
|
|
|
|
|
|
|
|
char szOut[512];
|
|
|
|
if( szMessage != NULL )
|
|
|
|
sprintf( szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage );
|
|
|
|
else sprintf( szOut, "ASSERT FAILED:\n %s \n(%s@%d)", szExpr, szFile, szLine );
|
|
|
|
HOST_ERROR( szOut );
|
|
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
int ColorStrlen( const char *str )
|
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
|
|
|
|
if( !str )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int len = 0;
|
|
|
|
p = str;
|
|
|
|
|
|
|
|
while( *p )
|
|
|
|
{
|
|
|
|
if( IsColorString( p ))
|
|
|
|
{
|
|
|
|
p += 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
p++;
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ColorPrexfixCount( const char *str )
|
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
|
|
|
|
if( !str )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int len = 0;
|
|
|
|
p = str;
|
|
|
|
|
|
|
|
while( *p )
|
|
|
|
{
|
|
|
|
if( IsColorString( p ))
|
|
|
|
{
|
|
|
|
len += 2;
|
|
|
|
p += 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StringConcat( char *dst, const char *src, size_t size )
|
|
|
|
{
|
|
|
|
register char *d = dst;
|
|
|
|
register const char *s = src;
|
|
|
|
register size_t n = size;
|
|
|
|
size_t dlen;
|
|
|
|
|
|
|
|
if( !dst || !src || !size )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// find the end of dst and adjust bytes left but don't go past end
|
|
|
|
while(n-- != 0 && *d != '\0') d++;
|
|
|
|
dlen = d - dst;
|
|
|
|
n = size - dlen;
|
|
|
|
|
|
|
|
if ( n == 0 ) return;
|
|
|
|
while ( *s != '\0' )
|
|
|
|
{
|
|
|
|
if ( n != 1 )
|
|
|
|
{
|
|
|
|
*d++ = *s;
|
|
|
|
n--;
|
|
|
|
}
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*d = '\0';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *StringCopy( const char *input )
|
|
|
|
{
|
|
|
|
if( !input ) return NULL;
|
|
|
|
|
|
|
|
char *out = (char *)MALLOC( strlen( input ) + 1 );
|
|
|
|
strcpy( out, input );
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
COM_CompareSaves
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
int COM_CompareSaves( const void **a, const void **b )
|
|
|
|
{
|
|
|
|
char *file1, *file2;
|
|
|
|
|
|
|
|
file1 = (char *)*a;
|
|
|
|
file2 = (char *)*b;
|
|
|
|
|
|
|
|
int bResult;
|
|
|
|
|
|
|
|
COMPARE_FILE_TIME( file2, file1, &bResult );
|
|
|
|
|
|
|
|
return bResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
COM_FileBase
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
// Extracts the base name of a file (no path, no extension, assumes '/' as path separator)
|
|
|
|
void COM_FileBase ( const char *in, char *out )
|
|
|
|
{
|
|
|
|
int len, start, end;
|
|
|
|
|
|
|
|
len = strlen( in );
|
|
|
|
|
|
|
|
// scan backward for '.'
|
|
|
|
end = len - 1;
|
|
|
|
while ( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' )
|
|
|
|
end--;
|
|
|
|
|
|
|
|
if ( in[end] != '.' ) // no '.', copy to end
|
|
|
|
end = len-1;
|
|
|
|
else
|
|
|
|
end--; // Found ',', copy to left of '.'
|
|
|
|
|
|
|
|
|
|
|
|
// Scan backward for '/'
|
|
|
|
start = len-1;
|
|
|
|
while ( start >= 0 && in[start] != '/' && in[start] != '\\' )
|
|
|
|
start--;
|
|
|
|
|
|
|
|
if ( in[start] != '/' && in[start] != '\\' )
|
|
|
|
start = 0;
|
|
|
|
else
|
|
|
|
start++;
|
|
|
|
|
|
|
|
// Length of new sting
|
|
|
|
len = end - start + 1;
|
|
|
|
|
|
|
|
// Copy partial string
|
|
|
|
strncpy( out, &in[start], len );
|
|
|
|
// Terminate it
|
|
|
|
out[len] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Info_ValueForKey
|
|
|
|
|
|
|
|
Searches the string for the given
|
|
|
|
key and returns the associated value, or an empty string.
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
char *Info_ValueForKey( const char *s, const char *key )
|
|
|
|
{
|
|
|
|
static char value[MAX_INFO_STRING];
|
|
|
|
char pkey[MAX_INFO_STRING];
|
|
|
|
|
|
|
|
if ( *s == '\\' )
|
|
|
|
s++;
|
|
|
|
|
|
|
|
while ( 1 )
|
|
|
|
{
|
|
|
|
char *o = pkey;
|
|
|
|
|
|
|
|
while ( *s != '\\' && *s != '\n' )
|
|
|
|
{
|
|
|
|
if ( !*s )
|
|
|
|
return "";
|
|
|
|
*o++ = *s++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*o = 0;
|
|
|
|
s++;
|
|
|
|
|
|
|
|
o = value;
|
|
|
|
|
|
|
|
while ( *s != '\\' && *s != '\n' && *s )
|
|
|
|
{
|
|
|
|
if ( !*s )
|
|
|
|
return "";
|
|
|
|
*o++ = *s++;
|
|
|
|
}
|
|
|
|
*o = 0;
|
|
|
|
|
|
|
|
if ( !strcmp( key, pkey ))
|
|
|
|
return value;
|
|
|
|
|
|
|
|
if ( !*s )
|
|
|
|
return "";
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===================
|
|
|
|
Key_GetKey
|
|
|
|
===================
|
|
|
|
*/
|
|
|
|
int KEY_GetKey( const char *binding )
|
|
|
|
{
|
|
|
|
const char *b;
|
|
|
|
|
|
|
|
if ( !binding )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for ( int i = 0; i < 256; i++ )
|
|
|
|
{
|
|
|
|
b = KEY_GetBinding( i );
|
|
|
|
if( !b ) continue;
|
|
|
|
|
|
|
|
if( !stricmp( binding, b ))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
UI_FadeAlpha
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
int UI_FadeAlpha( int starttime, int endtime )
|
|
|
|
{
|
|
|
|
int time, fade_time;
|
|
|
|
|
|
|
|
if( starttime == 0 )
|
|
|
|
{
|
|
|
|
return 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
time = ( gpGlobals->time * 1000 ) - starttime;
|
|
|
|
|
|
|
|
if( time >= endtime )
|
|
|
|
{
|
|
|
|
return 0x00FFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fade time is 1/4 of endtime
|
|
|
|
fade_time = endtime / 4;
|
|
|
|
fade_time = bound( 300, fade_time, 10000 );
|
|
|
|
|
|
|
|
int alpha;
|
|
|
|
|
|
|
|
// fade out
|
|
|
|
if(( endtime - time ) < fade_time )
|
|
|
|
alpha = bound( 0, (( endtime - time ) * 1.0f / fade_time ) * 255, 255 );
|
|
|
|
else alpha = 255;
|
|
|
|
|
|
|
|
return PackRGBA( 255, 255, 255, alpha );
|
|
|
|
}
|
|
|
|
|
|
|
|
void UI_UtilSetupPicButton( menuPicButton_s *pic, int ID )
|
|
|
|
{
|
|
|
|
if( ID < 0 || ID > PC_BUTTONCOUNT )
|
|
|
|
return; // bad id
|
|
|
|
|
|
|
|
#if 0 // too different results on various games. disabled
|
|
|
|
pic->generic.width = PicButtonWidth( ID ) * UI_BUTTON_CHARWIDTH;
|
|
|
|
#else
|
|
|
|
pic->generic.width = UI_BUTTONS_WIDTH;
|
|
|
|
#endif
|
|
|
|
pic->generic.height = UI_BUTTONS_HEIGHT;
|
|
|
|
|
|
|
|
pic->pic = uiStatic.buttonsPics[ID];
|
|
|
|
pic->button_id = ID;
|
|
|
|
|
|
|
|
if( pic->pic ) // text buttons not use it
|
|
|
|
pic->generic.flags|= QMF_ACT_ONRELEASE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_ScrollList_Init
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_ScrollList_Init( menuScrollList_s *sl )
|
|
|
|
{
|
|
|
|
if( !sl->generic.name ) sl->generic.name = "";
|
|
|
|
|
|
|
|
if( sl->generic.flags & QMF_BIGFONT )
|
|
|
|
{
|
|
|
|
sl->generic.charWidth = UI_BIG_CHAR_WIDTH;
|
|
|
|
sl->generic.charHeight = UI_BIG_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else if( sl->generic.flags & QMF_SMALLFONT )
|
|
|
|
{
|
|
|
|
sl->generic.charWidth = UI_SMALL_CHAR_WIDTH;
|
|
|
|
sl->generic.charHeight = UI_SMALL_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( sl->generic.charWidth < 1 ) sl->generic.charWidth = UI_MED_CHAR_WIDTH;
|
|
|
|
if( sl->generic.charHeight < 1 ) sl->generic.charHeight = UI_MED_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &sl->generic.charWidth, &sl->generic.charHeight );
|
|
|
|
|
|
|
|
if(!(sl->generic.flags & (QMF_LEFT_JUSTIFY|QMF_CENTER_JUSTIFY|QMF_RIGHT_JUSTIFY)))
|
|
|
|
sl->generic.flags |= QMF_LEFT_JUSTIFY;
|
|
|
|
|
|
|
|
if( !sl->generic.color ) sl->generic.color = uiPromptTextColor;
|
|
|
|
if( !sl->generic.focusColor ) sl->generic.focusColor = uiPromptFocusColor;
|
|
|
|
if( !sl->upArrow ) sl->upArrow = UI_UPARROW;
|
|
|
|
if( !sl->upArrowFocus ) sl->upArrowFocus = UI_UPARROWFOCUS;
|
|
|
|
if( !sl->downArrow ) sl->downArrow = UI_DOWNARROW;
|
|
|
|
if( !sl->downArrowFocus ) sl->downArrowFocus = UI_DOWNARROWFOCUS;
|
|
|
|
|
|
|
|
// sl->curItem = 0;
|
|
|
|
sl->topItem = 0;
|
|
|
|
sl->numItems = 0;
|
|
|
|
|
|
|
|
// count number of items
|
|
|
|
while( sl->itemNames[sl->numItems] )
|
|
|
|
sl->numItems++;
|
|
|
|
|
|
|
|
// scale the center box
|
|
|
|
sl->generic.x2 = sl->generic.x;
|
|
|
|
sl->generic.y2 = sl->generic.y;
|
|
|
|
sl->generic.width2 = sl->generic.width;
|
|
|
|
sl->generic.height2 = sl->generic.height;
|
|
|
|
UI_ScaleCoords( &sl->generic.x2, &sl->generic.y2, &sl->generic.width2, &sl->generic.height2 );
|
|
|
|
|
|
|
|
// calculate number of visible rows
|
|
|
|
sl->numRows = (sl->generic.height2 / sl->generic.charHeight) - 2;
|
|
|
|
if( sl->numRows > sl->numItems ) sl->numRows = sl->numItems;
|
|
|
|
|
|
|
|
// extend the height so it has room for the arrows
|
|
|
|
sl->generic.height += (sl->generic.width / 4);
|
|
|
|
|
|
|
|
// calculate new Y for the control
|
|
|
|
sl->generic.y -= (sl->generic.width / 8);
|
|
|
|
|
|
|
|
UI_ScaleCoords( &sl->generic.x, &sl->generic.y, &sl->generic.width, &sl->generic.height );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_ScrollList_Key
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
const char *UI_ScrollList_Key( menuScrollList_s *sl, int key, int down )
|
|
|
|
{
|
|
|
|
const char *sound = 0;
|
|
|
|
int arrowWidth, arrowHeight, upX, upY, downX, downY;
|
|
|
|
int i, y;
|
|
|
|
|
|
|
|
if( !down )
|
|
|
|
{
|
|
|
|
sl->scrollBarSliding = false;
|
|
|
|
return uiSoundNull;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch( key )
|
|
|
|
{
|
|
|
|
case K_MOUSE1:
|
|
|
|
if(!( sl->generic.flags & QMF_HASMOUSEFOCUS ))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// use fixed size for arrows
|
|
|
|
arrowWidth = 24;
|
|
|
|
arrowHeight = 24;
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &arrowWidth, &arrowHeight );
|
|
|
|
|
|
|
|
// glue with right top and right bottom corners
|
|
|
|
upX = sl->generic.x2 + sl->generic.width2 - arrowWidth;
|
|
|
|
upY = sl->generic.y2 + UI_OUTLINE_WIDTH;
|
|
|
|
downX = sl->generic.x2 + sl->generic.width2 - arrowWidth;
|
|
|
|
downY = sl->generic.y2 + (sl->generic.height2 - arrowHeight) - UI_OUTLINE_WIDTH;
|
|
|
|
|
|
|
|
// ADAMIX
|
|
|
|
if( UI_CursorInRect( sl->scrollBarX, sl->scrollBarY, sl->scrollBarWidth, sl->scrollBarHeight ))
|
|
|
|
{
|
|
|
|
sl->scrollBarSliding = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// ADAMIX END
|
|
|
|
|
|
|
|
// Now see if either up or down has focus
|
|
|
|
if( UI_CursorInRect( upX, upY, arrowWidth, arrowHeight ))
|
|
|
|
{
|
|
|
|
if( sl->curItem != 0 )
|
|
|
|
{
|
|
|
|
sl->curItem--;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if( UI_CursorInRect( downX, downY, arrowWidth, arrowHeight ))
|
|
|
|
{
|
|
|
|
if( sl->curItem != sl->numItems - 1 )
|
|
|
|
{
|
|
|
|
sl->curItem++;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// see if an item has been selected
|
|
|
|
y = sl->generic.y2 + sl->generic.charHeight;
|
|
|
|
for( i = sl->topItem; i < sl->topItem + sl->numRows; i++, y += sl->generic.charHeight )
|
|
|
|
{
|
|
|
|
if( !sl->itemNames[i] )
|
|
|
|
break; // done
|
|
|
|
|
|
|
|
if( UI_CursorInRect( sl->generic.x, y, sl->generic.width, sl->generic.charHeight ))
|
|
|
|
{
|
|
|
|
sl->curItem = i;
|
|
|
|
sound = uiSoundNull;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case K_HOME:
|
|
|
|
case K_KP_HOME:
|
|
|
|
if( sl->curItem != 0 )
|
|
|
|
{
|
|
|
|
sl->curItem = 0;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
break;
|
|
|
|
case K_END:
|
|
|
|
case K_KP_END:
|
|
|
|
if( sl->curItem != sl->numItems - 1 )
|
|
|
|
{
|
|
|
|
sl->curItem = sl->numItems - 1;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
break;
|
|
|
|
case K_PGUP:
|
|
|
|
case K_KP_PGUP:
|
|
|
|
if( sl->curItem != 0 )
|
|
|
|
{
|
|
|
|
sl->curItem -= 2;
|
|
|
|
if( sl->curItem < 0 )
|
|
|
|
sl->curItem = 0;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
break;
|
|
|
|
case K_PGDN:
|
|
|
|
case K_KP_PGDN:
|
|
|
|
if( sl->curItem != sl->numItems - 1 )
|
|
|
|
{
|
|
|
|
sl->curItem += 2;
|
|
|
|
if( sl->curItem > sl->numItems - 1 )
|
|
|
|
sl->curItem = sl->numItems - 1;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
break;
|
|
|
|
case K_UPARROW:
|
|
|
|
case K_KP_UPARROW:
|
|
|
|
case K_MWHEELUP:
|
|
|
|
if( sl->curItem != 0 )
|
|
|
|
{
|
|
|
|
sl->curItem--;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
break;
|
|
|
|
case K_DOWNARROW:
|
|
|
|
case K_MWHEELDOWN:
|
|
|
|
if( sl->numItems > 0 && sl->curItem != sl->numItems - 1 )
|
|
|
|
{
|
|
|
|
sl->curItem++;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sl->topItem = sl->curItem - sl->numRows + 1;
|
|
|
|
if( sl->topItem < 0 ) sl->topItem = 0;
|
|
|
|
if( sl->topItem > sl->numItems - sl->numRows )
|
|
|
|
sl->topItem = sl->numItems - sl->numRows;
|
|
|
|
|
|
|
|
if( sound && ( sl->generic.flags & QMF_SILENT ))
|
|
|
|
sound = uiSoundNull;
|
|
|
|
|
|
|
|
if( sound && sl->generic.callback )
|
|
|
|
{
|
|
|
|
if( sound != uiSoundBuzz )
|
|
|
|
sl->generic.callback( sl, QM_CHANGED );
|
|
|
|
}
|
|
|
|
return sound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_ScrollList_Draw
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_ScrollList_Draw( menuScrollList_s *sl )
|
|
|
|
{
|
|
|
|
int justify;
|
|
|
|
int shadow;
|
|
|
|
int i, x, y, w, h;
|
|
|
|
int selColor = 0xFF503818; // Red 80, Green 56, Blue 24, Alpha 255
|
|
|
|
int arrowWidth, arrowHeight, upX, upY, downX, downY;
|
|
|
|
int upFocus, downFocus, scrollbarFocus;
|
|
|
|
|
|
|
|
if( sl->generic.flags & QMF_LEFT_JUSTIFY )
|
|
|
|
justify = 0;
|
|
|
|
else if( sl->generic.flags & QMF_CENTER_JUSTIFY )
|
|
|
|
justify = 1;
|
|
|
|
else if( sl->generic.flags & QMF_RIGHT_JUSTIFY )
|
|
|
|
justify = 2;
|
|
|
|
|
|
|
|
shadow = (sl->generic.flags & QMF_DROPSHADOW);
|
|
|
|
|
|
|
|
// use fixed size for arrows
|
|
|
|
arrowWidth = 24;
|
|
|
|
arrowHeight = 24;
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &arrowWidth, &arrowHeight );
|
|
|
|
|
|
|
|
x = sl->generic.x2;
|
|
|
|
y = sl->generic.y2;
|
|
|
|
w = sl->generic.width2;
|
|
|
|
h = sl->generic.height2;
|
|
|
|
|
|
|
|
if( !sl->background )
|
|
|
|
{
|
|
|
|
// draw the opaque outlinebox first
|
|
|
|
UI_FillRect( x, y, w, h, uiColorBlack );
|
|
|
|
}
|
|
|
|
|
|
|
|
// hightlight the selected item
|
|
|
|
if( !( sl->generic.flags & QMF_GRAYED ))
|
|
|
|
{
|
|
|
|
y = sl->generic.y2 + sl->generic.charHeight;
|
|
|
|
for( i = sl->topItem; i < sl->topItem + sl->numRows; i++, y += sl->generic.charHeight )
|
|
|
|
{
|
|
|
|
if( !sl->itemNames[i] )
|
|
|
|
break; // Done
|
|
|
|
|
|
|
|
if( i == sl->curItem )
|
|
|
|
{
|
|
|
|
UI_FillRect( sl->generic.x, y, sl->generic.width - arrowWidth, sl->generic.charHeight, selColor );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sl->background )
|
|
|
|
{
|
|
|
|
// get size and position for the center box
|
|
|
|
UI_DrawPic( x, y, w, h, uiColorWhite, sl->background );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x = sl->generic.x2 - UI_OUTLINE_WIDTH;
|
|
|
|
y = sl->generic.y2;
|
|
|
|
w = UI_OUTLINE_WIDTH;
|
|
|
|
h = sl->generic.height2;
|
|
|
|
|
|
|
|
// draw left
|
|
|
|
UI_FillRect( x, y, w, h, uiInputFgColor );
|
|
|
|
|
|
|
|
x = sl->generic.x2 + sl->generic.width2;
|
|
|
|
y = sl->generic.y2;
|
|
|
|
w = UI_OUTLINE_WIDTH;
|
|
|
|
h = sl->generic.height2;
|
|
|
|
|
|
|
|
// draw right
|
|
|
|
UI_FillRect( x, y, w, h, uiInputFgColor );
|
|
|
|
|
|
|
|
x = sl->generic.x2;
|
|
|
|
y = sl->generic.y2;
|
|
|
|
w = sl->generic.width2 + UI_OUTLINE_WIDTH;
|
|
|
|
h = UI_OUTLINE_WIDTH;
|
|
|
|
|
|
|
|
// draw top
|
|
|
|
UI_FillRect( x, y, w, h, uiInputFgColor );
|
|
|
|
|
|
|
|
// draw bottom
|
|
|
|
x = sl->generic.x2;
|
|
|
|
y = sl->generic.y2 + sl->generic.height2 - UI_OUTLINE_WIDTH;
|
|
|
|
w = sl->generic.width2 + UI_OUTLINE_WIDTH;
|
|
|
|
h = UI_OUTLINE_WIDTH;
|
|
|
|
|
|
|
|
UI_FillRect( x, y, w, h, uiInputFgColor );
|
|
|
|
}
|
|
|
|
|
|
|
|
// glue with right top and right bottom corners
|
|
|
|
upX = sl->generic.x2 + sl->generic.width2 - arrowWidth;
|
|
|
|
upY = sl->generic.y2 + UI_OUTLINE_WIDTH;
|
|
|
|
downX = sl->generic.x2 + sl->generic.width2 - arrowWidth;
|
|
|
|
downY = sl->generic.y2 + (sl->generic.height2 - arrowHeight) - UI_OUTLINE_WIDTH;
|
|
|
|
|
|
|
|
// draw the arrows base
|
|
|
|
UI_FillRect( upX, upY + arrowHeight, arrowWidth, downY - upY - arrowHeight, uiInputFgColor );
|
|
|
|
|
|
|
|
// ADAMIX
|
|
|
|
sl->scrollBarX = upX + sl->generic.charHeight/4;
|
|
|
|
sl->scrollBarWidth = arrowWidth - sl->generic.charHeight/4;
|
|
|
|
|
|
|
|
int step = (sl->numItems <= 1 ) ? 1 : (downY - upY - arrowHeight) / (sl->numItems - 1);
|
|
|
|
|
|
|
|
if(((downY - upY - arrowHeight) - (((sl->numItems-1)*sl->generic.charHeight)/2)) < 2)
|
|
|
|
{
|
|
|
|
sl->scrollBarHeight = (downY - upY - arrowHeight) - (step * (sl->numItems-1));
|
|
|
|
sl->scrollBarY = upY + arrowHeight + (step*sl->curItem);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sl->scrollBarHeight = downY - upY - arrowHeight - (((sl->numItems-1) * sl->generic.charHeight) / 2);
|
|
|
|
sl->scrollBarY = upY + arrowHeight + (((sl->curItem) * sl->generic.charHeight)/2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sl->scrollBarSliding )
|
|
|
|
{
|
|
|
|
int dist = uiStatic.cursorY - sl->scrollBarY - (sl->scrollBarHeight>>2);
|
|
|
|
|
|
|
|
if((((dist / 2) > (sl->generic.charHeight / 2)) || ((dist / 2) < (sl->generic.charHeight / 2))) && sl->curItem <= (sl->numItems - 1) && sl->curItem >= 0)
|
|
|
|
{
|
|
|
|
if(sl->generic.callback)
|
|
|
|
sl->generic.callback( sl, QM_CHANGED );
|
|
|
|
|
|
|
|
if((dist / 2) > ( sl->generic.charHeight / 2 ) && sl->curItem < ( sl->numItems - 1 ))
|
|
|
|
{
|
|
|
|
sl->curItem++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((dist / 2) < -(sl->generic.charHeight / 2) && sl->curItem > 0 )
|
|
|
|
{
|
|
|
|
sl->curItem--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sl->topItem = sl->curItem - sl->numRows + 1;
|
|
|
|
if( sl->topItem < 0 ) sl->topItem = 0;
|
|
|
|
if( sl->topItem > ( sl->numItems - sl->numRows ))
|
|
|
|
sl->topItem = sl->numItems - sl->numRows;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sl->scrollBarSliding )
|
|
|
|
{
|
|
|
|
// Draw scrollbar background
|
|
|
|
UI_FillRect ( sl->scrollBarX, upY + arrowHeight, sl->scrollBarWidth, downY - upY - arrowHeight, uiColorBlack);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ADAMIX END
|
|
|
|
// draw the arrows
|
|
|
|
if( sl->generic.flags & QMF_GRAYED )
|
|
|
|
{
|
|
|
|
UI_DrawPic( upX, upY, arrowWidth, arrowHeight, uiColorDkGrey, sl->upArrow );
|
|
|
|
UI_DrawPic( downX, downY, arrowWidth, arrowHeight, uiColorDkGrey, sl->downArrow );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
scrollbarFocus = UI_CursorInRect( sl->scrollBarX, sl->scrollBarY, sl->scrollBarWidth, sl->scrollBarHeight );
|
|
|
|
|
|
|
|
// special case if we sliding but lost focus
|
|
|
|
if( sl->scrollBarSliding ) scrollbarFocus = true;
|
|
|
|
|
|
|
|
// Draw scrollbar itself
|
|
|
|
UI_FillRect( sl->scrollBarX, sl->scrollBarY, sl->scrollBarWidth, sl->scrollBarHeight, scrollbarFocus ? uiInputTextColor : uiColorBlack );
|
|
|
|
|
|
|
|
if((menuCommon_s *)sl != (menuCommon_s *)UI_ItemAtCursor(sl->generic.parent))
|
|
|
|
{
|
|
|
|
UI_DrawPic( upX, upY, arrowWidth, arrowHeight, uiColorWhite, sl->upArrow );
|
|
|
|
UI_DrawPic( downX, downY, arrowWidth, arrowHeight, uiColorWhite, sl->downArrow );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// see which arrow has the mouse focus
|
|
|
|
upFocus = UI_CursorInRect( upX, upY, arrowWidth, arrowHeight );
|
|
|
|
downFocus = UI_CursorInRect( downX, downY, arrowWidth, arrowHeight );
|
|
|
|
|
|
|
|
if(!( sl->generic.flags & QMF_FOCUSBEHIND ))
|
|
|
|
{
|
|
|
|
UI_DrawPic( upX, upY, arrowWidth, arrowHeight, uiColorWhite, sl->upArrow );
|
|
|
|
UI_DrawPic( downX, downY, arrowWidth, arrowHeight, uiColorWhite, sl->downArrow );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sl->generic.flags & QMF_HIGHLIGHTIFFOCUS )
|
|
|
|
{
|
|
|
|
UI_DrawPic( upX, upY, arrowWidth, arrowHeight, uiColorWhite, (upFocus) ? sl->upArrowFocus : sl->upArrow );
|
|
|
|
UI_DrawPic( downX, downY, arrowWidth, arrowHeight, uiColorWhite, (downFocus) ? sl->downArrowFocus : sl->downArrow );
|
|
|
|
}
|
|
|
|
else if( sl->generic.flags & QMF_PULSEIFFOCUS )
|
|
|
|
{
|
|
|
|
int color;
|
|
|
|
|
|
|
|
color = PackAlpha( sl->generic.color, 255 * (0.5 + 0.5 * sin( uiStatic.realTime / UI_PULSE_DIVISOR )));
|
|
|
|
|
|
|
|
UI_DrawPic( upX, upY, arrowWidth, arrowHeight, (upFocus) ? color : sl->generic.color, (upFocus) ? sl->upArrowFocus : sl->upArrow );
|
|
|
|
UI_DrawPic( downX, downY, arrowWidth, arrowHeight, (downFocus) ? color : sl->generic.color, (downFocus) ? sl->downArrowFocus : sl->downArrow );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sl->generic.flags & QMF_FOCUSBEHIND )
|
|
|
|
{
|
|
|
|
UI_DrawPic( upX, upY, arrowWidth, arrowHeight, sl->generic.color, sl->upArrow );
|
|
|
|
UI_DrawPic( downX, downY, arrowWidth, arrowHeight, sl->generic.color, sl->downArrow );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the list
|
|
|
|
x = sl->generic.x2;
|
|
|
|
w = sl->generic.width2;
|
|
|
|
h = sl->generic.charHeight;
|
|
|
|
y = sl->generic.y2 + sl->generic.charHeight;
|
|
|
|
|
|
|
|
// prevent the columns out of rectangle bounds
|
|
|
|
PIC_EnableScissor( x, y, sl->generic.width - arrowWidth - uiStatic.outlineWidth, sl->generic.height );
|
|
|
|
|
|
|
|
for( i = sl->topItem; i < sl->topItem + sl->numRows; i++, y += sl->generic.charHeight )
|
|
|
|
{
|
|
|
|
if( !sl->itemNames[i] )
|
|
|
|
break; // done
|
|
|
|
|
|
|
|
if( sl->generic.flags & QMF_GRAYED )
|
|
|
|
{
|
|
|
|
UI_DrawString( x, y, w, h, sl->itemNames[i], uiColorDkGrey, true, sl->generic.charWidth, sl->generic.charHeight, justify, shadow );
|
|
|
|
continue; // grayed
|
|
|
|
}
|
|
|
|
|
|
|
|
if( i != sl->curItem )
|
|
|
|
{
|
|
|
|
UI_DrawString( x, y, w, h, sl->itemNames[i], sl->generic.color, false, sl->generic.charWidth, sl->generic.charHeight, justify, shadow );
|
|
|
|
continue; // no focus
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!( sl->generic.flags & QMF_FOCUSBEHIND ))
|
|
|
|
UI_DrawString( x, y, w, h, sl->itemNames[i], sl->generic.color, false, sl->generic.charWidth, sl->generic.charHeight, justify, shadow );
|
|
|
|
|
|
|
|
if( sl->generic.flags & QMF_HIGHLIGHTIFFOCUS )
|
|
|
|
UI_DrawString( x, y, w, h, sl->itemNames[i], sl->generic.focusColor, false, sl->generic.charWidth, sl->generic.charHeight, justify, shadow );
|
|
|
|
else if( sl->generic.flags & QMF_PULSEIFFOCUS )
|
|
|
|
{
|
|
|
|
int color;
|
|
|
|
|
|
|
|
color = PackAlpha( sl->generic.color, 255 * (0.5 + 0.5 * sin( uiStatic.realTime / UI_PULSE_DIVISOR )));
|
|
|
|
|
|
|
|
UI_DrawString( x, y, w, h, sl->itemNames[i], color, false, sl->generic.charWidth, sl->generic.charHeight, justify, shadow );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sl->generic.flags & QMF_FOCUSBEHIND )
|
|
|
|
UI_DrawString( x, y, w, h, sl->itemNames[i], sl->generic.color, false, sl->generic.charWidth, sl->generic.charHeight, justify, shadow );
|
|
|
|
}
|
|
|
|
|
|
|
|
PIC_DisableScissor();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_SpinControl_Init
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_SpinControl_Init( menuSpinControl_s *sc )
|
|
|
|
{
|
|
|
|
if( !sc->generic.name ) sc->generic.name = ""; // this is also the text displayed
|
|
|
|
|
|
|
|
if( sc->generic.flags & QMF_BIGFONT )
|
|
|
|
{
|
|
|
|
sc->generic.charWidth = UI_BIG_CHAR_WIDTH;
|
|
|
|
sc->generic.charHeight = UI_BIG_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else if( sc->generic.flags & QMF_SMALLFONT )
|
|
|
|
{
|
|
|
|
sc->generic.charWidth = UI_SMALL_CHAR_WIDTH;
|
|
|
|
sc->generic.charHeight = UI_SMALL_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( sc->generic.charWidth < 1 ) sc->generic.charWidth = UI_MED_CHAR_WIDTH;
|
|
|
|
if( sc->generic.charHeight < 1 ) sc->generic.charHeight = UI_MED_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &sc->generic.charWidth, &sc->generic.charHeight );
|
|
|
|
|
|
|
|
if(!( sc->generic.flags & (QMF_LEFT_JUSTIFY|QMF_CENTER_JUSTIFY|QMF_RIGHT_JUSTIFY)))
|
|
|
|
sc->generic.flags |= QMF_LEFT_JUSTIFY;
|
|
|
|
|
|
|
|
if( !sc->generic.color ) sc->generic.color = uiColorHelp;
|
|
|
|
if( !sc->generic.focusColor ) sc->generic.focusColor = uiPromptTextColor;
|
|
|
|
if( !sc->leftArrow ) sc->leftArrow = UI_LEFTARROW;
|
|
|
|
if( !sc->leftArrowFocus ) sc->leftArrowFocus = UI_LEFTARROWFOCUS;
|
|
|
|
if( !sc->rightArrow ) sc->rightArrow = UI_RIGHTARROW;
|
|
|
|
if( !sc->rightArrowFocus ) sc->rightArrowFocus = UI_RIGHTARROWFOCUS;
|
|
|
|
|
|
|
|
// scale the center box
|
|
|
|
sc->generic.x2 = sc->generic.x;
|
|
|
|
sc->generic.y2 = sc->generic.y;
|
|
|
|
sc->generic.width2 = sc->generic.width;
|
|
|
|
sc->generic.height2 = sc->generic.height;
|
|
|
|
UI_ScaleCoords( &sc->generic.x2, &sc->generic.y2, &sc->generic.width2, &sc->generic.height2 );
|
|
|
|
|
|
|
|
// extend the width so it has room for the arrows
|
|
|
|
sc->generic.width += (sc->generic.height * 3);
|
|
|
|
|
|
|
|
// calculate new X for the control
|
|
|
|
sc->generic.x -= (sc->generic.height + (sc->generic.height/2));
|
|
|
|
|
|
|
|
UI_ScaleCoords( &sc->generic.x, &sc->generic.y, &sc->generic.width, &sc->generic.height );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_SpinControl_Key
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
const char *UI_SpinControl_Key( menuSpinControl_s *sc, int key, int down )
|
|
|
|
{
|
|
|
|
const char *sound = 0;
|
|
|
|
int arrowWidth, arrowHeight, leftX, leftY, rightX, rightY;
|
|
|
|
|
|
|
|
if( !down ) return uiSoundNull;
|
|
|
|
|
|
|
|
switch( key )
|
|
|
|
{
|
|
|
|
case K_MOUSE1:
|
|
|
|
case K_MOUSE2:
|
|
|
|
if( !( sc->generic.flags & QMF_HASMOUSEFOCUS ))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// calculate size and position for the arrows
|
|
|
|
arrowWidth = sc->generic.height + (UI_OUTLINE_WIDTH * 2);
|
|
|
|
arrowHeight = sc->generic.height + (UI_OUTLINE_WIDTH * 2);
|
|
|
|
|
|
|
|
leftX = sc->generic.x + UI_OUTLINE_WIDTH;
|
|
|
|
leftY = sc->generic.y - UI_OUTLINE_WIDTH;
|
|
|
|
rightX = sc->generic.x + (sc->generic.width - arrowWidth) - UI_OUTLINE_WIDTH;
|
|
|
|
rightY = sc->generic.y - UI_OUTLINE_WIDTH;
|
|
|
|
|
|
|
|
// now see if either left or right arrow has focus
|
|
|
|
if( UI_CursorInRect( leftX, leftY, arrowWidth, arrowHeight ))
|
|
|
|
{
|
|
|
|
if( sc->curValue > sc->minValue )
|
|
|
|
{
|
|
|
|
sc->curValue -= sc->range;
|
|
|
|
if( sc->curValue < sc->minValue )
|
|
|
|
sc->curValue = sc->minValue;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
}
|
|
|
|
else if( UI_CursorInRect( rightX, rightY, arrowWidth, arrowHeight ))
|
|
|
|
{
|
|
|
|
if( sc->curValue < sc->maxValue )
|
|
|
|
{
|
|
|
|
sc->curValue += sc->range;
|
|
|
|
if( sc->curValue > sc->maxValue )
|
|
|
|
sc->curValue = sc->maxValue;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case K_LEFTARROW:
|
|
|
|
case K_KP_LEFTARROW:
|
|
|
|
if( sc->generic.flags & QMF_MOUSEONLY )
|
|
|
|
break;
|
|
|
|
if( sc->curValue > sc->minValue )
|
|
|
|
{
|
|
|
|
sc->curValue -= sc->range;
|
|
|
|
if( sc->curValue < sc->minValue )
|
|
|
|
sc->curValue = sc->minValue;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
break;
|
|
|
|
case K_RIGHTARROW:
|
|
|
|
case K_KP_RIGHTARROW:
|
|
|
|
if( sc->generic.flags & QMF_MOUSEONLY )
|
|
|
|
break;
|
|
|
|
|
|
|
|
if( sc->curValue < sc->maxValue )
|
|
|
|
{
|
|
|
|
sc->curValue += sc->range;
|
|
|
|
if( sc->curValue > sc->maxValue )
|
|
|
|
sc->curValue = sc->maxValue;
|
|
|
|
sound = uiSoundMove;
|
|
|
|
}
|
|
|
|
else sound = uiSoundBuzz;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sound && ( sc->generic.flags & QMF_SILENT ))
|
|
|
|
sound = uiSoundNull;
|
|
|
|
|
|
|
|
if( sound && sc->generic.callback )
|
|
|
|
{
|
|
|
|
if( sound != uiSoundBuzz )
|
|
|
|
sc->generic.callback( sc, QM_CHANGED );
|
|
|
|
}
|
|
|
|
return sound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_SpinControl_Draw
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_SpinControl_Draw( menuSpinControl_s *sc )
|
|
|
|
{
|
|
|
|
int justify;
|
|
|
|
int shadow;
|
|
|
|
int x, y, w, h;
|
|
|
|
int arrowWidth, arrowHeight, leftX, leftY, rightX, rightY;
|
|
|
|
int leftFocus, rightFocus;
|
|
|
|
|
|
|
|
if( sc->generic.flags & QMF_LEFT_JUSTIFY )
|
|
|
|
justify = 0;
|
|
|
|
else if( sc->generic.flags & QMF_CENTER_JUSTIFY )
|
|
|
|
justify = 1;
|
|
|
|
else if( sc->generic.flags & QMF_RIGHT_JUSTIFY )
|
|
|
|
justify = 2;
|
|
|
|
|
|
|
|
shadow = (sc->generic.flags & QMF_DROPSHADOW);
|
|
|
|
|
|
|
|
// calculate size and position for the arrows
|
|
|
|
arrowWidth = sc->generic.height + (UI_OUTLINE_WIDTH * 2);
|
|
|
|
arrowHeight = sc->generic.height + (UI_OUTLINE_WIDTH * 2);
|
|
|
|
|
|
|
|
leftX = sc->generic.x + UI_OUTLINE_WIDTH;
|
|
|
|
leftY = sc->generic.y - UI_OUTLINE_WIDTH;
|
|
|
|
rightX = sc->generic.x + (sc->generic.width - arrowWidth) - UI_OUTLINE_WIDTH;
|
|
|
|
rightY = sc->generic.y - UI_OUTLINE_WIDTH;
|
|
|
|
|
|
|
|
// get size and position for the center box
|
|
|
|
w = sc->generic.width2;
|
|
|
|
h = sc->generic.height2;
|
|
|
|
x = sc->generic.x2;
|
|
|
|
y = sc->generic.y2;
|
|
|
|
|
|
|
|
if( sc->background )
|
|
|
|
{
|
|
|
|
UI_DrawPic( x, y, w, h, uiColorWhite, sc->background );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// draw the background
|
|
|
|
UI_FillRect( x, y, w, h, uiColorBlack );
|
|
|
|
|
|
|
|
// draw the rectangle
|
|
|
|
UI_DrawRectangle( x, y, w, h, uiInputFgColor );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sc->generic.flags & QMF_GRAYED )
|
|
|
|
{
|
|
|
|
UI_DrawString( x, y, w, h, sc->generic.name, uiColorDkGrey, true, sc->generic.charWidth, sc->generic.charHeight, justify, shadow );
|
|
|
|
UI_DrawPic( leftX, leftY, arrowWidth, arrowHeight, uiColorDkGrey, sc->leftArrow );
|
|
|
|
UI_DrawPic( rightX, rightY, arrowWidth, arrowHeight, uiColorDkGrey, sc->rightArrow );
|
|
|
|
return; // grayed
|
|
|
|
}
|
|
|
|
|
|
|
|
if((menuCommon_s *)sc != (menuCommon_s *)UI_ItemAtCursor(sc->generic.parent ))
|
|
|
|
{
|
|
|
|
UI_DrawString(x, y, w, h, sc->generic.name, sc->generic.color, false, sc->generic.charWidth, sc->generic.charHeight, justify, shadow );
|
|
|
|
UI_DrawPic(leftX, leftY, arrowWidth, arrowHeight, sc->generic.color, sc->leftArrow);
|
|
|
|
UI_DrawPic(rightX, rightY, arrowWidth, arrowHeight, sc->generic.color, sc->rightArrow);
|
|
|
|
return; // No focus
|
|
|
|
}
|
|
|
|
|
|
|
|
// see which arrow has the mouse focus
|
|
|
|
leftFocus = UI_CursorInRect( leftX, leftY, arrowWidth, arrowHeight );
|
|
|
|
rightFocus = UI_CursorInRect( rightX, rightY, arrowWidth, arrowHeight );
|
|
|
|
|
|
|
|
if( !( sc->generic.flags & QMF_FOCUSBEHIND ))
|
|
|
|
{
|
|
|
|
UI_DrawString( x, y, w, h, sc->generic.name, sc->generic.color, false, sc->generic.charWidth, sc->generic.charHeight, justify, shadow );
|
|
|
|
UI_DrawPic( leftX, leftY, arrowWidth, arrowHeight, sc->generic.color, sc->leftArrow );
|
|
|
|
UI_DrawPic( rightX, rightY, arrowWidth, arrowHeight, sc->generic.color, sc->rightArrow );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sc->generic.flags & QMF_HIGHLIGHTIFFOCUS )
|
|
|
|
{
|
|
|
|
UI_DrawString( x, y, w, h, sc->generic.name, sc->generic.focusColor, false, sc->generic.charWidth, sc->generic.charHeight, justify, shadow );
|
|
|
|
UI_DrawPic( leftX, leftY, arrowWidth, arrowHeight, (leftFocus) ? sc->generic.color : sc->generic.color, (leftFocus) ? sc->leftArrowFocus : sc->leftArrow );
|
|
|
|
UI_DrawPic( rightX, rightY, arrowWidth, arrowHeight, (rightFocus) ? sc->generic.color : sc->generic.color, (rightFocus) ? sc->rightArrowFocus : sc->rightArrow );
|
|
|
|
}
|
|
|
|
else if( sc->generic.flags & QMF_PULSEIFFOCUS )
|
|
|
|
{
|
|
|
|
int color;
|
|
|
|
|
|
|
|
color = PackAlpha( sc->generic.color, 255 * (0.5 + 0.5 * sin( uiStatic.realTime / UI_PULSE_DIVISOR )));
|
|
|
|
|
|
|
|
UI_DrawString( x, y, w, h, sc->generic.name, color, false, sc->generic.charWidth, sc->generic.charHeight, justify, shadow );
|
|
|
|
UI_DrawPic( leftX, leftY, arrowWidth, arrowHeight, (leftFocus) ? color : sc->generic.color, (leftFocus) ? sc->leftArrowFocus : sc->leftArrow );
|
|
|
|
UI_DrawPic( rightX, rightY, arrowWidth, arrowHeight, (rightFocus) ? color : sc->generic.color, (rightFocus) ? sc->rightArrowFocus : sc->rightArrow );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sc->generic.flags & QMF_FOCUSBEHIND )
|
|
|
|
{
|
|
|
|
UI_DrawString( x, y, w, h, sc->generic.name, sc->generic.color, false, sc->generic.charWidth, sc->generic.charHeight, justify, shadow );
|
|
|
|
UI_DrawPic( leftX, leftY, arrowWidth, arrowHeight, sc->generic.color, sc->leftArrow );
|
|
|
|
UI_DrawPic( rightX, rightY, arrowWidth, arrowHeight, sc->generic.color, sc->rightArrow );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Slider_Init
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_Slider_Init( menuSlider_s *sl )
|
|
|
|
{
|
|
|
|
if( !sl->generic.name ) sl->generic.name = ""; // this is also the text displayed
|
|
|
|
|
|
|
|
if( !sl->generic.width ) sl->generic.width = 200;
|
|
|
|
if( !sl->generic.height) sl->generic.height = 4;
|
|
|
|
if( !sl->generic.color ) sl->generic.color = uiColorWhite;
|
|
|
|
if( !sl->generic.focusColor ) sl->generic.focusColor = uiColorWhite;
|
|
|
|
if( !sl->range ) sl->range = 1.0f;
|
|
|
|
if( sl->range < 0.05f ) sl->range = 0.05f;
|
|
|
|
|
|
|
|
if( sl->generic.flags & QMF_BIGFONT )
|
|
|
|
{
|
|
|
|
sl->generic.charWidth = UI_BIG_CHAR_WIDTH;
|
|
|
|
sl->generic.charHeight = UI_BIG_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else if( sl->generic.flags & QMF_SMALLFONT )
|
|
|
|
{
|
|
|
|
sl->generic.charWidth = UI_SMALL_CHAR_WIDTH;
|
|
|
|
sl->generic.charHeight = UI_SMALL_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( sl->generic.charWidth < 1 ) sl->generic.charWidth = 12;
|
|
|
|
if( sl->generic.charHeight < 1 ) sl->generic.charHeight = 24;
|
|
|
|
}
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &sl->generic.charWidth, &sl->generic.charHeight );
|
|
|
|
|
|
|
|
if(!(sl->generic.flags & (QMF_LEFT_JUSTIFY|QMF_CENTER_JUSTIFY|QMF_RIGHT_JUSTIFY)))
|
|
|
|
sl->generic.flags |= QMF_LEFT_JUSTIFY;
|
|
|
|
|
|
|
|
// scale the center box
|
|
|
|
sl->generic.x2 = sl->generic.x;
|
|
|
|
sl->generic.y2 = sl->generic.y;
|
|
|
|
sl->generic.width2 = sl->generic.width / 5;
|
|
|
|
sl->generic.height2 = 4;
|
|
|
|
|
|
|
|
UI_ScaleCoords( &sl->generic.x2, &sl->generic.y2, &sl->generic.width2, &sl->generic.height2 );
|
|
|
|
UI_ScaleCoords( &sl->generic.x, &sl->generic.y, &sl->generic.width, &sl->generic.height );
|
|
|
|
|
|
|
|
sl->generic.y -= uiStatic.sliderWidth;
|
|
|
|
sl->generic.height += uiStatic.sliderWidth * 2;
|
|
|
|
sl->generic.y2 -= uiStatic.sliderWidth;
|
|
|
|
|
|
|
|
sl->drawStep = (sl->generic.width - sl->generic.width2) / ((sl->maxValue - sl->minValue) / sl->range);
|
|
|
|
sl->numSteps = ((sl->maxValue - sl->minValue) / sl->range) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Slider_Key
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
const char *UI_Slider_Key( menuSlider_s *sl, int key, int down )
|
|
|
|
{
|
|
|
|
int sliderX;
|
|
|
|
|
|
|
|
if( !down )
|
|
|
|
{
|
|
|
|
if( sl->keepSlider )
|
|
|
|
{
|
|
|
|
// tell menu about changes
|
|
|
|
if( sl->generic.callback )
|
|
|
|
sl->generic.callback( sl, QM_CHANGED );
|
|
|
|
sl->keepSlider = false; // button released
|
|
|
|
}
|
|
|
|
return uiSoundNull;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch( key )
|
|
|
|
{
|
|
|
|
case K_MOUSE1:
|
|
|
|
if(!( sl->generic.flags & QMF_HASMOUSEFOCUS ))
|
|
|
|
return uiSoundNull;
|
|
|
|
|
|
|
|
// find the current slider position
|
|
|
|
sliderX = sl->generic.x2 + (sl->drawStep * (sl->curValue * sl->numSteps));
|
|
|
|
if( UI_CursorInRect( sliderX, sl->generic.y2, sl->generic.width2, sl->generic.height ))
|
|
|
|
{
|
|
|
|
sl->keepSlider = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int dist, numSteps;
|
|
|
|
|
|
|
|
// immediately move slider into specified place
|
|
|
|
dist = uiStatic.cursorX - sl->generic.x2 - (sl->generic.width2>>2);
|
|
|
|
numSteps = dist / (int)sl->drawStep;
|
|
|
|
sl->curValue = bound( sl->minValue, numSteps * sl->range, sl->maxValue );
|
|
|
|
|
|
|
|
// tell menu about changes
|
|
|
|
if( sl->generic.callback )
|
|
|
|
sl->generic.callback( sl, QM_CHANGED );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return uiSoundNull;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Slider_Draw
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_Slider_Draw( menuSlider_s *sl )
|
|
|
|
{
|
|
|
|
int justify;
|
|
|
|
int shadow;
|
|
|
|
int textHeight, sliderX;
|
|
|
|
|
|
|
|
if( sl->generic.flags & QMF_LEFT_JUSTIFY )
|
|
|
|
justify = 0;
|
|
|
|
else if( sl->generic.flags & QMF_CENTER_JUSTIFY )
|
|
|
|
justify = 1;
|
|
|
|
else if( sl->generic.flags & QMF_RIGHT_JUSTIFY )
|
|
|
|
justify = 2;
|
|
|
|
|
|
|
|
shadow = (sl->generic.flags & QMF_DROPSHADOW);
|
|
|
|
|
|
|
|
if( sl->keepSlider )
|
|
|
|
{
|
|
|
|
int dist, numSteps;
|
|
|
|
|
|
|
|
// move slider follow the holded mouse button
|
|
|
|
dist = uiStatic.cursorX - sl->generic.x2 - (sl->generic.width2>>2);
|
|
|
|
numSteps = dist / (int)sl->drawStep;
|
|
|
|
sl->curValue = bound( sl->minValue, numSteps * sl->range, sl->maxValue );
|
|
|
|
|
|
|
|
// tell menu about changes
|
|
|
|
if( sl->generic.callback ) sl->generic.callback( sl, QM_CHANGED );
|
|
|
|
}
|
|
|
|
|
|
|
|
// keep value in range
|
|
|
|
sl->curValue = bound( sl->minValue, sl->curValue, sl->maxValue );
|
|
|
|
|
|
|
|
// calc slider position
|
|
|
|
sliderX = sl->generic.x2 + (sl->drawStep * (sl->curValue * sl->numSteps));
|
|
|
|
|
|
|
|
UI_DrawRectangleExt( sl->generic.x, sl->generic.y + uiStatic.sliderWidth, sl->generic.width, sl->generic.height2, uiInputBgColor, uiStatic.sliderWidth );
|
|
|
|
UI_DrawPic( sliderX, sl->generic.y2, sl->generic.width2, sl->generic.height, uiColorWhite, UI_SLIDER_MAIN );
|
|
|
|
|
|
|
|
textHeight = sl->generic.y - (sl->generic.charHeight * 1.5f);
|
|
|
|
UI_DrawString( sl->generic.x, textHeight, sl->generic.width, sl->generic.charHeight, sl->generic.name, uiColorHelp, true, sl->generic.charWidth, sl->generic.charHeight, justify, shadow );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_CheckBox_Init
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_CheckBox_Init( menuCheckBox_s *cb )
|
|
|
|
{
|
|
|
|
if( !cb->generic.name ) cb->generic.name = "";
|
|
|
|
|
|
|
|
if( cb->generic.flags & QMF_BIGFONT )
|
|
|
|
{
|
|
|
|
cb->generic.charWidth = UI_BIG_CHAR_WIDTH;
|
|
|
|
cb->generic.charHeight = UI_BIG_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else if( cb->generic.flags & QMF_SMALLFONT )
|
|
|
|
{
|
|
|
|
cb->generic.charWidth = UI_SMALL_CHAR_WIDTH;
|
|
|
|
cb->generic.charHeight = UI_SMALL_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( cb->generic.charWidth < 1 ) cb->generic.charWidth = 12;
|
|
|
|
if( cb->generic.charHeight < 1 ) cb->generic.charHeight = 24;
|
|
|
|
}
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &cb->generic.charWidth, &cb->generic.charHeight );
|
|
|
|
|
|
|
|
if(!(cb->generic.flags & (QMF_LEFT_JUSTIFY|QMF_CENTER_JUSTIFY|QMF_RIGHT_JUSTIFY)))
|
|
|
|
cb->generic.flags |= QMF_LEFT_JUSTIFY;
|
|
|
|
|
|
|
|
if( !cb->emptyPic ) cb->emptyPic = UI_CHECKBOX_EMPTY;
|
|
|
|
if( !cb->focusPic ) cb->focusPic = UI_CHECKBOX_FOCUS;
|
|
|
|
if( !cb->checkPic ) cb->checkPic = UI_CHECKBOX_ENABLED;
|
|
|
|
if( !cb->grayedPic ) cb->grayedPic = UI_CHECKBOX_GRAYED;
|
|
|
|
if( !cb->generic.color ) cb->generic.color = uiColorWhite;
|
|
|
|
if( !cb->generic.focusColor ) cb->generic.focusColor = uiColorWhite;
|
|
|
|
|
|
|
|
if( !cb->generic.width ) cb->generic.width = 32;
|
|
|
|
if( !cb->generic.height ) cb->generic.height = 32;
|
|
|
|
|
|
|
|
UI_ScaleCoords( &cb->generic.x, &cb->generic.y, &cb->generic.width, &cb->generic.height );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_CheckBox_Key
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
const char *UI_CheckBox_Key( menuCheckBox_s *cb, int key, int down )
|
|
|
|
{
|
|
|
|
const char *sound = 0;
|
|
|
|
|
|
|
|
switch( key )
|
|
|
|
{
|
|
|
|
case K_MOUSE1:
|
|
|
|
if(!( cb->generic.flags & QMF_HASMOUSEFOCUS ))
|
|
|
|
break;
|
|
|
|
sound = uiSoundGlow;
|
|
|
|
break;
|
|
|
|
case K_ENTER:
|
|
|
|
case K_KP_ENTER:
|
|
|
|
if( !down ) return sound;
|
|
|
|
if( cb->generic.flags & QMF_MOUSEONLY )
|
|
|
|
break;
|
|
|
|
sound = uiSoundGlow;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( sound && ( cb->generic.flags & QMF_SILENT ))
|
|
|
|
sound = uiSoundNull;
|
|
|
|
|
|
|
|
if( cb->generic.flags & QMF_ACT_ONRELEASE )
|
|
|
|
{
|
|
|
|
if( sound && cb->generic.callback )
|
|
|
|
{
|
|
|
|
int event;
|
|
|
|
|
|
|
|
if( down )
|
|
|
|
{
|
|
|
|
event = QM_PRESSED;
|
|
|
|
cb->generic.bPressed = true;
|
|
|
|
}
|
|
|
|
else event = QM_CHANGED;
|
|
|
|
if( !down ) cb->enabled = !cb->enabled; // apply on release
|
|
|
|
cb->generic.callback( cb, event );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( down )
|
|
|
|
{
|
|
|
|
if( sound && cb->generic.callback )
|
|
|
|
{
|
|
|
|
cb->enabled = !cb->enabled;
|
|
|
|
cb->generic.callback( cb, QM_CHANGED );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_CheckBox_Draw
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_CheckBox_Draw( menuCheckBox_s *cb )
|
|
|
|
{
|
|
|
|
int justify;
|
|
|
|
int shadow;
|
|
|
|
int textOffset, y;
|
|
|
|
|
|
|
|
if( cb->generic.flags & QMF_LEFT_JUSTIFY )
|
|
|
|
justify = 0;
|
|
|
|
else if( cb->generic.flags & QMF_CENTER_JUSTIFY )
|
|
|
|
justify = 1;
|
|
|
|
else if( cb->generic.flags & QMF_RIGHT_JUSTIFY )
|
|
|
|
justify = 2;
|
|
|
|
|
|
|
|
shadow = (cb->generic.flags & QMF_DROPSHADOW);
|
|
|
|
|
|
|
|
y = cb->generic.y + (cb->generic.height>>2);
|
|
|
|
textOffset = cb->generic.x + (cb->generic.width * 1.7f);
|
|
|
|
UI_DrawString( textOffset, y, strlen( cb->generic.name ) * cb->generic.charWidth, cb->generic.charHeight, cb->generic.name, uiColorHelp, true, cb->generic.charWidth, cb->generic.charHeight, justify, shadow );
|
|
|
|
|
|
|
|
if( cb->generic.statusText && cb->generic.flags & QMF_NOTIFY )
|
|
|
|
{
|
|
|
|
int charW, charH;
|
|
|
|
int x, w;
|
|
|
|
|
|
|
|
charW = UI_SMALL_CHAR_WIDTH;
|
|
|
|
charH = UI_SMALL_CHAR_HEIGHT;
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &charW, &charH );
|
|
|
|
|
|
|
|
x = 250;
|
|
|
|
w = UI_SMALL_CHAR_WIDTH * strlen( cb->generic.statusText );
|
|
|
|
UI_ScaleCoords( &x, NULL, &w, NULL );
|
|
|
|
x += cb->generic.x;
|
|
|
|
|
|
|
|
int r, g, b;
|
|
|
|
|
|
|
|
UnpackRGB( r, g, b, uiColorHelp );
|
|
|
|
TextMessageSetColor( r, g, b );
|
|
|
|
DrawConsoleString( x, cb->generic.y, cb->generic.statusText );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( cb->generic.flags & QMF_GRAYED )
|
|
|
|
{
|
|
|
|
UI_DrawPic( cb->generic.x, cb->generic.y, cb->generic.width, cb->generic.height, uiColorWhite, cb->grayedPic );
|
|
|
|
return; // grayed
|
|
|
|
}
|
|
|
|
|
|
|
|
if(( cb->generic.flags & QMF_MOUSEONLY ) && !( cb->generic.flags & QMF_HASMOUSEFOCUS ))
|
|
|
|
{
|
|
|
|
if( !cb->enabled )
|
|
|
|
UI_DrawPic( cb->generic.x, cb->generic.y, cb->generic.width, cb->generic.height, cb->generic.color, cb->emptyPic );
|
|
|
|
else UI_DrawPic( cb->generic.x, cb->generic.y, cb->generic.width, cb->generic.height, cb->generic.color, cb->checkPic );
|
|
|
|
return; // no focus
|
|
|
|
}
|
|
|
|
|
|
|
|
if((menuCommon_s *)cb != (menuCommon_s *)UI_ItemAtCursor( cb->generic.parent ))
|
|
|
|
{
|
|
|
|
if( !cb->enabled )
|
|
|
|
UI_DrawPic( cb->generic.x, cb->generic.y, cb->generic.width, cb->generic.height, cb->generic.color, cb->emptyPic );
|
|
|
|
else UI_DrawPic( cb->generic.x, cb->generic.y, cb->generic.width, cb->generic.height, cb->generic.color, cb->checkPic );
|
|
|
|
return; // no focus
|
|
|
|
}
|
|
|
|
|
|
|
|
if( cb->generic.flags & QMF_HIGHLIGHTIFFOCUS && !cb->enabled )
|
|
|
|
{
|
|
|
|
UI_DrawPic( cb->generic.x, cb->generic.y, cb->generic.width, cb->generic.height, cb->generic.focusColor, cb->focusPic );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( !cb->enabled )
|
|
|
|
UI_DrawPic( cb->generic.x, cb->generic.y, cb->generic.width, cb->generic.height, cb->generic.color, cb->emptyPic );
|
|
|
|
else UI_DrawPic( cb->generic.x, cb->generic.y, cb->generic.width, cb->generic.height, cb->generic.color, cb->checkPic );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Field_Init
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_Field_Init( menuField_s *f )
|
|
|
|
{
|
|
|
|
if( !f->generic.name ) f->generic.name = "";
|
|
|
|
|
|
|
|
if( f->generic.flags & QMF_BIGFONT )
|
|
|
|
{
|
|
|
|
f->generic.charWidth = UI_BIG_CHAR_WIDTH;
|
|
|
|
f->generic.charHeight = UI_BIG_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else if( f->generic.flags & QMF_SMALLFONT )
|
|
|
|
{
|
|
|
|
f->generic.charWidth = UI_SMALL_CHAR_WIDTH;
|
|
|
|
f->generic.charHeight = UI_SMALL_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( f->generic.charWidth < 1 ) f->generic.charWidth = UI_MED_CHAR_WIDTH;
|
|
|
|
if( f->generic.charHeight < 1 ) f->generic.charHeight = UI_MED_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &f->generic.charWidth, &f->generic.charHeight );
|
|
|
|
|
|
|
|
if( !(f->generic.flags & (QMF_LEFT_JUSTIFY|QMF_CENTER_JUSTIFY|QMF_RIGHT_JUSTIFY)))
|
|
|
|
f->generic.flags |= QMF_LEFT_JUSTIFY;
|
|
|
|
|
|
|
|
if( !f->generic.color ) f->generic.color = uiInputTextColor;
|
|
|
|
if( !f->generic.focusColor ) f->generic.focusColor = uiInputTextColor;
|
|
|
|
|
|
|
|
f->maxLength++;
|
|
|
|
if( f->maxLength <= 1 || f->maxLength >= UI_MAX_FIELD_LINE )
|
|
|
|
f->maxLength = UI_MAX_FIELD_LINE - 1;
|
|
|
|
|
|
|
|
UI_ScaleCoords( &f->generic.x, &f->generic.y, &f->generic.width, &f->generic.height );
|
|
|
|
|
|
|
|
// calculate number of visible characters
|
|
|
|
f->widthInChars = (f->generic.width / f->generic.charWidth);
|
|
|
|
|
|
|
|
f->cursor = strlen( f->buffer );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
UI_Field_Paste
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void UI_Field_Paste( void )
|
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
int pasteLen, i;
|
|
|
|
|
|
|
|
str = GET_CLIPBOARD ();
|
|
|
|
if( !str ) return;
|
|
|
|
|
|
|
|
// send as if typed, so insert / overstrike works properly
|
|
|
|
pasteLen = strlen( str );
|
|
|
|
for( i = 0; i < pasteLen; i++ )
|
|
|
|
UI_CharEvent( str[i] );
|
|
|
|
FREE( str );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
UI_Field_Clear
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void UI_Field_Clear( menuField_s *f )
|
|
|
|
{
|
|
|
|
memset( f->buffer, 0, UI_MAX_FIELD_LINE );
|
|
|
|
f->cursor = 0;
|
|
|
|
f->scroll = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Field_Key
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
const char *UI_Field_Key( menuField_s *f, int key, int down )
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if( !down ) return 0;
|
|
|
|
|
|
|
|
// clipboard paste
|
|
|
|
if((( key == K_INS ) || ( key == K_KP_INS )) && KEY_IsDown( K_SHIFT ))
|
|
|
|
{
|
|
|
|
UI_Field_Paste();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen( f->buffer );
|
|
|
|
|
|
|
|
if( key == K_INS )
|
|
|
|
{
|
|
|
|
// toggle overstrike mode
|
|
|
|
KEY_SetOverstrike( !KEY_GetOverstrike( ));
|
|
|
|
return uiSoundNull; // handled
|
|
|
|
}
|
|
|
|
|
|
|
|
// previous character
|
|
|
|
if( key == K_LEFTARROW )
|
|
|
|
{
|
|
|
|
if( f->cursor > 0 ) f->cursor--;
|
|
|
|
if( f->cursor < f->scroll ) f->scroll--;
|
|
|
|
return uiSoundNull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// next character
|
|
|
|
if( key == K_RIGHTARROW )
|
|
|
|
{
|
|
|
|
if( f->cursor < len ) f->cursor++;
|
|
|
|
if( f->cursor >= f->scroll + f->widthInChars && f->cursor <= len )
|
|
|
|
f->scroll++;
|
|
|
|
return uiSoundNull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// first character
|
|
|
|
if( key == K_HOME )
|
|
|
|
{
|
|
|
|
f->cursor = 0;
|
|
|
|
return uiSoundNull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// last character
|
|
|
|
if( key == K_END )
|
|
|
|
{
|
|
|
|
f->cursor = len;
|
|
|
|
return uiSoundNull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( key == K_BACKSPACE )
|
|
|
|
{
|
|
|
|
if( f->cursor > 0 )
|
|
|
|
{
|
|
|
|
memmove( f->buffer + f->cursor - 1, f->buffer + f->cursor, len - f->cursor + 1 );
|
|
|
|
f->cursor--;
|
|
|
|
if( f->scroll ) f->scroll--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( key == K_DEL )
|
|
|
|
{
|
|
|
|
if( f->cursor < len )
|
|
|
|
memmove( f->buffer + f->cursor, f->buffer + f->cursor + 1, len - f->cursor );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( f->generic.callback )
|
|
|
|
f->generic.callback( f, QM_CHANGED );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Field_Char
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_Field_Char( menuField_s *f, int key )
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if( key == 'v' - 'a' + 1 )
|
|
|
|
{
|
|
|
|
// ctrl-v is paste
|
|
|
|
UI_Field_Paste();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( key == 'c' - 'a' + 1 )
|
|
|
|
{
|
|
|
|
// ctrl-c clears the field
|
|
|
|
UI_Field_Clear( f );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen( f->buffer );
|
|
|
|
|
|
|
|
if( key == 'a' - 'a' + 1 )
|
|
|
|
{
|
|
|
|
// ctrl-a is home
|
|
|
|
f->cursor = 0;
|
|
|
|
f->scroll = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( key == 'e' - 'a' + 1 )
|
|
|
|
{
|
|
|
|
// ctrl-e is end
|
|
|
|
f->cursor = len;
|
|
|
|
f->scroll = f->cursor - f->widthInChars;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ignore any other non printable chars
|
|
|
|
if( key < 32 ) return;
|
|
|
|
|
|
|
|
if( key == '^' && !( f->generic.flags & QMF_ALLOW_COLORSTRINGS ))
|
|
|
|
{
|
|
|
|
// ignore color key-symbol
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( f->generic.flags & QMF_NUMBERSONLY )
|
|
|
|
{
|
|
|
|
if( key < '0' || key > '9' )
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( f->generic.flags & QMF_LOWERCASE )
|
|
|
|
key = tolower( key );
|
|
|
|
else if( f->generic.flags & QMF_UPPERCASE )
|
|
|
|
key = toupper( key );
|
|
|
|
|
|
|
|
if( KEY_GetOverstrike( ))
|
|
|
|
{
|
|
|
|
if( f->cursor == f->maxLength - 1 ) return;
|
|
|
|
f->buffer[f->cursor] = key;
|
|
|
|
f->cursor++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// insert mode
|
|
|
|
if( len == f->maxLength - 1 ) return; // all full
|
|
|
|
memmove( f->buffer + f->cursor + 1, f->buffer + f->cursor, len + 1 - f->cursor );
|
|
|
|
f->buffer[f->cursor] = key;
|
|
|
|
f->cursor++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( f->cursor >= f->widthInChars ) f->scroll++;
|
|
|
|
if( f->cursor == len + 1 ) f->buffer[f->cursor] = 0;
|
|
|
|
|
|
|
|
if( f->generic.callback )
|
|
|
|
f->generic.callback( f, QM_CHANGED );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Field_Draw
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_Field_Draw( menuField_s *f )
|
|
|
|
{
|
|
|
|
int justify;
|
|
|
|
int shadow;
|
|
|
|
char text[UI_MAX_FIELD_LINE];
|
|
|
|
int len, drawLen, prestep;
|
|
|
|
int cursor, x, textHeight;
|
|
|
|
char cursor_char[3];
|
|
|
|
|
|
|
|
if( f->generic.flags & QMF_LEFT_JUSTIFY )
|
|
|
|
justify = 0;
|
|
|
|
else if( f->generic.flags & QMF_CENTER_JUSTIFY )
|
|
|
|
justify = 1;
|
|
|
|
else if( f->generic.flags & QMF_RIGHT_JUSTIFY )
|
|
|
|
justify = 2;
|
|
|
|
|
|
|
|
shadow = (f->generic.flags & QMF_DROPSHADOW);
|
|
|
|
|
|
|
|
cursor_char[1] = '\0';
|
|
|
|
if( KEY_GetOverstrike( ))
|
|
|
|
cursor_char[0] = 11;
|
|
|
|
else cursor_char[0] = 95;
|
|
|
|
|
|
|
|
drawLen = f->widthInChars;
|
|
|
|
len = strlen( f->buffer ) + 1;
|
|
|
|
|
|
|
|
// guarantee that cursor will be visible
|
|
|
|
if( len <= drawLen )
|
|
|
|
{
|
|
|
|
prestep = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( f->scroll + drawLen > len )
|
|
|
|
{
|
|
|
|
f->scroll = len - drawLen;
|
|
|
|
if( f->scroll < 0 ) f->scroll = 0;
|
|
|
|
}
|
|
|
|
prestep = f->scroll;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( prestep + drawLen > len )
|
|
|
|
drawLen = len - prestep;
|
|
|
|
|
|
|
|
// extract <drawLen> characters from the field at <prestep>
|
|
|
|
if( drawLen >= UI_MAX_FIELD_LINE )
|
|
|
|
HOST_ERROR( "UI_Field_Draw: drawLen >= UI_MAX_FIELD_LINE\n" );
|
|
|
|
|
|
|
|
memcpy( text, f->buffer + prestep, drawLen );
|
|
|
|
text[drawLen] = 0;
|
|
|
|
|
|
|
|
if( f->generic.flags & QMF_HIDEINPUT )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < drawLen; i++ )
|
|
|
|
if( text[i] ) text[i] = '*';
|
|
|
|
}
|
|
|
|
|
|
|
|
// find cursor position
|
|
|
|
x = drawLen - (ColorStrlen( text ) + 1 );
|
|
|
|
if( x < 0 ) x = 0;
|
|
|
|
cursor = ( f->cursor - prestep - x );
|
|
|
|
if( cursor < 0 ) cursor = 0;
|
|
|
|
|
|
|
|
if( justify == 0 ) x = f->generic.x;
|
|
|
|
else if( justify == 1 )
|
|
|
|
x = f->generic.x + ((f->generic.width - (ColorStrlen( text ) * f->generic.charWidth )) / 2 );
|
|
|
|
else if( justify == 2 )
|
|
|
|
x = f->generic.x + (f->generic.width - (ColorStrlen( text ) * f->generic.charWidth ));
|
|
|
|
|
|
|
|
if( f->background )
|
|
|
|
{
|
|
|
|
UI_DrawPic( f->generic.x, f->generic.y, f->generic.width, f->generic.height, uiColorWhite, f->background );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// draw the background
|
|
|
|
UI_FillRect( f->generic.x, f->generic.y, f->generic.width, f->generic.height, uiInputBgColor );
|
|
|
|
|
|
|
|
// draw the rectangle
|
|
|
|
UI_DrawRectangle( f->generic.x, f->generic.y, f->generic.width, f->generic.height, uiInputFgColor );
|
|
|
|
}
|
|
|
|
|
|
|
|
textHeight = f->generic.y - (f->generic.charHeight * 1.5f);
|
|
|
|
UI_DrawString( f->generic.x, textHeight, f->generic.width, f->generic.charHeight, f->generic.name, uiColorHelp, true, f->generic.charWidth, f->generic.charHeight, 0, shadow );
|
|
|
|
|
|
|
|
if( f->generic.flags & QMF_GRAYED )
|
|
|
|
{
|
|
|
|
UI_DrawString( f->generic.x, f->generic.y, f->generic.width, f->generic.height, text, uiColorDkGrey, true, f->generic.charWidth, f->generic.charHeight, justify, shadow );
|
|
|
|
return; // grayed
|
|
|
|
}
|
|
|
|
|
|
|
|
if((menuCommon_s *)f != (menuCommon_s *)UI_ItemAtCursor( f->generic.parent ))
|
|
|
|
{
|
|
|
|
UI_DrawString( f->generic.x, f->generic.y, f->generic.width, f->generic.height, text, f->generic.color, false, f->generic.charWidth, f->generic.charHeight, justify, shadow );
|
|
|
|
return; // no focus
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !( f->generic.flags & QMF_FOCUSBEHIND ))
|
|
|
|
{
|
|
|
|
UI_DrawString( f->generic.x, f->generic.y, f->generic.width, f->generic.height, text, f->generic.color, false, f->generic.charWidth, f->generic.charHeight, justify, shadow );
|
|
|
|
|
|
|
|
if(( uiStatic.realTime & 499 ) < 250 )
|
|
|
|
UI_DrawString( x + (cursor * f->generic.charWidth), f->generic.y, f->generic.charWidth, f->generic.height, cursor_char, f->generic.color, true, f->generic.charWidth, f->generic.charHeight, 0, shadow );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( f->generic.flags & QMF_HIGHLIGHTIFFOCUS )
|
|
|
|
{
|
|
|
|
UI_DrawString( f->generic.x, f->generic.y, f->generic.width, f->generic.height, text, f->generic.focusColor, false, f->generic.charWidth, f->generic.charHeight, justify, shadow );
|
|
|
|
|
|
|
|
if(( uiStatic.realTime & 499 ) < 250 )
|
|
|
|
UI_DrawString( x + (cursor * f->generic.charWidth), f->generic.y, f->generic.charWidth, f->generic.height, cursor_char, f->generic.focusColor, true, f->generic.charWidth, f->generic.charHeight, 0, shadow );
|
|
|
|
}
|
|
|
|
else if( f->generic.flags & QMF_PULSEIFFOCUS )
|
|
|
|
{
|
|
|
|
int color;
|
|
|
|
|
|
|
|
color = PackAlpha( f->generic.color, 255 * (0.5 + 0.5 * sin( uiStatic.realTime / UI_PULSE_DIVISOR )));
|
|
|
|
UI_DrawString( f->generic.x, f->generic.y, f->generic.width, f->generic.height, text, color, false, f->generic.charWidth, f->generic.charHeight, justify, shadow );
|
|
|
|
|
|
|
|
if(( uiStatic.realTime & 499 ) < 250 )
|
|
|
|
UI_DrawString( x + (cursor * f->generic.charWidth), f->generic.y, f->generic.charWidth, f->generic.height, cursor_char, color, true, f->generic.charWidth, f->generic.charHeight, 0, shadow );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( f->generic.flags & QMF_FOCUSBEHIND )
|
|
|
|
{
|
|
|
|
UI_DrawString( f->generic.x, f->generic.y, f->generic.width, f->generic.height, text, f->generic.color, false, f->generic.charWidth, f->generic.charHeight, justify, shadow );
|
|
|
|
|
|
|
|
if(( uiStatic.realTime & 499 ) < 250 )
|
|
|
|
UI_DrawString( x + (cursor * f->generic.charWidth), f->generic.y, f->generic.charWidth, f->generic.height, cursor_char, f->generic.color, true, f->generic.charWidth, f->generic.charHeight, 0, shadow );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Action_Init
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_Action_Init( menuAction_s *a )
|
|
|
|
{
|
|
|
|
if( !a->generic.name ) a->generic.name = ""; // this is also the text displayed
|
|
|
|
|
|
|
|
if( a->generic.flags & QMF_BIGFONT )
|
|
|
|
{
|
|
|
|
a->generic.charWidth = UI_BIG_CHAR_WIDTH;
|
|
|
|
a->generic.charHeight = UI_BIG_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else if( a->generic.flags & QMF_SMALLFONT )
|
|
|
|
{
|
|
|
|
a->generic.charWidth = UI_SMALL_CHAR_WIDTH;
|
|
|
|
a->generic.charHeight = UI_SMALL_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( a->generic.charWidth < 1 ) a->generic.charWidth = UI_MED_CHAR_WIDTH;
|
|
|
|
if( a->generic.charHeight < 1 ) a->generic.charHeight = UI_MED_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!( a->generic.flags & ( QMF_LEFT_JUSTIFY|QMF_CENTER_JUSTIFY|QMF_RIGHT_JUSTIFY )))
|
|
|
|
a->generic.flags |= QMF_LEFT_JUSTIFY;
|
|
|
|
|
|
|
|
if( !a->generic.color ) a->generic.color = uiPromptTextColor;
|
|
|
|
if( !a->generic.focusColor ) a->generic.focusColor = uiPromptFocusColor;
|
|
|
|
|
|
|
|
if( a->generic.width < 1 || a->generic.height < 1 )
|
|
|
|
{
|
|
|
|
if( a->background )
|
|
|
|
{
|
|
|
|
HIMAGE handle = PIC_Load( a->background );
|
|
|
|
a->generic.width = PIC_Width( handle );
|
|
|
|
a->generic.height = PIC_Height( handle );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( a->generic.width < 1 )
|
|
|
|
a->generic.width = a->generic.charWidth * strlen( a->generic.name );
|
|
|
|
|
|
|
|
if( a->generic.height < 1 )
|
|
|
|
a->generic.height = a->generic.charHeight * 1.5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &a->generic.charWidth, &a->generic.charHeight );
|
|
|
|
UI_ScaleCoords( &a->generic.x, &a->generic.y, &a->generic.width, &a->generic.height );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Action_Key
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
const char *UI_Action_Key( menuAction_s *a, int key, int down )
|
|
|
|
{
|
|
|
|
const char *sound = 0;
|
|
|
|
|
|
|
|
switch( key )
|
|
|
|
{
|
|
|
|
case K_MOUSE1:
|
|
|
|
if(!( a->generic.flags & QMF_HASMOUSEFOCUS ))
|
|
|
|
break;
|
|
|
|
sound = uiSoundLaunch;
|
|
|
|
break;
|
|
|
|
case K_ENTER:
|
|
|
|
case K_KP_ENTER:
|
|
|
|
if( !down ) return sound;
|
|
|
|
if( a->generic.flags & QMF_MOUSEONLY )
|
|
|
|
break;
|
|
|
|
sound = uiSoundLaunch;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( sound && ( a->generic.flags & QMF_SILENT ))
|
|
|
|
sound = uiSoundNull;
|
|
|
|
|
|
|
|
if( a->generic.flags & QMF_ACT_ONRELEASE )
|
|
|
|
{
|
|
|
|
if( sound && a->generic.callback )
|
|
|
|
{
|
|
|
|
int event;
|
|
|
|
|
|
|
|
if( down )
|
|
|
|
{
|
|
|
|
event = QM_PRESSED;
|
|
|
|
a->generic.bPressed = true;
|
|
|
|
}
|
|
|
|
else event = QM_ACTIVATED;
|
|
|
|
a->generic.callback( a, event );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( down )
|
|
|
|
{
|
|
|
|
if( sound && a->generic.callback )
|
|
|
|
a->generic.callback( a, QM_ACTIVATED );
|
|
|
|
}
|
|
|
|
|
|
|
|
return sound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Action_Draw
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_Action_Draw( menuAction_s *a )
|
|
|
|
{
|
|
|
|
int justify;
|
|
|
|
int shadow;
|
|
|
|
|
|
|
|
if( a->generic.flags & QMF_LEFT_JUSTIFY )
|
|
|
|
justify = 0;
|
|
|
|
else if( a->generic.flags & QMF_CENTER_JUSTIFY )
|
|
|
|
justify = 1;
|
|
|
|
else if( a->generic.flags & QMF_RIGHT_JUSTIFY )
|
|
|
|
justify = 2;
|
|
|
|
|
|
|
|
shadow = (a->generic.flags & QMF_DROPSHADOW);
|
|
|
|
|
|
|
|
if( a->background )
|
|
|
|
UI_DrawPic( a->generic.x, a->generic.y, a->generic.width, a->generic.height, uiColorWhite, a->background );
|
|
|
|
|
|
|
|
if( a->generic.statusText && a->generic.flags & QMF_NOTIFY )
|
|
|
|
{
|
|
|
|
int charW, charH;
|
|
|
|
int x, w;
|
|
|
|
|
|
|
|
charW = UI_SMALL_CHAR_WIDTH;
|
|
|
|
charH = UI_SMALL_CHAR_HEIGHT;
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &charW, &charH );
|
|
|
|
|
|
|
|
x = 290;
|
|
|
|
w = UI_SMALL_CHAR_WIDTH * strlen( a->generic.statusText );
|
|
|
|
UI_ScaleCoords( &x, NULL, &w, NULL );
|
|
|
|
x += a->generic.x;
|
|
|
|
|
|
|
|
int r, g, b;
|
|
|
|
|
|
|
|
UnpackRGB( r, g, b, uiColorHelp );
|
|
|
|
TextMessageSetColor( r, g, b );
|
|
|
|
DrawConsoleString( x, a->generic.y, a->generic.statusText );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( a->generic.flags & QMF_GRAYED )
|
|
|
|
{
|
|
|
|
UI_DrawString( a->generic.x, a->generic.y, a->generic.width, a->generic.height, a->generic.name, uiColorDkGrey, true, a->generic.charWidth, a->generic.charHeight, justify, shadow );
|
|
|
|
return; // grayed
|
|
|
|
}
|
|
|
|
|
|
|
|
if((menuCommon_s *)a != (menuCommon_s *)UI_ItemAtCursor( a->generic.parent ))
|
|
|
|
{
|
|
|
|
UI_DrawString( a->generic.x, a->generic.y, a->generic.width, a->generic.height, a->generic.name, a->generic.color, false, a->generic.charWidth, a->generic.charHeight, justify, shadow );
|
|
|
|
return; // no focus
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!( a->generic.flags & QMF_FOCUSBEHIND ))
|
|
|
|
UI_DrawString( a->generic.x, a->generic.y, a->generic.width, a->generic.height, a->generic.name, a->generic.color, false, a->generic.charWidth, a->generic.charHeight, justify, shadow );
|
|
|
|
|
|
|
|
if( a->generic.flags & QMF_HIGHLIGHTIFFOCUS )
|
|
|
|
UI_DrawString( a->generic.x, a->generic.y, a->generic.width, a->generic.height, a->generic.name, a->generic.focusColor, false, a->generic.charWidth, a->generic.charHeight, justify, shadow );
|
|
|
|
else if( a->generic.flags & QMF_PULSEIFFOCUS )
|
|
|
|
{
|
|
|
|
int color;
|
|
|
|
|
|
|
|
color = PackAlpha( a->generic.color, 255 * (0.5 + 0.5 * sin( uiStatic.realTime / UI_PULSE_DIVISOR )));
|
|
|
|
|
|
|
|
UI_DrawString( a->generic.x, a->generic.y, a->generic.width, a->generic.height, a->generic.name, color, false, a->generic.charWidth, a->generic.charHeight, justify, shadow );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( a->generic.flags & QMF_FOCUSBEHIND )
|
|
|
|
UI_DrawString( a->generic.x, a->generic.y, a->generic.width, a->generic.height, a->generic.name, a->generic.color, false, a->generic.charWidth, a->generic.charHeight, justify, shadow );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Bitmap_Init
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_Bitmap_Init( menuBitmap_s *b )
|
|
|
|
{
|
|
|
|
if( !b->generic.name ) b->generic.name = "";
|
|
|
|
if( !b->focusPic ) b->focusPic = b->pic;
|
|
|
|
if( !b->generic.color ) b->generic.color = uiColorWhite;
|
|
|
|
|
|
|
|
UI_ScaleCoords( &b->generic.x, &b->generic.y, &b->generic.width, &b->generic.height );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Bitmap_Key
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
const char *UI_Bitmap_Key( menuBitmap_s *b, int key, int down )
|
|
|
|
{
|
|
|
|
const char *sound = 0;
|
|
|
|
|
|
|
|
switch( key )
|
|
|
|
{
|
|
|
|
case K_MOUSE1:
|
|
|
|
if(!( b->generic.flags & QMF_HASMOUSEFOCUS ))
|
|
|
|
break;
|
|
|
|
sound = uiSoundLaunch;
|
|
|
|
break;
|
|
|
|
case K_ENTER:
|
|
|
|
case K_KP_ENTER:
|
|
|
|
if( !down ) return sound;
|
|
|
|
if( b->generic.flags & QMF_MOUSEONLY )
|
|
|
|
break;
|
|
|
|
sound = uiSoundLaunch;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( sound && ( b->generic.flags & QMF_SILENT ))
|
|
|
|
sound = uiSoundNull;
|
|
|
|
|
|
|
|
if( b->generic.flags & QMF_ACT_ONRELEASE )
|
|
|
|
{
|
|
|
|
if( sound && b->generic.callback )
|
|
|
|
{
|
|
|
|
int event;
|
|
|
|
|
|
|
|
if( down )
|
|
|
|
{
|
|
|
|
event = QM_PRESSED;
|
|
|
|
b->generic.bPressed = true;
|
|
|
|
}
|
|
|
|
else event = QM_ACTIVATED;
|
|
|
|
b->generic.callback( b, event );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( down )
|
|
|
|
{
|
|
|
|
if( sound && b->generic.callback )
|
|
|
|
b->generic.callback( b, QM_ACTIVATED );
|
|
|
|
}
|
|
|
|
|
|
|
|
return sound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_Bitmap_Draw
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_Bitmap_Draw( menuBitmap_s *b )
|
|
|
|
{
|
|
|
|
if( b->generic.id == ID_BACKGROUND ) // background is always 0!
|
|
|
|
{
|
|
|
|
if( CVAR_GET_FLOAT( "cl_background" ))
|
|
|
|
return; // has background map disable images
|
|
|
|
|
|
|
|
// UGLY HACK for replace all backgrounds
|
|
|
|
UI_DrawBackground_Callback( b );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//CR
|
|
|
|
if( b->generic.id == 1 )
|
|
|
|
{
|
|
|
|
// don't draw banners until transition is done
|
|
|
|
#ifdef TA_ALT_MODE
|
|
|
|
if( UI_GetTitleTransFraction() != 10 ) return;
|
|
|
|
#else
|
|
|
|
if( UI_GetTitleTransFraction() < 1.0f ) return;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if( b->generic.flags & QMF_GRAYED )
|
|
|
|
{
|
|
|
|
UI_DrawPic( b->generic.x, b->generic.y, b->generic.width, b->generic.height, uiColorDkGrey, b->pic );
|
|
|
|
return; // grayed
|
|
|
|
}
|
|
|
|
|
|
|
|
if(( b->generic.flags & QMF_MOUSEONLY ) && !( b->generic.flags & QMF_HASMOUSEFOCUS ))
|
|
|
|
{
|
|
|
|
UI_DrawPic( b->generic.x, b->generic.y, b->generic.width, b->generic.height, b->generic.color, b->pic );
|
|
|
|
return; // no focus
|
|
|
|
}
|
|
|
|
|
|
|
|
if((menuCommon_s *)b != (menuCommon_s *)UI_ItemAtCursor( b->generic.parent ))
|
|
|
|
{
|
|
|
|
// UNDONE: only inactive bitmaps supported
|
|
|
|
if( b->generic.flags & QMF_DRAW_ADDITIVE )
|
|
|
|
UI_DrawPicAdditive( b->generic.x, b->generic.y, b->generic.width, b->generic.height, b->generic.color, b->pic );
|
|
|
|
else UI_DrawPic( b->generic.x, b->generic.y, b->generic.width, b->generic.height, b->generic.color, b->pic );
|
|
|
|
return; // no focus
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!( b->generic.flags & QMF_FOCUSBEHIND ))
|
|
|
|
UI_DrawPic( b->generic.x, b->generic.y, b->generic.width, b->generic.height, b->generic.color, b->pic );
|
|
|
|
if( b->generic.flags & QMF_HIGHLIGHTIFFOCUS )
|
|
|
|
UI_DrawPic( b->generic.x, b->generic.y, b->generic.width, b->generic.height, b->generic.color, b->focusPic );
|
|
|
|
else if( b->generic.flags & QMF_PULSEIFFOCUS )
|
|
|
|
{
|
|
|
|
int color;
|
|
|
|
|
|
|
|
color = PackAlpha( b->generic.color, 255 * (0.5 + 0.5 * sin( uiStatic.realTime / UI_PULSE_DIVISOR )));
|
|
|
|
UI_DrawPic( b->generic.x, b->generic.y, b->generic.width, b->generic.height, color, b->focusPic );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( b->generic.flags & QMF_FOCUSBEHIND )
|
|
|
|
UI_DrawPic( b->generic.x, b->generic.y, b->generic.width, b->generic.height, b->generic.color, b->pic );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_PicButton_Init
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_PicButton_Init( menuPicButton_s *pb )
|
|
|
|
{
|
|
|
|
if( !pb->generic.name ) pb->generic.name = "";
|
|
|
|
|
|
|
|
if( pb->generic.flags & QMF_BIGFONT )
|
|
|
|
{
|
|
|
|
pb->generic.charWidth = UI_BIG_CHAR_WIDTH;
|
|
|
|
pb->generic.charHeight = UI_BIG_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else if( pb->generic.flags & QMF_SMALLFONT )
|
|
|
|
{
|
|
|
|
pb->generic.charWidth = UI_SMALL_CHAR_WIDTH;
|
|
|
|
pb->generic.charHeight = UI_SMALL_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( pb->generic.charWidth < 1 ) pb->generic.charWidth = UI_MED_CHAR_WIDTH;
|
|
|
|
if( pb->generic.charHeight < 1 ) pb->generic.charHeight = UI_MED_CHAR_HEIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!( pb->generic.flags & ( QMF_LEFT_JUSTIFY|QMF_CENTER_JUSTIFY|QMF_RIGHT_JUSTIFY )))
|
|
|
|
pb->generic.flags |= QMF_LEFT_JUSTIFY;
|
|
|
|
|
|
|
|
if( !pb->generic.color ) pb->generic.color = uiPromptTextColor;
|
|
|
|
if( !pb->generic.focusColor ) pb->generic.focusColor = uiPromptFocusColor;
|
|
|
|
|
|
|
|
if( pb->generic.width < 1 || pb->generic.height < 1 )
|
|
|
|
{
|
|
|
|
if( pb->generic.width < 1 )
|
|
|
|
pb->generic.width = pb->generic.charWidth * strlen( pb->generic.name );
|
|
|
|
|
|
|
|
if( pb->generic.height < 1 )
|
|
|
|
pb->generic.height = pb->generic.charHeight * 1.5;
|
|
|
|
}
|
|
|
|
|
|
|
|
UI_ScaleCoords( &pb->generic.x, &pb->generic.y, &pb->generic.width, &pb->generic.height );
|
|
|
|
UI_ScaleCoords( NULL, NULL, &pb->generic.charWidth, &pb->generic.charHeight );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_PicButton_Key
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
const char *UI_PicButton_Key( menuPicButton_s *b, int key, int down )
|
|
|
|
{
|
|
|
|
const char *sound = 0;
|
|
|
|
|
|
|
|
switch( key )
|
|
|
|
{
|
|
|
|
case K_MOUSE1:
|
|
|
|
if(!( b->generic.flags & QMF_HASMOUSEFOCUS ))
|
|
|
|
break;
|
|
|
|
sound = uiSoundLaunch;
|
|
|
|
break;
|
|
|
|
case K_ENTER:
|
|
|
|
case K_KP_ENTER:
|
|
|
|
if( b->generic.flags & QMF_MOUSEONLY )
|
|
|
|
break;
|
|
|
|
sound = uiSoundLaunch;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( sound && ( b->generic.flags & QMF_SILENT ))
|
|
|
|
sound = uiSoundNull;
|
|
|
|
|
|
|
|
if( b->generic.flags & QMF_ACT_ONRELEASE )
|
|
|
|
{
|
|
|
|
if( sound && b->generic.callback )
|
|
|
|
{
|
|
|
|
int event;
|
|
|
|
|
|
|
|
if( down )
|
|
|
|
{
|
|
|
|
event = QM_PRESSED;
|
|
|
|
b->generic.bPressed = true;
|
|
|
|
}
|
|
|
|
else event = QM_ACTIVATED;
|
|
|
|
//CR
|
|
|
|
UI_TACheckMenuDepth();
|
|
|
|
b->generic.callback( b, event );
|
|
|
|
UI_SetTitleAnim( AS_TO_TITLE, b );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( down )
|
|
|
|
{
|
|
|
|
if( sound && b->generic.callback )
|
|
|
|
b->generic.callback( b, QM_ACTIVATED );
|
|
|
|
}
|
|
|
|
|
|
|
|
return sound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
UI_PicButton_Draw
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void UI_PicButton_Draw( menuPicButton_s *item )
|
|
|
|
{
|
|
|
|
int state = BUTTON_NOFOCUS;
|
|
|
|
|
|
|
|
if( item->generic.flags & QMF_HASMOUSEFOCUS )
|
|
|
|
state = BUTTON_FOCUS;
|
|
|
|
|
|
|
|
// make sure what cursor in rect
|
|
|
|
if( item->generic.bPressed )
|
|
|
|
state = BUTTON_PRESSED;
|
|
|
|
#if 0
|
|
|
|
if( item->generic.statusText && item->generic.flags & QMF_NOTIFY )
|
|
|
|
{
|
|
|
|
int charW, charH;
|
|
|
|
int x, w;
|
|
|
|
|
|
|
|
charW = UI_SMALL_CHAR_WIDTH;
|
|
|
|
charH = UI_SMALL_CHAR_HEIGHT;
|
|
|
|
|
|
|
|
UI_ScaleCoords( NULL, NULL, &charW, &charH );
|
|
|
|
|
|
|
|
x = 290;
|
|
|
|
w = UI_SMALL_CHAR_WIDTH * strlen( item->generic.statusText );
|
|
|
|
UI_ScaleCoords( &x, NULL, &w, NULL );
|
|
|
|
x += item->generic.x;
|
|
|
|
|
|
|
|
int r, g, b;
|
|
|
|
|
|
|
|
UnpackRGB( r, g, b, uiColorHelp );
|
|
|
|
TextMessageSetColor( r, g, b );
|
|
|
|
DrawConsoleString( x, item->generic.y, item->generic.statusText );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if( item->pic )
|
|
|
|
{
|
|
|
|
int r, g, b, a;
|
|
|
|
|
|
|
|
UnpackRGB( r, g, b, item->generic.flags & QMF_GRAYED ? uiColorDkGrey : uiColorWhite );
|
|
|
|
|
|
|
|
wrect_t rects[]=
|
|
|
|
{
|
|
|
|
{ 0, uiStatic.buttons_width, 0, 26 },
|
|
|
|
{ 0, uiStatic.buttons_width, 26, 52 },
|
|
|
|
{ 0, uiStatic.buttons_width, 52, 78 }
|
|
|
|
};
|
|
|
|
|
|
|
|
PIC_Set( item->pic, r, g, b, 255 );
|
|
|
|
PIC_EnableScissor( item->generic.x, item->generic.y, uiStatic.buttons_draw_width, uiStatic.buttons_draw_height - 2 );
|
|
|
|
PIC_DrawAdditive( item->generic.x, item->generic.y, uiStatic.buttons_draw_width, uiStatic.buttons_draw_height, &rects[state] );
|
|
|
|
|
|
|
|
a = (512 - (uiStatic.realTime - item->generic.lastFocusTime)) >> 1;
|
|
|
|
|
|
|
|
if( state == BUTTON_NOFOCUS && a > 0 )
|
|
|
|
{
|
|
|
|
PIC_Set( item->pic, r, g, b, a );
|
|
|
|
PIC_DrawAdditive( item->generic.x, item->generic.y, uiStatic.buttons_draw_width, uiStatic.buttons_draw_height, &rects[BUTTON_FOCUS] );
|
|
|
|
}
|
|
|
|
PIC_DisableScissor();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int justify;
|
|
|
|
int shadow;
|
|
|
|
|
|
|
|
if( item->generic.flags & QMF_LEFT_JUSTIFY )
|
|
|
|
justify = 0;
|
|
|
|
else if( item->generic.flags & QMF_CENTER_JUSTIFY )
|
|
|
|
justify = 1;
|
|
|
|
else if( item->generic.flags & QMF_RIGHT_JUSTIFY )
|
|
|
|
justify = 2;
|
|
|
|
|
|
|
|
shadow = (item->generic.flags & QMF_DROPSHADOW);
|
|
|
|
|
|
|
|
if( item->generic.flags & QMF_GRAYED )
|
|
|
|
{
|
|
|
|
UI_DrawString( item->generic.x, item->generic.y, item->generic.width, item->generic.height, item->generic.name, uiColorDkGrey, true, item->generic.charWidth, item->generic.charHeight, justify, shadow );
|
|
|
|
return; // grayed
|
|
|
|
}
|
|
|
|
|
|
|
|
if((menuCommon_s *)item != (menuCommon_s *)UI_ItemAtCursor( item->generic.parent ))
|
|
|
|
{
|
|
|
|
UI_DrawString( item->generic.x, item->generic.y, item->generic.width, item->generic.height, item->generic.name, item->generic.color, false, item->generic.charWidth, item->generic.charHeight, justify, shadow );
|
|
|
|
return; // no focus
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!( item->generic.flags & QMF_FOCUSBEHIND ))
|
|
|
|
UI_DrawString( item->generic.x, item->generic.y, item->generic.width, item->generic.height, item->generic.name, item->generic.color, false, item->generic.charWidth, item->generic.charHeight, justify, shadow );
|
|
|
|
|
|
|
|
if( item->generic.flags & QMF_HIGHLIGHTIFFOCUS )
|
|
|
|
UI_DrawString( item->generic.x, item->generic.y, item->generic.width, item->generic.height, item->generic.name, item->generic.focusColor, false, item->generic.charWidth, item->generic.charHeight, justify, shadow );
|
|
|
|
else if( item->generic.flags & QMF_PULSEIFFOCUS )
|
|
|
|
{
|
|
|
|
int color;
|
|
|
|
|
|
|
|
color = PackAlpha( item->generic.color, 255 * (0.5 + 0.5 * sin( uiStatic.realTime / UI_PULSE_DIVISOR )));
|
|
|
|
|
|
|
|
UI_DrawString( item->generic.x, item->generic.y, item->generic.width, item->generic.height, item->generic.name, color, false, item->generic.charWidth, item->generic.charHeight, justify, shadow );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( item->generic.flags & QMF_FOCUSBEHIND )
|
|
|
|
UI_DrawString( item->generic.x, item->generic.y, item->generic.width, item->generic.height, item->generic.name, item->generic.color, false, item->generic.charWidth, item->generic.charHeight, justify, shadow );
|
|
|
|
}
|
2020-08-31 00:15:53 +02:00
|
|
|
}
|