Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

ui_mfield.c (8901B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 //
     23 #include "ui_local.h"
     24 
     25 /*
     26 ===================
     27 MField_Draw
     28 
     29 Handles horizontal scrolling and cursor blinking
     30 x, y, are in pixels
     31 ===================
     32 */
     33 void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color ) {
     34 	int		len;
     35 	int		charw;
     36 	int		drawLen;
     37 	int		prestep;
     38 	int		cursorChar;
     39 	char	str[MAX_STRING_CHARS];
     40 
     41 	drawLen = edit->widthInChars;
     42 	len     = strlen( edit->buffer ) + 1;
     43 
     44 	// guarantee that cursor will be visible
     45 	if ( len <= drawLen ) {
     46 		prestep = 0;
     47 	} else {
     48 		if ( edit->scroll + drawLen > len ) {
     49 			edit->scroll = len - drawLen;
     50 			if ( edit->scroll < 0 ) {
     51 				edit->scroll = 0;
     52 			}
     53 		}
     54 		prestep = edit->scroll;
     55 	}
     56 
     57 	if ( prestep + drawLen > len ) {
     58 		drawLen = len - prestep;
     59 	}
     60 
     61 	// extract <drawLen> characters from the field at <prestep>
     62 	if ( drawLen >= MAX_STRING_CHARS ) {
     63 		trap_Error( "drawLen >= MAX_STRING_CHARS" );
     64 	}
     65 	memcpy( str, edit->buffer + prestep, drawLen );
     66 	str[ drawLen ] = 0;
     67 
     68 	UI_DrawString( x, y, str, style, color );
     69 
     70 	// draw the cursor
     71 	if (!(style & UI_PULSE)) {
     72 		return;
     73 	}
     74 
     75 	if ( trap_Key_GetOverstrikeMode() ) {
     76 		cursorChar = 11;
     77 	} else {
     78 		cursorChar = 10;
     79 	}
     80 
     81 	style &= ~UI_PULSE;
     82 	style |= UI_BLINK;
     83 
     84 	if (style & UI_SMALLFONT)
     85 	{
     86 		charw =	SMALLCHAR_WIDTH;
     87 	}
     88 	else if (style & UI_GIANTFONT)
     89 	{
     90 		charw =	GIANTCHAR_WIDTH;
     91 	}
     92 	else
     93 	{
     94 		charw =	BIGCHAR_WIDTH;
     95 	}
     96 
     97 	if (style & UI_CENTER)
     98 	{
     99 		len = strlen(str);
    100 		x = x - len*charw/2;
    101 	}
    102 	else if (style & UI_RIGHT)
    103 	{
    104 		len = strlen(str);
    105 		x = x - len*charw;
    106 	}
    107 	
    108 	UI_DrawChar( x + ( edit->cursor - prestep ) * charw, y, cursorChar, style & ~(UI_CENTER|UI_RIGHT), color );
    109 }
    110 
    111 /*
    112 ================
    113 MField_Paste
    114 ================
    115 */
    116 void MField_Paste( mfield_t *edit ) {
    117 	char	pasteBuffer[64];
    118 	int		pasteLen, i;
    119 
    120 	trap_GetClipboardData( pasteBuffer, 64 );
    121 
    122 	// send as if typed, so insert / overstrike works properly
    123 	pasteLen = strlen( pasteBuffer );
    124 	for ( i = 0 ; i < pasteLen ; i++ ) {
    125 		MField_CharEvent( edit, pasteBuffer[i] );
    126 	}
    127 }
    128 
    129 /*
    130 =================
    131 MField_KeyDownEvent
    132 
    133 Performs the basic line editing functions for the console,
    134 in-game talk, and menu fields
    135 
    136 Key events are used for non-printable characters, others are gotten from char events.
    137 =================
    138 */
    139 void MField_KeyDownEvent( mfield_t *edit, int key ) {
    140 	int		len;
    141 
    142 	// shift-insert is paste
    143 	if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && trap_Key_IsDown( K_SHIFT ) ) {
    144 		MField_Paste( edit );
    145 		return;
    146 	}
    147 
    148 	len = strlen( edit->buffer );
    149 
    150 	if ( key == K_DEL || key == K_KP_DEL ) {
    151 		if ( edit->cursor < len ) {
    152 			memmove( edit->buffer + edit->cursor, 
    153 				edit->buffer + edit->cursor + 1, len - edit->cursor );
    154 		}
    155 		return;
    156 	}
    157 
    158 	if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) 
    159 	{
    160 		if ( edit->cursor < len ) {
    161 			edit->cursor++;
    162 		}
    163 		if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
    164 		{
    165 			edit->scroll++;
    166 		}
    167 		return;
    168 	}
    169 
    170 	if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) 
    171 	{
    172 		if ( edit->cursor > 0 ) {
    173 			edit->cursor--;
    174 		}
    175 		if ( edit->cursor < edit->scroll )
    176 		{
    177 			edit->scroll--;
    178 		}
    179 		return;
    180 	}
    181 
    182 	if ( key == K_HOME || key == K_KP_HOME || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
    183 		edit->cursor = 0;
    184 		edit->scroll = 0;
    185 		return;
    186 	}
    187 
    188 	if ( key == K_END || key == K_KP_END || ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
    189 		edit->cursor = len;
    190 		edit->scroll = len - edit->widthInChars + 1;
    191 		if (edit->scroll < 0)
    192 			edit->scroll = 0;
    193 		return;
    194 	}
    195 
    196 	if ( key == K_INS || key == K_KP_INS ) {
    197 		trap_Key_SetOverstrikeMode( !trap_Key_GetOverstrikeMode() );
    198 		return;
    199 	}
    200 }
    201 
    202 /*
    203 ==================
    204 MField_CharEvent
    205 ==================
    206 */
    207 void MField_CharEvent( mfield_t *edit, int ch ) {
    208 	int		len;
    209 
    210 	if ( ch == 'v' - 'a' + 1 ) {	// ctrl-v is paste
    211 		MField_Paste( edit );
    212 		return;
    213 	}
    214 
    215 	if ( ch == 'c' - 'a' + 1 ) {	// ctrl-c clears the field
    216 		MField_Clear( edit );
    217 		return;
    218 	}
    219 
    220 	len = strlen( edit->buffer );
    221 
    222 	if ( ch == 'h' - 'a' + 1 )	{	// ctrl-h is backspace
    223 		if ( edit->cursor > 0 ) {
    224 			memmove( edit->buffer + edit->cursor - 1, 
    225 				edit->buffer + edit->cursor, len + 1 - edit->cursor );
    226 			edit->cursor--;
    227 			if ( edit->cursor < edit->scroll )
    228 			{
    229 				edit->scroll--;
    230 			}
    231 		}
    232 		return;
    233 	}
    234 
    235 	if ( ch == 'a' - 'a' + 1 ) {	// ctrl-a is home
    236 		edit->cursor = 0;
    237 		edit->scroll = 0;
    238 		return;
    239 	}
    240 
    241 	if ( ch == 'e' - 'a' + 1 ) {	// ctrl-e is end
    242 		edit->cursor = len;
    243 		edit->scroll = edit->cursor - edit->widthInChars + 1;
    244 		if (edit->scroll < 0)
    245 			edit->scroll = 0;
    246 		return;
    247 	}
    248 
    249 	//
    250 	// ignore any other non printable chars
    251 	//
    252 	if ( ch < 32 ) {
    253 		return;
    254 	}
    255 
    256 	if ( !trap_Key_GetOverstrikeMode() ) {	
    257 		if ((edit->cursor == MAX_EDIT_LINE - 1) || (edit->maxchars && edit->cursor >= edit->maxchars))
    258 			return;
    259 	} else {
    260 		// insert mode
    261 		if (( len == MAX_EDIT_LINE - 1 ) || (edit->maxchars && len >= edit->maxchars))
    262 			return;
    263 		memmove( edit->buffer + edit->cursor + 1, edit->buffer + edit->cursor, len + 1 - edit->cursor );
    264 	}
    265 
    266 	edit->buffer[edit->cursor] = ch;
    267 	if (!edit->maxchars || edit->cursor < edit->maxchars-1)
    268 		edit->cursor++;
    269 
    270 	if ( edit->cursor >= edit->widthInChars )
    271 	{
    272 		edit->scroll++;
    273 	}
    274 
    275 	if ( edit->cursor == len + 1) {
    276 		edit->buffer[edit->cursor] = 0;
    277 	}
    278 }
    279 
    280 /*
    281 ==================
    282 MField_Clear
    283 ==================
    284 */
    285 void MField_Clear( mfield_t *edit ) {
    286 	edit->buffer[0] = 0;
    287 	edit->cursor = 0;
    288 	edit->scroll = 0;
    289 }
    290 
    291 /*
    292 ==================
    293 MenuField_Init
    294 ==================
    295 */
    296 void MenuField_Init( menufield_s* m ) {
    297 	int	l;
    298 	int	w;
    299 	int	h;
    300 
    301 	MField_Clear( &m->field );
    302 
    303 	if (m->generic.flags & QMF_SMALLFONT)
    304 	{
    305 		w = SMALLCHAR_WIDTH;
    306 		h = SMALLCHAR_HEIGHT;
    307 	}
    308 	else
    309 	{
    310 		w = BIGCHAR_WIDTH;
    311 		h = BIGCHAR_HEIGHT;
    312 	}	
    313 
    314 	if (m->generic.name) {
    315 		l = (strlen( m->generic.name )+1) * w;		
    316 	}
    317 	else {
    318 		l = 0;
    319 	}
    320 
    321 	m->generic.left   = m->generic.x - l;
    322 	m->generic.top    = m->generic.y;
    323 	m->generic.right  = m->generic.x + w + m->field.widthInChars*w;
    324 	m->generic.bottom = m->generic.y + h;
    325 }
    326 
    327 /*
    328 ==================
    329 MenuField_Draw
    330 ==================
    331 */
    332 void MenuField_Draw( menufield_s *f )
    333 {
    334 	int		x;
    335 	int		y;
    336 	int		w;
    337 	int		h;
    338 	int		style;
    339 	qboolean focus;
    340 	float	*color;
    341 
    342 	x =	f->generic.x;
    343 	y =	f->generic.y;
    344 
    345 	if (f->generic.flags & QMF_SMALLFONT)
    346 	{
    347 		w = SMALLCHAR_WIDTH;
    348 		h = SMALLCHAR_HEIGHT;
    349 		style = UI_SMALLFONT;
    350 	}
    351 	else
    352 	{
    353 		w = BIGCHAR_WIDTH;
    354 		h = BIGCHAR_HEIGHT;
    355 		style = UI_BIGFONT;
    356 	}	
    357 
    358 	if (Menu_ItemAtCursor( f->generic.parent ) == f) {
    359 		focus = qtrue;
    360 		style |= UI_PULSE;
    361 	}
    362 	else {
    363 		focus = qfalse;
    364 	}
    365 
    366 	if (f->generic.flags & QMF_GRAYED)
    367 		color = text_color_disabled;
    368 	else if (focus)
    369 		color = text_color_highlight;
    370 	else
    371 		color = text_color_normal;
    372 
    373 	if ( focus )
    374 	{
    375 		// draw cursor
    376 		UI_FillRect( f->generic.left, f->generic.top, f->generic.right-f->generic.left+1, f->generic.bottom-f->generic.top+1, listbar_color ); 
    377 		UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|style, color);
    378 	}
    379 
    380 	if ( f->generic.name ) {
    381 		UI_DrawString( x - w, y, f->generic.name, style|UI_RIGHT, color );
    382 	}
    383 
    384 	MField_Draw( &f->field, x + w, y, style, color );
    385 }
    386 
    387 /*
    388 ==================
    389 MenuField_Key
    390 ==================
    391 */
    392 sfxHandle_t MenuField_Key( menufield_s* m, int* key )
    393 {
    394 	int keycode;
    395 
    396 	keycode = *key;
    397 
    398 	switch ( keycode )
    399 	{
    400 		case K_KP_ENTER:
    401 		case K_ENTER:
    402 		case K_JOY1:
    403 		case K_JOY2:
    404 		case K_JOY3:
    405 		case K_JOY4:
    406 			// have enter go to next cursor point
    407 			*key = K_TAB;
    408 			break;
    409 
    410 		case K_TAB:
    411 		case K_KP_DOWNARROW:
    412 		case K_DOWNARROW:
    413 		case K_KP_UPARROW:
    414 		case K_UPARROW:
    415 			break;
    416 
    417 		default:
    418 			if ( keycode & K_CHAR_FLAG )
    419 			{
    420 				keycode &= ~K_CHAR_FLAG;
    421 
    422 				if ((m->generic.flags & QMF_UPPERCASE) && Q_islower( keycode ))
    423 					keycode -= 'a' - 'A';
    424 				else if ((m->generic.flags & QMF_LOWERCASE) && Q_isupper( keycode ))
    425 					keycode -= 'A' - 'a';
    426 				else if ((m->generic.flags & QMF_NUMBERSONLY) && Q_isalpha( keycode ))
    427 					return (menu_buzz_sound);
    428 
    429 				MField_CharEvent( &m->field, keycode);
    430 			}
    431 			else
    432 				MField_KeyDownEvent( &m->field, keycode );
    433 			break;
    434 	}
    435 
    436 	return (0);
    437 }
    438 
    439