doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
EditField.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 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.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 static autoComplete_t globalAutoComplete;
33 
34 /*
35 ===============
36 FindMatches
37 ===============
38 */
39 static void FindMatches( const char *s ) {
40  int i;
41 
42  if ( idStr::Icmpn( s, globalAutoComplete.completionString, strlen( globalAutoComplete.completionString ) ) != 0 ) {
43  return;
44  }
45  globalAutoComplete.matchCount++;
46  if ( globalAutoComplete.matchCount == 1 ) {
47  idStr::Copynz( globalAutoComplete.currentMatch, s, sizeof( globalAutoComplete.currentMatch ) );
48  return;
49  }
50 
51  // cut currentMatch to the amount common with s
52  for ( i = 0; s[i]; i++ ) {
53  if ( tolower( globalAutoComplete.currentMatch[i] ) != tolower( s[i] ) ) {
54  globalAutoComplete.currentMatch[i] = 0;
55  break;
56  }
57  }
58  globalAutoComplete.currentMatch[i] = 0;
59 }
60 
61 /*
62 ===============
63 FindIndexMatch
64 ===============
65 */
66 static void FindIndexMatch( const char *s ) {
67 
68  if ( idStr::Icmpn( s, globalAutoComplete.completionString, strlen( globalAutoComplete.completionString ) ) != 0 ) {
69  return;
70  }
71 
72  if( globalAutoComplete.findMatchIndex == globalAutoComplete.matchIndex ) {
73  idStr::Copynz( globalAutoComplete.currentMatch, s, sizeof( globalAutoComplete.currentMatch ) );
74  }
75 
76  globalAutoComplete.findMatchIndex++;
77 }
78 
79 /*
80 ===============
81 PrintMatches
82 ===============
83 */
84 static void PrintMatches( const char *s ) {
85  if ( idStr::Icmpn( s, globalAutoComplete.currentMatch, strlen( globalAutoComplete.currentMatch ) ) == 0 ) {
86  common->Printf( " %s\n", s );
87  }
88 }
89 
90 /*
91 ===============
92 PrintCvarMatches
93 ===============
94 */
95 static void PrintCvarMatches( const char *s ) {
96  if ( idStr::Icmpn( s, globalAutoComplete.currentMatch, strlen( globalAutoComplete.currentMatch ) ) == 0 ) {
97  common->Printf( " %s" S_COLOR_WHITE " = \"%s\"\n", s, cvarSystem->GetCVarString( s ) );
98  }
99 }
100 
101 /*
102 ===============
103 idEditField::idEditField
104 ===============
105 */
107  widthInChars = 0;
108  Clear();
109 }
110 
111 /*
112 ===============
113 idEditField::~idEditField
114 ===============
115 */
117 }
118 
119 /*
120 ===============
121 idEditField::Clear
122 ===============
123 */
124 void idEditField::Clear( void ) {
125  buffer[0] = 0;
126  cursor = 0;
127  scroll = 0;
128  autoComplete.length = 0;
129  autoComplete.valid = false;
130 }
131 
132 /*
133 ===============
134 idEditField::SetWidthInChars
135 ===============
136 */
138  assert( w <= MAX_EDIT_LINE );
139  widthInChars = w;
140 }
141 
142 /*
143 ===============
144 idEditField::SetCursor
145 ===============
146 */
148  assert( c <= MAX_EDIT_LINE );
149  cursor = c;
150 }
151 
152 /*
153 ===============
154 idEditField::GetCursor
155 ===============
156 */
157 int idEditField::GetCursor( void ) const {
158  return cursor;
159 }
160 
161 /*
162 ===============
163 idEditField::ClearAutoComplete
164 ===============
165 */
167  if ( autoComplete.length > 0 && autoComplete.length <= (int) strlen( buffer ) ) {
168  buffer[autoComplete.length] = '\0';
169  if ( cursor > autoComplete.length ) {
171  }
172  }
173  autoComplete.length = 0;
174  autoComplete.valid = false;
175 }
176 
177 /*
178 ===============
179 idEditField::GetAutoCompleteLength
180 ===============
181 */
183  return autoComplete.length;
184 }
185 
186 /*
187 ===============
188 idEditField::AutoComplete
189 ===============
190 */
192  char completionArgString[MAX_EDIT_LINE];
193  idCmdArgs args;
194 
195  if ( !autoComplete.valid ) {
196  args.TokenizeString( buffer, false );
198  idStr::Copynz( completionArgString, args.Args(), sizeof( completionArgString ) );
201  autoComplete.currentMatch[0] = 0;
202 
203  if ( strlen( autoComplete.completionString ) == 0 ) {
204  return;
205  }
206 
207  globalAutoComplete = autoComplete;
208 
209  cmdSystem->CommandCompletion( FindMatches );
210  cvarSystem->CommandCompletion( FindMatches );
211 
212  autoComplete = globalAutoComplete;
213 
214  if ( autoComplete.matchCount == 0 ) {
215  return; // no matches
216  }
217 
218  // when there's only one match or there's an argument
219  if ( autoComplete.matchCount == 1 || completionArgString[0] != '\0' ) {
220 
223  idStr::Append( autoComplete.completionString, sizeof( autoComplete.completionString ), completionArgString );
225 
226  globalAutoComplete = autoComplete;
227 
230 
231  autoComplete = globalAutoComplete;
232 
234 
235  if ( autoComplete.matchCount == 0 ) {
236  // no argument matches
237  idStr::Append( buffer, sizeof( buffer ), " " );
238  idStr::Append( buffer, sizeof( buffer ), completionArgString );
239  SetCursor( strlen( buffer ) );
240  return;
241  }
242  } else {
243 
244  // multiple matches, complete to shortest
246  if ( strlen( completionArgString ) ) {
247  idStr::Append( buffer, sizeof( buffer ), " " );
248  idStr::Append( buffer, sizeof( buffer ), completionArgString );
249  }
250  }
251 
252  autoComplete.length = strlen( buffer );
255 
256  common->Printf( "]%s\n", buffer );
257 
258  // run through again, printing matches
259  globalAutoComplete = autoComplete;
260 
261  cmdSystem->CommandCompletion( PrintMatches );
263  cvarSystem->CommandCompletion( PrintCvarMatches );
265 
266  } else if ( autoComplete.matchCount != 1 ) {
267 
268  // get the next match and show instead
272  }
274 
275  globalAutoComplete = autoComplete;
276 
277  cmdSystem->CommandCompletion( FindIndexMatch );
279  cvarSystem->CommandCompletion( FindIndexMatch );
281 
282  autoComplete = globalAutoComplete;
283 
284  // and print it
286  if ( autoComplete.length > (int)strlen( buffer ) ) {
287  autoComplete.length = strlen( buffer );
288  }
290  }
291 }
292 
293 /*
294 ===============
295 idEditField::CharEvent
296 ===============
297 */
298 void idEditField::CharEvent( int ch ) {
299  int len;
300 
301  if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste
302  Paste();
303  return;
304  }
305 
306  if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field
307  Clear();
308  return;
309  }
310 
311  len = strlen( buffer );
312 
313  if ( ch == 'h' - 'a' + 1 || ch == K_BACKSPACE ) { // ctrl-h is backspace
314  if ( cursor > 0 ) {
315  memmove( buffer + cursor - 1, buffer + cursor, len + 1 - cursor );
316  cursor--;
317  if ( cursor < scroll ) {
318  scroll--;
319  }
320  }
321  return;
322  }
323 
324  if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home
325  cursor = 0;
326  scroll = 0;
327  return;
328  }
329 
330  if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end
331  cursor = len;
333  return;
334  }
335 
336  //
337  // ignore any other non printable chars
338  //
339  if ( ch < 32 ) {
340  return;
341  }
342 
344  if ( cursor == MAX_EDIT_LINE - 1 ) {
345  return;
346  }
347  buffer[cursor] = ch;
348  cursor++;
349  } else { // insert mode
350  if ( len == MAX_EDIT_LINE - 1 ) {
351  return; // all full
352  }
353  memmove( buffer + cursor + 1, buffer + cursor, len + 1 - cursor );
354  buffer[cursor] = ch;
355  cursor++;
356  }
357 
358 
359  if ( cursor >= widthInChars ) {
360  scroll++;
361  }
362 
363  if ( cursor == len + 1 ) {
364  buffer[cursor] = 0;
365  }
366 }
367 
368 /*
369 ===============
370 idEditField::KeyDownEvent
371 ===============
372 */
373 void idEditField::KeyDownEvent( int key ) {
374  int len;
375 
376  // shift-insert is paste
377  if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && idKeyInput::IsDown( K_SHIFT ) ) {
379  Paste();
380  return;
381  }
382 
383  len = strlen( buffer );
384 
385  if ( key == K_DEL ) {
386  if ( autoComplete.length ) {
388  } else if ( cursor < len ) {
389  memmove( buffer + cursor, buffer + cursor + 1, len - cursor );
390  }
391  return;
392  }
393 
394  if ( key == K_RIGHTARROW ) {
395  if ( idKeyInput::IsDown( K_CTRL ) ) {
396  // skip to next word
397  while( ( cursor < len ) && ( buffer[ cursor ] != ' ' ) ) {
398  cursor++;
399  }
400 
401  while( ( cursor < len ) && ( buffer[ cursor ] == ' ' ) ) {
402  cursor++;
403  }
404  } else {
405  cursor++;
406  }
407 
408  if ( cursor > len ) {
409  cursor = len;
410  }
411 
412  if ( cursor >= scroll + widthInChars ) {
413  scroll = cursor - widthInChars + 1;
414  }
415 
416  if ( autoComplete.length > 0 ) {
418  }
419  return;
420  }
421 
422  if ( key == K_LEFTARROW ) {
423  if ( idKeyInput::IsDown( K_CTRL ) ) {
424  // skip to previous word
425  while( ( cursor > 0 ) && ( buffer[ cursor - 1 ] == ' ' ) ) {
426  cursor--;
427  }
428 
429  while( ( cursor > 0 ) && ( buffer[ cursor - 1 ] != ' ' ) ) {
430  cursor--;
431  }
432  } else {
433  cursor--;
434  }
435 
436  if ( cursor < 0 ) {
437  cursor = 0;
438  }
439  if ( cursor < scroll ) {
440  scroll = cursor;
441  }
442 
443  if ( autoComplete.length ) {
445  }
446  return;
447  }
448 
449  if ( key == K_HOME || ( tolower( key ) == 'a' && idKeyInput::IsDown( K_CTRL ) ) ) {
450  cursor = 0;
451  scroll = 0;
452  if ( autoComplete.length ) {
454  autoComplete.valid = false;
455  }
456  return;
457  }
458 
459  if ( key == K_END || ( tolower( key ) == 'e' && idKeyInput::IsDown( K_CTRL ) ) ) {
460  cursor = len;
461  if ( cursor >= scroll + widthInChars ) {
462  scroll = cursor - widthInChars + 1;
463  }
464  if ( autoComplete.length ) {
466  autoComplete.valid = false;
467  }
468  return;
469  }
470 
471  if ( key == K_INS ) {
473  return;
474  }
475 
476  // clear autocompletion buffer on normal key input
477  if ( key != K_CAPSLOCK && key != K_ALT && key != K_CTRL && key != K_SHIFT ) {
479  }
480 }
481 
482 /*
483 ===============
484 idEditField::Paste
485 ===============
486 */
487 void idEditField::Paste( void ) {
488  char *cbd;
489  int pasteLen, i;
490 
491  cbd = Sys_GetClipboardData();
492 
493  if ( !cbd ) {
494  return;
495  }
496 
497  // send as if typed, so insert / overstrike works properly
498  pasteLen = strlen( cbd );
499  for ( i = 0; i < pasteLen; i++ ) {
500  CharEvent( cbd[i] );
501  }
502 
503  Mem_Free( cbd );
504 }
505 
506 /*
507 ===============
508 idEditField::GetBuffer
509 ===============
510 */
511 char *idEditField::GetBuffer( void ) {
512  return buffer;
513 }
514 
515 /*
516 ===============
517 idEditField::SetBuffer
518 ===============
519 */
520 void idEditField::SetBuffer( const char *buf ) {
521  Clear();
522  idStr::Copynz( buffer, buf, sizeof( buffer ) );
523  SetCursor( strlen( buffer ) );
524 }
525 
526 /*
527 ===============
528 idEditField::Draw
529 ===============
530 */
531 void idEditField::Draw( int x, int y, int width, bool showCursor, const idMaterial *shader ) {
532  int len;
533  int drawLen;
534  int prestep;
535  int cursorChar;
536  char str[MAX_EDIT_LINE];
537  int size;
538 
539  size = SMALLCHAR_WIDTH;
540 
541  drawLen = widthInChars;
542  len = strlen( buffer ) + 1;
543 
544  // guarantee that cursor will be visible
545  if ( len <= drawLen ) {
546  prestep = 0;
547  } else {
548  if ( scroll + drawLen > len ) {
549  scroll = len - drawLen;
550  if ( scroll < 0 ) {
551  scroll = 0;
552  }
553  }
554  prestep = scroll;
555 
556  // Skip color code
557  if ( idStr::IsColor( buffer + prestep ) ) {
558  prestep += 2;
559  }
560  if ( prestep > 0 && idStr::IsColor( buffer + prestep - 1 ) ) {
561  prestep++;
562  }
563  }
564 
565  if ( prestep + drawLen > len ) {
566  drawLen = len - prestep;
567  }
568 
569  // extract <drawLen> characters from the field at <prestep>
570  if ( drawLen >= MAX_EDIT_LINE ) {
571  common->Error( "drawLen >= MAX_EDIT_LINE" );
572  }
573 
574  memcpy( str, buffer + prestep, drawLen );
575  str[ drawLen ] = 0;
576 
577  // draw it
578  renderSystem->DrawSmallStringExt( x, y, str, colorWhite, false, shader );
579 
580  // draw the cursor
581  if ( !showCursor ) {
582  return;
583  }
584 
585  if ( (int)( com_ticNumber >> 4 ) & 1 ) {
586  return; // off blink
587  }
588 
590  cursorChar = 11;
591  } else {
592  cursorChar = 10;
593  }
594 
595  // Move the cursor back to account for color codes
596  for ( int i = 0; i<cursor; i++ ) {
597  if ( idStr::IsColor( &str[i] ) ) {
598  i++;
599  prestep += 2;
600  }
601  }
602 
603  renderSystem->DrawSmallChar( x + ( cursor - prestep ) * size, y, cursorChar, shader );
604 }
static bool IsDown(int keyNum)
Definition: KeyInput.cpp:271
void Draw(int x, int y, int width, bool showCursor, const idMaterial *material)
Definition: EditField.cpp:531
virtual void CommandCompletion(void(*callback)(const char *s))=0
Definition: KeyInput.h:78
static int snPrintf(char *dest, int size, const char *fmt,...) id_attribute((format(printf
Definition: Str.cpp:1465
assert(prefInfo.fullscreenBtn)
char buffer[MAX_EDIT_LINE]
Definition: EditField.h:75
idCVarSystem * cvarSystem
Definition: CVarSystem.cpp:487
idVec4 colorWhite
Definition: Lib.cpp:116
int GetCursor(void) const
Definition: EditField.cpp:157
Definition: KeyInput.h:74
autoComplete_t autoComplete
Definition: EditField.h:76
void AutoComplete(void)
Definition: EditField.cpp:191
GLenum GLint GLint y
Definition: glext.h:2849
int widthInChars
Definition: EditField.h:74
idRenderSystem * renderSystem
const char * Args(int start=1, int end=-1, bool escapeArgs=false) const
Definition: CmdArgs.cpp:52
int cursor
Definition: EditField.h:72
char * GetBuffer(void)
Definition: EditField.cpp:511
void ClearAutoComplete(void)
Definition: EditField.cpp:166
volatile int com_ticNumber
Definition: Common.cpp:96
#define S_COLOR_WHITE
Definition: Str.h:102
idCmdSystem * cmdSystem
Definition: CmdSystem.cpp:116
void CharEvent(int c)
Definition: EditField.cpp:298
int findMatchIndex
Definition: EditField.h:49
virtual void DrawSmallChar(int x, int y, int ch, const idMaterial *material)=0
virtual void ArgCompletion(const char *cmdString, void(*callback)(const char *s))=0
GLdouble s
Definition: glext.h:2935
GLenum GLsizei len
Definition: glext.h:3472
GLenum GLint x
Definition: glext.h:2849
int i
Definition: process.py:33
void SetCursor(int c)
Definition: EditField.cpp:147
virtual void ArgCompletion(const char *cmdString, void(*callback)(const char *s))=0
int Icmpn(const char *text, int n) const
Definition: Str.h:672
const int SMALLCHAR_WIDTH
Definition: RenderSystem.h:146
Definition: KeyInput.h:73
const GLubyte * c
Definition: glext.h:4677
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
void Clear(void)
Definition: EditField.cpp:124
static bool GetOverstrikeMode(void)
Definition: KeyInput.cpp:253
idCommon * common
Definition: Common.cpp:206
virtual void CommandCompletion(void(*callback)(const char *s))=0
virtual void DrawSmallStringExt(int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material)=0
virtual const char * GetCVarString(const char *name) const =0
void KeyDownEvent(int key)
Definition: EditField.cpp:373
int GetAutoCompleteLength(void) const
Definition: EditField.cpp:182
GLuint buffer
Definition: glext.h:3108
static void Copynz(char *dest, const char *src, int destsize)
Definition: Str.cpp:1376
char completionString[MAX_EDIT_LINE]
Definition: EditField.h:45
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
GLenum GLsizei width
Definition: glext.h:2846
virtual void Printf(const char *fmt,...) id_attribute((format(printf
int scroll
Definition: EditField.h:73
void TokenizeString(const char *text, bool keepAsStrings)
Definition: CmdArgs.cpp:106
char currentMatch[MAX_EDIT_LINE]
Definition: EditField.h:46
void Append(const char a)
Definition: Str.h:729
Definition: KeyInput.h:70
GLsizeiptr size
Definition: glext.h:3112
void SetBuffer(const char *buffer)
Definition: EditField.cpp:520
void SetWidthInChars(int w)
Definition: EditField.cpp:137
void Paste(void)
Definition: EditField.cpp:487
const char * Argv(int arg) const
Definition: CmdArgs.h:50
const int MAX_EDIT_LINE
Definition: EditField.h:40
virtual void Error(const char *fmt,...) id_attribute((format(printf
static void SetOverstrikeMode(bool state)
Definition: KeyInput.cpp:262
char * Sys_GetClipboardData(void)
Definition: macosx_sys.mm:100
bool IsColor(void) const
Definition: Str.h:837