aboutsummaryrefslogtreecommitdiff
path: root/code/q3_ui/ui_mfield.c
diff options
context:
space:
mode:
Diffstat (limited to 'code/q3_ui/ui_mfield.c')
-rw-r--r--code/q3_ui/ui_mfield.c439
1 files changed, 439 insertions, 0 deletions
diff --git a/code/q3_ui/ui_mfield.c b/code/q3_ui/ui_mfield.c
new file mode 100644
index 0000000..d7b13fe
--- /dev/null
+++ b/code/q3_ui/ui_mfield.c
@@ -0,0 +1,439 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//
+#include "ui_local.h"
+
+/*
+===================
+MField_Draw
+
+Handles horizontal scrolling and cursor blinking
+x, y, are in pixels
+===================
+*/
+void MField_Draw( mfield_t *edit, int x, int y, int style, vec4_t color ) {
+ int len;
+ int charw;
+ int drawLen;
+ int prestep;
+ int cursorChar;
+ char str[MAX_STRING_CHARS];
+
+ drawLen = edit->widthInChars;
+ len = strlen( edit->buffer ) + 1;
+
+ // guarantee that cursor will be visible
+ if ( len <= drawLen ) {
+ prestep = 0;
+ } else {
+ if ( edit->scroll + drawLen > len ) {
+ edit->scroll = len - drawLen;
+ if ( edit->scroll < 0 ) {
+ edit->scroll = 0;
+ }
+ }
+ prestep = edit->scroll;
+ }
+
+ if ( prestep + drawLen > len ) {
+ drawLen = len - prestep;
+ }
+
+ // extract <drawLen> characters from the field at <prestep>
+ if ( drawLen >= MAX_STRING_CHARS ) {
+ trap_Error( "drawLen >= MAX_STRING_CHARS" );
+ }
+ memcpy( str, edit->buffer + prestep, drawLen );
+ str[ drawLen ] = 0;
+
+ UI_DrawString( x, y, str, style, color );
+
+ // draw the cursor
+ if (!(style & UI_PULSE)) {
+ return;
+ }
+
+ if ( trap_Key_GetOverstrikeMode() ) {
+ cursorChar = 11;
+ } else {
+ cursorChar = 10;
+ }
+
+ style &= ~UI_PULSE;
+ style |= UI_BLINK;
+
+ if (style & UI_SMALLFONT)
+ {
+ charw = SMALLCHAR_WIDTH;
+ }
+ else if (style & UI_GIANTFONT)
+ {
+ charw = GIANTCHAR_WIDTH;
+ }
+ else
+ {
+ charw = BIGCHAR_WIDTH;
+ }
+
+ if (style & UI_CENTER)
+ {
+ len = strlen(str);
+ x = x - len*charw/2;
+ }
+ else if (style & UI_RIGHT)
+ {
+ len = strlen(str);
+ x = x - len*charw;
+ }
+
+ UI_DrawChar( x + ( edit->cursor - prestep ) * charw, y, cursorChar, style & ~(UI_CENTER|UI_RIGHT), color );
+}
+
+/*
+================
+MField_Paste
+================
+*/
+void MField_Paste( mfield_t *edit ) {
+ char pasteBuffer[64];
+ int pasteLen, i;
+
+ trap_GetClipboardData( pasteBuffer, 64 );
+
+ // send as if typed, so insert / overstrike works properly
+ pasteLen = strlen( pasteBuffer );
+ for ( i = 0 ; i < pasteLen ; i++ ) {
+ MField_CharEvent( edit, pasteBuffer[i] );
+ }
+}
+
+/*
+=================
+MField_KeyDownEvent
+
+Performs the basic line editing functions for the console,
+in-game talk, and menu fields
+
+Key events are used for non-printable characters, others are gotten from char events.
+=================
+*/
+void MField_KeyDownEvent( mfield_t *edit, int key ) {
+ int len;
+
+ // shift-insert is paste
+ if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && trap_Key_IsDown( K_SHIFT ) ) {
+ MField_Paste( edit );
+ return;
+ }
+
+ len = strlen( edit->buffer );
+
+ if ( key == K_DEL || key == K_KP_DEL ) {
+ if ( edit->cursor < len ) {
+ memmove( edit->buffer + edit->cursor,
+ edit->buffer + edit->cursor + 1, len - edit->cursor );
+ }
+ return;
+ }
+
+ if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
+ {
+ if ( edit->cursor < len ) {
+ edit->cursor++;
+ }
+ if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
+ {
+ edit->scroll++;
+ }
+ return;
+ }
+
+ if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
+ {
+ if ( edit->cursor > 0 ) {
+ edit->cursor--;
+ }
+ if ( edit->cursor < edit->scroll )
+ {
+ edit->scroll--;
+ }
+ return;
+ }
+
+ if ( key == K_HOME || key == K_KP_HOME || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
+ edit->cursor = 0;
+ edit->scroll = 0;
+ return;
+ }
+
+ if ( key == K_END || key == K_KP_END || ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
+ edit->cursor = len;
+ edit->scroll = len - edit->widthInChars + 1;
+ if (edit->scroll < 0)
+ edit->scroll = 0;
+ return;
+ }
+
+ if ( key == K_INS || key == K_KP_INS ) {
+ trap_Key_SetOverstrikeMode( !trap_Key_GetOverstrikeMode() );
+ return;
+ }
+}
+
+/*
+==================
+MField_CharEvent
+==================
+*/
+void MField_CharEvent( mfield_t *edit, int ch ) {
+ int len;
+
+ if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste
+ MField_Paste( edit );
+ return;
+ }
+
+ if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field
+ MField_Clear( edit );
+ return;
+ }
+
+ len = strlen( edit->buffer );
+
+ if ( ch == 'h' - 'a' + 1 ) { // ctrl-h is backspace
+ if ( edit->cursor > 0 ) {
+ memmove( edit->buffer + edit->cursor - 1,
+ edit->buffer + edit->cursor, len + 1 - edit->cursor );
+ edit->cursor--;
+ if ( edit->cursor < edit->scroll )
+ {
+ edit->scroll--;
+ }
+ }
+ return;
+ }
+
+ if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home
+ edit->cursor = 0;
+ edit->scroll = 0;
+ return;
+ }
+
+ if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end
+ edit->cursor = len;
+ edit->scroll = edit->cursor - edit->widthInChars + 1;
+ if (edit->scroll < 0)
+ edit->scroll = 0;
+ return;
+ }
+
+ //
+ // ignore any other non printable chars
+ //
+ if ( ch < 32 ) {
+ return;
+ }
+
+ if ( !trap_Key_GetOverstrikeMode() ) {
+ if ((edit->cursor == MAX_EDIT_LINE - 1) || (edit->maxchars && edit->cursor >= edit->maxchars))
+ return;
+ } else {
+ // insert mode
+ if (( len == MAX_EDIT_LINE - 1 ) || (edit->maxchars && len >= edit->maxchars))
+ return;
+ memmove( edit->buffer + edit->cursor + 1, edit->buffer + edit->cursor, len + 1 - edit->cursor );
+ }
+
+ edit->buffer[edit->cursor] = ch;
+ if (!edit->maxchars || edit->cursor < edit->maxchars-1)
+ edit->cursor++;
+
+ if ( edit->cursor >= edit->widthInChars )
+ {
+ edit->scroll++;
+ }
+
+ if ( edit->cursor == len + 1) {
+ edit->buffer[edit->cursor] = 0;
+ }
+}
+
+/*
+==================
+MField_Clear
+==================
+*/
+void MField_Clear( mfield_t *edit ) {
+ edit->buffer[0] = 0;
+ edit->cursor = 0;
+ edit->scroll = 0;
+}
+
+/*
+==================
+MenuField_Init
+==================
+*/
+void MenuField_Init( menufield_s* m ) {
+ int l;
+ int w;
+ int h;
+
+ MField_Clear( &m->field );
+
+ if (m->generic.flags & QMF_SMALLFONT)
+ {
+ w = SMALLCHAR_WIDTH;
+ h = SMALLCHAR_HEIGHT;
+ }
+ else
+ {
+ w = BIGCHAR_WIDTH;
+ h = BIGCHAR_HEIGHT;
+ }
+
+ if (m->generic.name) {
+ l = (strlen( m->generic.name )+1) * w;
+ }
+ else {
+ l = 0;
+ }
+
+ m->generic.left = m->generic.x - l;
+ m->generic.top = m->generic.y;
+ m->generic.right = m->generic.x + w + m->field.widthInChars*w;
+ m->generic.bottom = m->generic.y + h;
+}
+
+/*
+==================
+MenuField_Draw
+==================
+*/
+void MenuField_Draw( menufield_s *f )
+{
+ int x;
+ int y;
+ int w;
+ int h;
+ int style;
+ qboolean focus;
+ float *color;
+
+ x = f->generic.x;
+ y = f->generic.y;
+
+ if (f->generic.flags & QMF_SMALLFONT)
+ {
+ w = SMALLCHAR_WIDTH;
+ h = SMALLCHAR_HEIGHT;
+ style = UI_SMALLFONT;
+ }
+ else
+ {
+ w = BIGCHAR_WIDTH;
+ h = BIGCHAR_HEIGHT;
+ style = UI_BIGFONT;
+ }
+
+ if (Menu_ItemAtCursor( f->generic.parent ) == f) {
+ focus = qtrue;
+ style |= UI_PULSE;
+ }
+ else {
+ focus = qfalse;
+ }
+
+ if (f->generic.flags & QMF_GRAYED)
+ color = text_color_disabled;
+ else if (focus)
+ color = text_color_highlight;
+ else
+ color = text_color_normal;
+
+ if ( focus )
+ {
+ // draw cursor
+ UI_FillRect( f->generic.left, f->generic.top, f->generic.right-f->generic.left+1, f->generic.bottom-f->generic.top+1, listbar_color );
+ UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|style, color);
+ }
+
+ if ( f->generic.name ) {
+ UI_DrawString( x - w, y, f->generic.name, style|UI_RIGHT, color );
+ }
+
+ MField_Draw( &f->field, x + w, y, style, color );
+}
+
+/*
+==================
+MenuField_Key
+==================
+*/
+sfxHandle_t MenuField_Key( menufield_s* m, int* key )
+{
+ int keycode;
+
+ keycode = *key;
+
+ switch ( keycode )
+ {
+ case K_KP_ENTER:
+ case K_ENTER:
+ case K_JOY1:
+ case K_JOY2:
+ case K_JOY3:
+ case K_JOY4:
+ // have enter go to next cursor point
+ *key = K_TAB;
+ break;
+
+ case K_TAB:
+ case K_KP_DOWNARROW:
+ case K_DOWNARROW:
+ case K_KP_UPARROW:
+ case K_UPARROW:
+ break;
+
+ default:
+ if ( keycode & K_CHAR_FLAG )
+ {
+ keycode &= ~K_CHAR_FLAG;
+
+ if ((m->generic.flags & QMF_UPPERCASE) && Q_islower( keycode ))
+ keycode -= 'a' - 'A';
+ else if ((m->generic.flags & QMF_LOWERCASE) && Q_isupper( keycode ))
+ keycode -= 'A' - 'a';
+ else if ((m->generic.flags & QMF_NUMBERSONLY) && Q_isalpha( keycode ))
+ return (menu_buzz_sound);
+
+ MField_CharEvent( &m->field, keycode);
+ }
+ else
+ MField_KeyDownEvent( &m->field, keycode );
+ break;
+ }
+
+ return (0);
+}
+
+