FS2_Open
Open source remastering of the Freespace 2 engine
inputbox.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #include <ctype.h>
13 
14 #include "bmpman/bmpman.h"
15 #include "globalincs/alphacolors.h"
16 #include "io/timer.h"
17 #include "ui/ui.h"
18 #include "ui/uidefs.h"
19 
20 
21 
22 #define INPUTBOX_PASSWD_CHAR '*' // the password protected char
23 
24 // Retuen true if c is a letter, else return false.
25 int is_letter(char c)
26 {
27  return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
28 }
29 
30 // if the passed key is keypad number, return the ascii value, otherwise -1
32 {
33  switch(c){
34  case KEY_PAD0:
35  return key_to_ascii(KEY_0);
36  break;
37  case KEY_PAD1:
38  return key_to_ascii(KEY_1);
39  break;
40  case KEY_PAD2:
41  return key_to_ascii(KEY_2);
42  break;
43  case KEY_PAD3:
44  return key_to_ascii(KEY_3);
45  break;
46  case KEY_PAD4:
47  return key_to_ascii(KEY_4);
48  break;
49  case KEY_PAD5:
50  return key_to_ascii(KEY_5);
51  break;
52  case KEY_PAD6:
53  return key_to_ascii(KEY_6);
54  break;
55  case KEY_PAD7:
56  return key_to_ascii(KEY_7);
57  break;
58  case KEY_PAD8:
59  return key_to_ascii(KEY_8);
60  break;
61  case KEY_PAD9:
62  return key_to_ascii(KEY_9);
63  break;
64  case KEY_PADPERIOD:
65  return key_to_ascii(KEY_PERIOD);
66  break;
67  default :
68  return -1;
69  break;
70  }
71 }
72 
73 // insert character c into string s at position p.
74 void strcins(char *s, int p, char c)
75 {
76  int n;
77  for (n=strlen(s)-p; n>=0; n-- )
78  *(s+p+n+1) = *(s+p+n); // Move everything over
79  *(s+p) = c; // then insert the character
80 }
81 
82 // delete n character from string s starting at position p
83 
84 void strndel(char *s, int p, int n)
85 {
86  for (; (*(s+p) = *(s+p+n)) != '\0'; s++ )
87  *(s+p+n) = '\0'; // Delete and zero fill
88 }
89 
90 void UI_INPUTBOX::init_cursor()
91 {
92  cursor_first_frame = bm_load_animation("cursor1", &cursor_nframes, &cursor_fps);
93  if ( cursor_first_frame < 0 ) {
94  Warning(LOCATION,"Cannot load input box cursor: cursor1.ani\n");
95  return;
96  }
97  cursor_elapsed_time=0;
98  cursor_current_frame=0;
99 }
100 
101 void UI_INPUTBOX::create(UI_WINDOW *wnd, int _x, int _y, int _w, int _text_len, char *_text, int _flags, int pixel_lim, color *clr)
102 {
103  int tw, th;
104 
105  Assert(_text_len >= 0);
106  Assert((int) strlen(_text) <= _text_len);
107  gr_set_font(wnd->f_id);
108  gr_get_string_size( &tw, &th, "*" );
109 
110  // check to see if the user passed in a text color otherwise use the default green color
111  if (clr){
112  text_color = clr;
113  } else {
114  text_color = &CBRIGHT;
115  }
116 
117  base_create( wnd, UI_KIND_INPUTBOX, _x, _y, _w, th+4 );
118  text = (char *) vm_malloc( _text_len + 1);
119 
120  // input boxes no longer use background
121  _flags |= UI_INPUTBOX_FLAG_NO_BACK;
122 
123  // if its in "password" mode, allocate a second string
124  // and copy it
125  if (_flags & UI_INPUTBOX_FLAG_PASSWD) {
126  passwd_text = (char *) vm_malloc(_text_len + 1);
127  memset(passwd_text, INPUTBOX_PASSWD_CHAR, strlen(_text));
128  passwd_text[strlen(_text)] = 0;
129 
130  } else {
131  passwd_text = NULL;
132  }
133 
134  init_cursor();
135 
136  if ( _text_len > 0 ) {
137  strncpy( text, _text, _text_len );
138  }
139  text[_text_len] = 0;
140  position = strlen(_text);
141  oldposition = position;
142  length = _text_len;
143  pressed_down = 0;
144  changed_flag = 0;
145  flags = _flags;
146  pixel_limit = pixel_lim;
147  locked = 0;
148  valid_chars = NULL;
149  invalid_chars = NULL;
150 }
151 
153 {
154  // free up any existing string
155  if(valid_chars != NULL){
156  vm_free(valid_chars);
157  valid_chars = NULL;
158  }
159 
160  valid_chars = vm_strdup(vchars);
161 }
162 
164 {
165  // free up any existing string
166  if(invalid_chars != NULL){
167  vm_free(invalid_chars);
168  invalid_chars = NULL;
169  }
170 
171  invalid_chars = vm_strdup(ichars);
172 }
173 
174 void UI_INPUTBOX::destroy()
175 {
176  if (text) {
177  vm_free(text);
178  text = NULL;
179  }
180 
181  // free any valid chars
182  if(valid_chars != NULL){
183  vm_free(valid_chars);
184  valid_chars = NULL;
185  }
186 
187  // free any invalid chars
188  if(invalid_chars != NULL){
189  vm_free(invalid_chars);
190  invalid_chars = NULL;
191  }
192 
193  if ((flags & UI_INPUTBOX_FLAG_PASSWD) && passwd_text) {
194  vm_free(passwd_text);
195  passwd_text = NULL;
196  }
197 
199 }
200 
201 void UI_INPUTBOX::draw()
202 {
203  int invis, w1, h1, tw, th;
204  int text_x, text_y;
205 
206  if (hidden){
207  return;
208  }
209 
210  w1 = w;
211  h1 = h;
212  invis = flags & UI_INPUTBOX_FLAG_INVIS;
213 
215  gr_reset_clip();
216  if (!invis && !(flags & UI_INPUTBOX_FLAG_NO_BACK)) {
217  // draw the entire text box region
218  ui_draw_sunken_border( x-2, y-2, x+w+1, y+h+1 );
220  gr_rect( 0, 0, w, h, GR_RESIZE_MENU );
221  w1 -= 4;
222  h1 -= 4;
223  gr_set_clip( x + 1, y + 1, w1 + 1, h1 + 1, GR_RESIZE_MENU );
224  } else {
225  gr_set_clip( x - 1, y - 1, w1 + 1, h1 + 1, GR_RESIZE_MENU );
226  }
227 
229  gr_get_string_size(&tw, &th, passwd_text);
230  } else {
231  gr_get_string_size(&tw, &th, text);
232  }
233 
234  if (!disabled_flag && !(flags & UI_INPUTBOX_FLAG_NO_BACK)) {
236 
237  // color the background behind the text
238  gr_rect( 0, 0, tw + 1, th, GR_RESIZE_MENU_NO_OFFSET );
239  }
240 
241  if ( (my_wnd->selected_gadget == this) || disabled_flag ) {
242  gr_set_color_fast(text_color);
243  } else {
245  }
246 
247  // coords of where to draw the text
248  text_x = 1;
249  text_y = 1;
251  // if we fit within the text area, draw it centered
252  if(tw <= w1 - 5){
253  text_x += (w1 - tw)/2;
254  }
255  }
256 
257  // draw the text
258  if (flags & UI_INPUTBOX_FLAG_PASSWD){
259  gr_string(text_x, text_y, passwd_text, GR_RESIZE_MENU);
260  } else {
261  gr_string(text_x, text_y, text, GR_RESIZE_MENU);
262  }
263 
264  // draw the "cursor"
265  if (!disabled_flag) {
266  if (my_wnd->selected_gadget == this) {
267  if (cursor_first_frame == -1) {
268  gr_set_color_fast(text_color);
269  ui_vline(1, h1, text_x + tw + 4);
270  ui_vline(1, h1, text_x + tw + 5);
271  } else {
272  // draw animating cursor
273  int time_delta = timer_get_milliseconds() - cursor_elapsed_time;
274 
275  if ( (time_delta / 1000.0f) > (1.0f / cursor_fps) ) {
276  // advance frame
277  cursor_elapsed_time += time_delta;
278  cursor_current_frame++;
279  if (cursor_current_frame >= cursor_nframes) {
280  cursor_current_frame = 0;
281  }
282  }
283 
284  // draw current frame
285  gr_set_bitmap(cursor_first_frame + cursor_current_frame);
286  gr_bitmap(text_x + tw + 4, 1, GR_RESIZE_MENU_NO_OFFSET);
287  }
288  }
289  }
290 
291  gr_reset_clip();
292 }
293 
294 int UI_INPUTBOX::validate_input(int chr)
295 {
296  if (chr < 32) { // weed out control characters
297  return 0;
298  }
299 
300  // if we're disallowing letters altogether
301  if((flags & UI_INPUTBOX_FLAG_NO_LETTERS) && isalpha(chr)){
302  return 0;
303  }
304 
305  // if we're disallowing numbers altogether
306  if((flags & UI_INPUTBOX_FLAG_NO_NUMERALS) && isdigit(chr)){
307  return 0;
308  }
309 
310  // otherwise allow numbers and alpha chars by
311  if (isdigit(chr) || isalpha(chr)){
312  return chr;
313  }
314 
315  // if we have specified no valid or invalid chars, accept everything
316  if(!valid_chars && !invalid_chars){
317  return chr;
318  }
319 
320  // otherwise compare against the valid chars list
321  if((valid_chars) && strchr(valid_chars, chr)){
322  return chr;
323  }
324 
325  // otherwise compare against the invalid chars list0
326  if((invalid_chars) && !strchr(invalid_chars,chr)){
327  return chr;
328  }
329 
330  return 0;
331 }
332 
333 void UI_INPUTBOX::process(int focus)
334 {
335  int ascii, clear_lastkey, key, key_used, key_check;
336 
337  // check if mouse is pressed
338  if (B1_PRESSED && is_mouse_on()) {
339  set_focus();
340  }
341 
342  if (disabled_flag)
343  return;
344 
345  if (my_wnd->selected_gadget == this)
346  focus = 1;
347 
348  key_used = 0;
349  changed_flag = 0;
350  oldposition = position;
351  pressed_down = 0;
352  clear_lastkey = (flags & UI_INPUTBOX_FLAG_KEYTHRU) ? 0 : 1;
353 
354  if (focus) {
355  key = my_wnd->keypress;
356  switch (key) {
357  case 0:
358  break;
359 
360  //case KEY_LEFT:
361  case KEY_BACKSP:
362  if (position > 0)
363  position--;
364 
365  text[position] = 0;
366  if (flags & UI_INPUTBOX_FLAG_PASSWD) {
367  passwd_text[position] = 0;
368  }
369 
370  changed_flag = 1;
371  key_used = 1;
372 
373  break;
374 
375  case KEY_ENTER:
376  pressed_down = 1;
377  locked = 0;
378  changed_flag = 1;
379  key_used = 1;
380 
381  break;
382 
383  case KEY_ESC:
385  if (position > 0) {
386  set_text("");
387  key_used = 1;
388 
389  } else {
390  key_used = 0;
391  clear_lastkey = 0;
392  }
393  }
394 
396  clear_focus();
397  }
398 
399  break;
400 
401  default:
402  if (!locked) {
403  // MWA -- determine if alt or ctrl held down on this key and don't process if it is. We
404  // need to be able to pass these keys back to the top level. (And anyway -- ctrl-a shouldn't
405  // print out an A in the input window
406  if ( key & (KEY_ALTED | KEY_CTRLED) ) {
407  clear_lastkey = 0;
408  break;
409  }
410 
411  // get an ascii char from the input if possible
412  key_check = keypad_to_ascii(key);
413  if(key_check == -1){
414  key_check = key_to_ascii(key);
415  }
416 
417  ascii = validate_input(key_check);
418  if ((ascii > 0) && (ascii < 255)) {
419 
421  if ((position == 0) && !is_letter((char) ascii))
422  break;
423  }
424 
425  key_used = 1;
426 
427  if ( position < length ) {
428  text[position] = (char) ascii;
429  text[position + 1] = 0;
430 
431  if (flags & UI_INPUTBOX_FLAG_PASSWD) {
432  passwd_text[position] = (char) INPUTBOX_PASSWD_CHAR;
433  passwd_text[position + 1] = 0;
434  }
435 
436  position++;
437 
438  // check to see if we should limit by pixel width
439  if (pixel_limit > -1) {
440  int _w;
441 
442  if (flags & UI_INPUTBOX_FLAG_PASSWD) {
443  gr_get_string_size(&_w, NULL, passwd_text);
444 
445  } else {
446  gr_get_string_size(&_w, NULL, text);
447  }
448 
449  if (_w > pixel_limit) {
450  position--;
451  locked = 1;
452  text[position] = 0;
453 
454  if (flags & UI_INPUTBOX_FLAG_PASSWD) {
455  passwd_text[position] = 0;
456  }
457  }
458  }
459  }
460 
461  changed_flag = 1;
462  }
463  }
464 
465  break;
466  }
467 
468  if (clear_lastkey || (key_used && (flags & UI_INPUTBOX_FLAG_EAT_USED)) )
470 
471  }
472 }
473 
475 {
476  return changed_flag;
477 }
478 
480 {
481  return pressed_down;
482 }
483 
484 void UI_INPUTBOX::get_text(char *out)
485 {
486  strncpy(out, text, length);
487  out[length] = 0;
488 }
489 
490 void UI_INPUTBOX::set_text(const char *in)
491 {
492  int in_length;
493 
494  in_length = strlen(in);
495  if (in_length > length)
496  Assert(0); // tried to force text into an input box that won't fit into allocated memory
497 
498  strcpy(text, in);
499 
500  if (flags & UI_INPUTBOX_FLAG_PASSWD) {
501  memset(passwd_text, INPUTBOX_PASSWD_CHAR, strlen(text));
502  passwd_text[strlen(text)] = 0;
503  }
504 
505  position = in_length; // fixes the zero-length-I-don't-think-so bug
506 }
#define KEY_0
Definition: key.h:71
void gr_rect(int x, int y, int w, int h, int resize_mode)
Definition: 2d.cpp:2068
void set_text(const char *in)
Definition: inputbox.cpp:490
#define KEY_PAD9
Definition: key.h:165
#define UI_INPUTBOX_FLAG_EAT_USED
Definition: ui.h:40
#define KEY_6
Definition: key.h:77
#define vm_free(ptr)
Definition: pstypes.h:548
#define KEY_PAD5
Definition: key.h:161
#define GR_RESIZE_MENU_NO_OFFSET
Definition: 2d.h:686
#define UI_INPUTBOX_FLAG_LETTER_FIRST
Definition: ui.h:41
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
int is_mouse_on()
Definition: gadget.cpp:371
#define KEY_5
Definition: key.h:76
#define GR_RESIZE_MENU
Definition: 2d.h:684
#define KEY_PAD8
Definition: key.h:164
#define KEY_8
Definition: key.h:79
UI_WINDOW * my_wnd
Definition: ui.h:111
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
Assert(pm!=NULL)
#define KEY_1
Definition: key.h:72
__inline void gr_string(int x, int y, const char *string, int resize_mode=GR_RESIZE_FULL)
Definition: 2d.h:769
#define UI_INPUTBOX_FLAG_NO_BACK
Definition: ui.h:45
Definition: 2d.h:95
#define KEY_PAD1
Definition: key.h:157
#define KEY_PAD4
Definition: key.h:160
void clear_focus()
Definition: gadget.cpp:328
int keypad_to_ascii(int c)
Definition: inputbox.cpp:31
void set_focus()
Definition: gadget.cpp:321
GLclampf f
Definition: Glext.h:7097
void base_create(UI_WINDOW *wnd, int _kind, int _x, int _y, int _w, int _h)
Definition: gadget.cpp:244
#define KEY_PAD0
Definition: key.h:156
int h
Definition: ui.h:79
int changed()
Definition: inputbox.cpp:474
void gr_set_color_fast(color *dst)
Definition: 2d.cpp:1197
#define UI_INPUTBOX_FLAG_ESC_FOC
Definition: ui.h:38
int key
void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha)
Definition: 2d.cpp:2105
GLuint in
Definition: Glext.h:9087
int key_to_ascii(int keycode)
Definition: key.cpp:336
int is_letter(char c)
Definition: inputbox.cpp:25
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
Loads a bitmap sequance so we can draw with it.
Definition: bmpman.cpp:1420
#define KEY_PAD7
Definition: key.h:163
__inline void gr_set_clip(int x, int y, int w, int h, int resize_mode=GR_RESIZE_FULL)
Definition: 2d.h:741
#define gr_reset_clip
Definition: 2d.h:745
virtual void destroy()
Definition: gadget.cpp:160
#define KEY_9
Definition: key.h:80
#define UI_INPUTBOX_FLAG_PASSWD
Definition: ui.h:39
int pressed()
Definition: inputbox.cpp:479
#define CWHITE
Definition: uidefs.h:25
int w
Definition: ui.h:79
void ui_draw_sunken_border(int x1, int y1, int x2, int y2)
Definition: uidraw.cpp:106
#define KEY_PAD3
Definition: key.h:159
#define UI_INPUTBOX_FLAG_NO_NUMERALS
Definition: ui.h:43
#define KEY_ENTER
Definition: key.h:125
#define UI_INPUTBOX_FLAG_NO_LETTERS
Definition: ui.h:42
#define UI_INPUTBOX_FLAG_TEXT_CEN
Definition: ui.h:44
#define vm_strdup(ptr)
Definition: pstypes.h:549
GLdouble s
Definition: Glext.h:5321
#define UI_KIND_INPUTBOX
Definition: ui.h:24
void strndel(char *s, int p, int n)
Definition: inputbox.cpp:84
#define CBLACK
Definition: uidefs.h:20
#define KEY_BACKSP
Definition: key.h:126
#define KEY_7
Definition: key.h:78
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
GLclampd n
Definition: Glext.h:7286
#define CBRIGHT
Definition: uidefs.h:26
#define INPUTBOX_PASSWD_CHAR
Definition: inputbox.cpp:22
GLbitfield flags
Definition: Glext.h:6722
#define vm_malloc(size)
Definition: pstypes.h:547
#define B1_PRESSED
Definition: uidefs.h:47
int hidden
Definition: ui.h:86
int disabled_flag
Definition: ui.h:82
void ui_vline(int y1, int y2, int x)
Definition: uidraw.cpp:23
int key_check(int key)
Definition: key.cpp:689
#define KEY_PADPERIOD
Definition: key.h:168
#define KEY_ESC
Definition: key.h:124
GLubyte GLubyte GLubyte GLubyte w
Definition: Glext.h:5679
int last_keypress
Definition: ui.h:650
#define KEY_ALTED
Definition: key.h:63
#define KEY_4
Definition: key.h:75
Definition: ui.h:584
void gr_get_string_size(int *w, int *h, const char *text, int len=9999)
Definition: font.cpp:196
void set_invalid_chars(char *ichars)
Definition: inputbox.cpp:163
GLfloat GLfloat p
Definition: Glext.h:8373
#define LOCATION
Definition: pstypes.h:245
void create(UI_WINDOW *wnd, int _x, int _y, int _w, int _textlen, char *_text, int _flags=0, int pixel_lim=-1, color *clr=NULL)
Definition: inputbox.cpp:101
void strcins(char *s, int p, char c)
Definition: inputbox.cpp:74
#define UI_INPUTBOX_FLAG_INVIS
Definition: ui.h:35
#define KEY_CTRLED
Definition: key.h:64
GLenum GLuint GLenum GLsizei length
Definition: Glext.h:5156
void get_text(char *out)
Definition: inputbox.cpp:484
void gr_bitmap(int _x, int _y, int resize_mode)
Definition: 2d.cpp:1303
void set_valid_chars(char *vchars)
Definition: inputbox.cpp:152
#define KEY_PAD6
Definition: key.h:162
#define KEY_PAD2
Definition: key.h:158
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble w1
Definition: Glext.h:7779
void gr_set_font(int fontnum)
Definition: font.cpp:566
#define KEY_PERIOD
Definition: key.h:115
int keypress
Definition: ui.h:622
#define KEY_2
Definition: key.h:73
int timer_get_milliseconds()
Definition: timer.cpp:150
#define UI_INPUTBOX_FLAG_KEYTHRU
Definition: ui.h:36
int f_id
Definition: ui.h:603
const GLubyte * c
Definition: Glext.h:8376
#define UI_INPUTBOX_FLAG_ESC_CLR
Definition: ui.h:37
GLint y
Definition: Gl.h:1505
#define KEY_3
Definition: key.h:74
UI_GADGET * selected_gadget
Definition: ui.h:610