123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 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 3 of the License, or
- (at your option) any later version.
- Doom 3 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- static autoComplete_t globalAutoComplete;
- /*
- ===============
- FindMatches
- ===============
- */
- static void FindMatches( const char *s ) {
- int i;
- if ( idStr::Icmpn( s, globalAutoComplete.completionString, strlen( globalAutoComplete.completionString ) ) != 0 ) {
- return;
- }
- globalAutoComplete.matchCount++;
- if ( globalAutoComplete.matchCount == 1 ) {
- idStr::Copynz( globalAutoComplete.currentMatch, s, sizeof( globalAutoComplete.currentMatch ) );
- return;
- }
- // cut currentMatch to the amount common with s
- for ( i = 0; s[i]; i++ ) {
- if ( tolower( globalAutoComplete.currentMatch[i] ) != tolower( s[i] ) ) {
- globalAutoComplete.currentMatch[i] = 0;
- break;
- }
- }
- globalAutoComplete.currentMatch[i] = 0;
- }
- /*
- ===============
- FindIndexMatch
- ===============
- */
- static void FindIndexMatch( const char *s ) {
- if ( idStr::Icmpn( s, globalAutoComplete.completionString, strlen( globalAutoComplete.completionString ) ) != 0 ) {
- return;
- }
- if( globalAutoComplete.findMatchIndex == globalAutoComplete.matchIndex ) {
- idStr::Copynz( globalAutoComplete.currentMatch, s, sizeof( globalAutoComplete.currentMatch ) );
- }
- globalAutoComplete.findMatchIndex++;
- }
- /*
- ===============
- PrintMatches
- ===============
- */
- static void PrintMatches( const char *s ) {
- if ( idStr::Icmpn( s, globalAutoComplete.currentMatch, strlen( globalAutoComplete.currentMatch ) ) == 0 ) {
- common->Printf( " %s\n", s );
- }
- }
- /*
- ===============
- PrintCvarMatches
- ===============
- */
- static void PrintCvarMatches( const char *s ) {
- if ( idStr::Icmpn( s, globalAutoComplete.currentMatch, strlen( globalAutoComplete.currentMatch ) ) == 0 ) {
- common->Printf( " %s" S_COLOR_WHITE " = \"%s\"\n", s, cvarSystem->GetCVarString( s ) );
- }
- }
- /*
- ===============
- idEditField::idEditField
- ===============
- */
- idEditField::idEditField() {
- widthInChars = 0;
- Clear();
- }
- /*
- ===============
- idEditField::~idEditField
- ===============
- */
- idEditField::~idEditField() {
- }
- /*
- ===============
- idEditField::Clear
- ===============
- */
- void idEditField::Clear( void ) {
- buffer[0] = 0;
- cursor = 0;
- scroll = 0;
- autoComplete.length = 0;
- autoComplete.valid = false;
- }
- /*
- ===============
- idEditField::SetWidthInChars
- ===============
- */
- void idEditField::SetWidthInChars( int w ) {
- assert( w <= MAX_EDIT_LINE );
- widthInChars = w;
- }
- /*
- ===============
- idEditField::SetCursor
- ===============
- */
- void idEditField::SetCursor( int c ) {
- assert( c <= MAX_EDIT_LINE );
- cursor = c;
- }
- /*
- ===============
- idEditField::GetCursor
- ===============
- */
- int idEditField::GetCursor( void ) const {
- return cursor;
- }
- /*
- ===============
- idEditField::ClearAutoComplete
- ===============
- */
- void idEditField::ClearAutoComplete( void ) {
- if ( autoComplete.length > 0 && autoComplete.length <= (int) strlen( buffer ) ) {
- buffer[autoComplete.length] = '\0';
- if ( cursor > autoComplete.length ) {
- cursor = autoComplete.length;
- }
- }
- autoComplete.length = 0;
- autoComplete.valid = false;
- }
- /*
- ===============
- idEditField::GetAutoCompleteLength
- ===============
- */
- int idEditField::GetAutoCompleteLength( void ) const {
- return autoComplete.length;
- }
- /*
- ===============
- idEditField::AutoComplete
- ===============
- */
- void idEditField::AutoComplete( void ) {
- char completionArgString[MAX_EDIT_LINE];
- idCmdArgs args;
- if ( !autoComplete.valid ) {
- args.TokenizeString( buffer, false );
- idStr::Copynz( autoComplete.completionString, args.Argv( 0 ), sizeof( autoComplete.completionString ) );
- idStr::Copynz( completionArgString, args.Args(), sizeof( completionArgString ) );
- autoComplete.matchCount = 0;
- autoComplete.matchIndex = 0;
- autoComplete.currentMatch[0] = 0;
- if ( strlen( autoComplete.completionString ) == 0 ) {
- return;
- }
- globalAutoComplete = autoComplete;
- cmdSystem->CommandCompletion( FindMatches );
- cvarSystem->CommandCompletion( FindMatches );
- autoComplete = globalAutoComplete;
- if ( autoComplete.matchCount == 0 ) {
- return; // no matches
- }
- // when there's only one match or there's an argument
- if ( autoComplete.matchCount == 1 || completionArgString[0] != '\0' ) {
- /// try completing arguments
- idStr::Append( autoComplete.completionString, sizeof( autoComplete.completionString ), " " );
- idStr::Append( autoComplete.completionString, sizeof( autoComplete.completionString ), completionArgString );
- autoComplete.matchCount = 0;
- globalAutoComplete = autoComplete;
- cmdSystem->ArgCompletion( autoComplete.completionString, FindMatches );
- cvarSystem->ArgCompletion( autoComplete.completionString, FindMatches );
- autoComplete = globalAutoComplete;
- idStr::snPrintf( buffer, sizeof( buffer ), "%s", autoComplete.currentMatch );
- if ( autoComplete.matchCount == 0 ) {
- // no argument matches
- idStr::Append( buffer, sizeof( buffer ), " " );
- idStr::Append( buffer, sizeof( buffer ), completionArgString );
- SetCursor( strlen( buffer ) );
- return;
- }
- } else {
- // multiple matches, complete to shortest
- idStr::snPrintf( buffer, sizeof( buffer ), "%s", autoComplete.currentMatch );
- if ( strlen( completionArgString ) ) {
- idStr::Append( buffer, sizeof( buffer ), " " );
- idStr::Append( buffer, sizeof( buffer ), completionArgString );
- }
- }
- autoComplete.length = strlen( buffer );
- autoComplete.valid = ( autoComplete.matchCount != 1 );
- SetCursor( autoComplete.length );
- common->Printf( "]%s\n", buffer );
- // run through again, printing matches
- globalAutoComplete = autoComplete;
- cmdSystem->CommandCompletion( PrintMatches );
- cmdSystem->ArgCompletion( autoComplete.completionString, PrintMatches );
- cvarSystem->CommandCompletion( PrintCvarMatches );
- cvarSystem->ArgCompletion( autoComplete.completionString, PrintMatches );
- } else if ( autoComplete.matchCount != 1 ) {
- // get the next match and show instead
- autoComplete.matchIndex++;
- if ( autoComplete.matchIndex == autoComplete.matchCount ) {
- autoComplete.matchIndex = 0;
- }
- autoComplete.findMatchIndex = 0;
- globalAutoComplete = autoComplete;
- cmdSystem->CommandCompletion( FindIndexMatch );
- cmdSystem->ArgCompletion( autoComplete.completionString, FindIndexMatch );
- cvarSystem->CommandCompletion( FindIndexMatch );
- cvarSystem->ArgCompletion( autoComplete.completionString, FindIndexMatch );
- autoComplete = globalAutoComplete;
- // and print it
- idStr::snPrintf( buffer, sizeof( buffer ), autoComplete.currentMatch );
- if ( autoComplete.length > (int)strlen( buffer ) ) {
- autoComplete.length = strlen( buffer );
- }
- SetCursor( autoComplete.length );
- }
- }
- /*
- ===============
- idEditField::CharEvent
- ===============
- */
- void idEditField::CharEvent( int ch ) {
- int len;
- if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste
- Paste();
- return;
- }
- if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field
- Clear();
- return;
- }
- len = strlen( buffer );
- if ( ch == 'h' - 'a' + 1 || ch == K_BACKSPACE ) { // ctrl-h is backspace
- if ( cursor > 0 ) {
- memmove( buffer + cursor - 1, buffer + cursor, len + 1 - cursor );
- cursor--;
- if ( cursor < scroll ) {
- scroll--;
- }
- }
- return;
- }
- if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home
- cursor = 0;
- scroll = 0;
- return;
- }
- if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end
- cursor = len;
- scroll = cursor - widthInChars;
- return;
- }
- //
- // ignore any other non printable chars
- //
- if ( ch < 32 ) {
- return;
- }
- if ( idKeyInput::GetOverstrikeMode() ) {
- if ( cursor == MAX_EDIT_LINE - 1 ) {
- return;
- }
- buffer[cursor] = ch;
- cursor++;
- } else { // insert mode
- if ( len == MAX_EDIT_LINE - 1 ) {
- return; // all full
- }
- memmove( buffer + cursor + 1, buffer + cursor, len + 1 - cursor );
- buffer[cursor] = ch;
- cursor++;
- }
- if ( cursor >= widthInChars ) {
- scroll++;
- }
- if ( cursor == len + 1 ) {
- buffer[cursor] = 0;
- }
- }
- /*
- ===============
- idEditField::KeyDownEvent
- ===============
- */
- void idEditField::KeyDownEvent( int key ) {
- int len;
- // shift-insert is paste
- if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && idKeyInput::IsDown( K_SHIFT ) ) {
- ClearAutoComplete();
- Paste();
- return;
- }
- len = strlen( buffer );
- if ( key == K_DEL ) {
- if ( autoComplete.length ) {
- ClearAutoComplete();
- } else if ( cursor < len ) {
- memmove( buffer + cursor, buffer + cursor + 1, len - cursor );
- }
- return;
- }
- if ( key == K_RIGHTARROW ) {
- if ( idKeyInput::IsDown( K_CTRL ) ) {
- // skip to next word
- while( ( cursor < len ) && ( buffer[ cursor ] != ' ' ) ) {
- cursor++;
- }
- while( ( cursor < len ) && ( buffer[ cursor ] == ' ' ) ) {
- cursor++;
- }
- } else {
- cursor++;
- }
- if ( cursor > len ) {
- cursor = len;
- }
- if ( cursor >= scroll + widthInChars ) {
- scroll = cursor - widthInChars + 1;
- }
- if ( autoComplete.length > 0 ) {
- autoComplete.length = cursor;
- }
- return;
- }
- if ( key == K_LEFTARROW ) {
- if ( idKeyInput::IsDown( K_CTRL ) ) {
- // skip to previous word
- while( ( cursor > 0 ) && ( buffer[ cursor - 1 ] == ' ' ) ) {
- cursor--;
- }
- while( ( cursor > 0 ) && ( buffer[ cursor - 1 ] != ' ' ) ) {
- cursor--;
- }
- } else {
- cursor--;
- }
- if ( cursor < 0 ) {
- cursor = 0;
- }
- if ( cursor < scroll ) {
- scroll = cursor;
- }
- if ( autoComplete.length ) {
- autoComplete.length = cursor;
- }
- return;
- }
- if ( key == K_HOME || ( tolower( key ) == 'a' && idKeyInput::IsDown( K_CTRL ) ) ) {
- cursor = 0;
- scroll = 0;
- if ( autoComplete.length ) {
- autoComplete.length = cursor;
- autoComplete.valid = false;
- }
- return;
- }
- if ( key == K_END || ( tolower( key ) == 'e' && idKeyInput::IsDown( K_CTRL ) ) ) {
- cursor = len;
- if ( cursor >= scroll + widthInChars ) {
- scroll = cursor - widthInChars + 1;
- }
- if ( autoComplete.length ) {
- autoComplete.length = cursor;
- autoComplete.valid = false;
- }
- return;
- }
- if ( key == K_INS ) {
- idKeyInput::SetOverstrikeMode( !idKeyInput::GetOverstrikeMode() );
- return;
- }
- // clear autocompletion buffer on normal key input
- if ( key != K_CAPSLOCK && key != K_ALT && key != K_CTRL && key != K_SHIFT ) {
- ClearAutoComplete();
- }
- }
- /*
- ===============
- idEditField::Paste
- ===============
- */
- void idEditField::Paste( void ) {
- char *cbd;
- int pasteLen, i;
- cbd = Sys_GetClipboardData();
- if ( !cbd ) {
- return;
- }
- // send as if typed, so insert / overstrike works properly
- pasteLen = strlen( cbd );
- for ( i = 0; i < pasteLen; i++ ) {
- CharEvent( cbd[i] );
- }
- Mem_Free( cbd );
- }
- /*
- ===============
- idEditField::GetBuffer
- ===============
- */
- char *idEditField::GetBuffer( void ) {
- return buffer;
- }
- /*
- ===============
- idEditField::SetBuffer
- ===============
- */
- void idEditField::SetBuffer( const char *buf ) {
- Clear();
- idStr::Copynz( buffer, buf, sizeof( buffer ) );
- SetCursor( strlen( buffer ) );
- }
- /*
- ===============
- idEditField::Draw
- ===============
- */
- void idEditField::Draw( int x, int y, int width, bool showCursor, const idMaterial *shader ) {
- int len;
- int drawLen;
- int prestep;
- int cursorChar;
- char str[MAX_EDIT_LINE];
- int size;
- size = SMALLCHAR_WIDTH;
- drawLen = widthInChars;
- len = strlen( buffer ) + 1;
- // guarantee that cursor will be visible
- if ( len <= drawLen ) {
- prestep = 0;
- } else {
- if ( scroll + drawLen > len ) {
- scroll = len - drawLen;
- if ( scroll < 0 ) {
- scroll = 0;
- }
- }
- prestep = scroll;
- // Skip color code
- if ( idStr::IsColor( buffer + prestep ) ) {
- prestep += 2;
- }
- if ( prestep > 0 && idStr::IsColor( buffer + prestep - 1 ) ) {
- prestep++;
- }
- }
- if ( prestep + drawLen > len ) {
- drawLen = len - prestep;
- }
- // extract <drawLen> characters from the field at <prestep>
- if ( drawLen >= MAX_EDIT_LINE ) {
- common->Error( "drawLen >= MAX_EDIT_LINE" );
- }
- memcpy( str, buffer + prestep, drawLen );
- str[ drawLen ] = 0;
- // draw it
- renderSystem->DrawSmallStringExt( x, y, str, colorWhite, false, shader );
- // draw the cursor
- if ( !showCursor ) {
- return;
- }
- if ( (int)( com_ticNumber >> 4 ) & 1 ) {
- return; // off blink
- }
- if ( idKeyInput::GetOverstrikeMode() ) {
- cursorChar = 11;
- } else {
- cursorChar = 10;
- }
- // Move the cursor back to account for color codes
- for ( int i = 0; i<cursor; i++ ) {
- if ( idStr::IsColor( &str[i] ) ) {
- i++;
- prestep += 2;
- }
- }
- renderSystem->DrawSmallChar( x + ( cursor - prestep ) * size, y, cursorChar, shader );
- }
|