Paranoia2/mainui/utils.cpp

2266 lines
59 KiB
C++
Raw Normal View History

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 );
}
}