Files
fs2open.github.com/code/ui/inputbox.cpp
T
Zacam 4952b70488 Trunk Sync - r10911
There are a lot of changes here that should probably be examined, namely the Debug Console (which had conflicts) and Yarn's "any resolution" mainhalls code (Which also had conflicts) but for the most part this should be fairly clean.

git-svn-id: svn://svn.icculus.org/fs2open/branches/antipodes@10912 387891d4-d844-0410-90c0-e4c51a9137d3
2014-09-11 19:22:13 +10:00

486 lines
10 KiB
C++

/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
#include <ctype.h>
#include "ui/uidefs.h"
#include "ui/ui.h"
#include "bmpman/bmpman.h"
#include "io/timer.h"
#include "globalincs/alphacolors.h"
#define INPUTBOX_PASSWD_CHAR '*' // the password protected char
// Retuen true if c is a letter, else return false.
int is_letter(char c)
{
return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
}
// if the passed key is keypad number, return the ascii value, otherwise -1
int keypad_to_ascii(int c)
{
switch(c){
case KEY_PAD0:
case KEY_PAD1:
case KEY_PAD2:
case KEY_PAD3:
case KEY_PAD4:
case KEY_PAD5:
case KEY_PAD6:
case KEY_PAD7:
case KEY_PAD8:
case KEY_PAD9:
case KEY_PADPERIOD:
return key_to_ascii(c);
break;
default :
return -1;
break;
}
}
// insert character c into string s at position p.
void strcins(char *s, int p, char c)
{
int n;
for (n=strlen(s)-p; n>=0; n-- )
*(s+p+n+1) = *(s+p+n); // Move everything over
*(s+p) = c; // then insert the character
}
// delete n character from string s starting at position p
void strndel(char *s, int p, int n)
{
for (; (*(s+p) = *(s+p+n)) != '\0'; s++ )
*(s+p+n) = '\0'; // Delete and zero fill
}
void UI_INPUTBOX::init_cursor()
{
cursor_first_frame = bm_load_animation("cursor1", &cursor_nframes, &cursor_fps);
if ( cursor_first_frame < 0 ) {
Warning(LOCATION,"Cannot load input box cursor: cursor1.ani\n");
return;
}
cursor_elapsed_time=0;
cursor_current_frame=0;
}
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)
{
int tw, th;
Assert(_text_len >= 0);
Assert((int) strlen(_text) <= _text_len);
gr_set_font(wnd->f_id);
gr_get_string_size( &tw, &th, "*" );
// check to see if the user passed in a text color otherwise use the default green color
if (clr){
text_color = clr;
} else {
text_color = &CBRIGHT;
}
base_create( wnd, UI_KIND_INPUTBOX, _x, _y, _w, th+4 );
text = (char *) vm_malloc( _text_len + 1);
// input boxes no longer use background
_flags |= UI_INPUTBOX_FLAG_NO_BACK;
// if its in "password" mode, allocate a second string
// and copy it
if (_flags & UI_INPUTBOX_FLAG_PASSWD) {
passwd_text = (char *) vm_malloc(_text_len + 1);
memset(passwd_text, INPUTBOX_PASSWD_CHAR, strlen(_text));
passwd_text[strlen(_text)] = 0;
} else {
passwd_text = NULL;
}
init_cursor();
if ( _text_len > 0 ) {
strncpy( text, _text, _text_len );
}
text[_text_len] = 0;
position = strlen(_text);
oldposition = position;
length = _text_len;
pressed_down = 0;
changed_flag = 0;
flags = _flags;
pixel_limit = pixel_lim;
locked = 0;
valid_chars = NULL;
invalid_chars = NULL;
}
void UI_INPUTBOX::set_valid_chars(char *vchars)
{
// free up any existing string
if(valid_chars != NULL){
vm_free(valid_chars);
valid_chars = NULL;
}
valid_chars = vm_strdup(vchars);
}
void UI_INPUTBOX::set_invalid_chars(char *ichars)
{
// free up any existing string
if(invalid_chars != NULL){
vm_free(invalid_chars);
invalid_chars = NULL;
}
invalid_chars = vm_strdup(ichars);
}
void UI_INPUTBOX::destroy()
{
if (text) {
vm_free(text);
text = NULL;
}
// free any valid chars
if(valid_chars != NULL){
vm_free(valid_chars);
valid_chars = NULL;
}
// free any invalid chars
if(invalid_chars != NULL){
vm_free(invalid_chars);
invalid_chars = NULL;
}
if ((flags & UI_INPUTBOX_FLAG_PASSWD) && passwd_text) {
vm_free(passwd_text);
passwd_text = NULL;
}
UI_GADGET::destroy();
}
void UI_INPUTBOX::draw()
{
int invis, w1, h1, tw, th;
int text_x, text_y;
if (hidden){
return;
}
w1 = w;
h1 = h;
invis = flags & UI_INPUTBOX_FLAG_INVIS;
gr_set_font(my_wnd->f_id);
gr_reset_clip();
if (!invis && !(flags & UI_INPUTBOX_FLAG_NO_BACK)) {
// draw the entire text box region
ui_draw_sunken_border( x-2, y-2, x+w+1, y+h+1 );
gr_set_color_fast( &CBLACK );
gr_rect( 0, 0, w, h, GR_RESIZE_MENU );
w1 -= 4;
h1 -= 4;
gr_set_clip( x + 1, y + 1, w1 + 1, h1 + 1, GR_RESIZE_MENU );
} else {
gr_set_clip( x - 1, y - 1, w1 + 1, h1 + 1, GR_RESIZE_MENU );
}
if (flags & UI_INPUTBOX_FLAG_PASSWD){
gr_get_string_size(&tw, &th, passwd_text);
} else {
gr_get_string_size(&tw, &th, text);
}
if (!disabled_flag && !(flags & UI_INPUTBOX_FLAG_NO_BACK)) {
gr_set_color_fast( &CBLACK );
// color the background behind the text
gr_rect( 0, 0, tw + 1, th, GR_RESIZE_MENU_NO_OFFSET );
}
if ( (my_wnd->selected_gadget == this) || disabled_flag ) {
gr_set_color_fast(text_color);
} else {
gr_set_color_fast(&CWHITE);
}
// coords of where to draw the text
text_x = 1;
text_y = 1;
if(flags & UI_INPUTBOX_FLAG_TEXT_CEN){
// if we fit within the text area, draw it centered
if(tw <= w1 - 5){
text_x += (w1 - tw)/2;
}
}
// draw the text
if (flags & UI_INPUTBOX_FLAG_PASSWD){
gr_string(text_x, text_y, passwd_text, GR_RESIZE_MENU);
} else {
gr_string(text_x, text_y, text, GR_RESIZE_MENU);
}
// draw the "cursor"
if (!disabled_flag) {
if (my_wnd->selected_gadget == this) {
if (cursor_first_frame == -1) {
gr_set_color_fast(text_color);
ui_vline(1, h1, text_x + tw + 4);
ui_vline(1, h1, text_x + tw + 5);
} else {
// draw animating cursor
int time_delta = timer_get_milliseconds() - cursor_elapsed_time;
if ( (time_delta / 1000.0f) > (1.0f / cursor_fps) ) {
// advance frame
cursor_elapsed_time += time_delta;
cursor_current_frame++;
if (cursor_current_frame >= cursor_nframes) {
cursor_current_frame = 0;
}
}
// draw current frame
gr_set_bitmap(cursor_first_frame + cursor_current_frame);
gr_bitmap(text_x + tw + 4, 1, GR_RESIZE_MENU_NO_OFFSET);
}
}
}
gr_reset_clip();
}
int UI_INPUTBOX::validate_input(int chr)
{
if (chr < 32) { // weed out control characters
return 0;
}
// if we're disallowing letters altogether
if((flags & UI_INPUTBOX_FLAG_NO_LETTERS) && isalpha(chr)){
return 0;
}
// if we're disallowing numbers altogether
if((flags & UI_INPUTBOX_FLAG_NO_NUMERALS) && isdigit(chr)){
return 0;
}
// otherwise allow numbers and alpha chars by
if (isdigit(chr) || isalpha(chr)){
return chr;
}
// if we have specified no valid or invalid chars, accept everything
if(!valid_chars && !invalid_chars){
return chr;
}
// otherwise compare against the valid chars list
if((valid_chars) && strchr(valid_chars, chr)){
return chr;
}
// otherwise compare against the invalid chars list0
if((invalid_chars) && !strchr(invalid_chars,chr)){
return chr;
}
return 0;
}
void UI_INPUTBOX::process(int focus)
{
int ascii, clear_lastkey, key, key_used, key_check;
// check if mouse is pressed
if (B1_PRESSED && is_mouse_on()) {
set_focus();
}
if (disabled_flag)
return;
if (my_wnd->selected_gadget == this)
focus = 1;
key_used = 0;
changed_flag = 0;
oldposition = position;
pressed_down = 0;
clear_lastkey = (flags & UI_INPUTBOX_FLAG_KEYTHRU) ? 0 : 1;
if (focus) {
key = my_wnd->keypress;
switch (key) {
case 0:
break;
//case KEY_LEFT:
case KEY_BACKSP:
if (position > 0)
position--;
text[position] = 0;
if (flags & UI_INPUTBOX_FLAG_PASSWD) {
passwd_text[position] = 0;
}
changed_flag = 1;
key_used = 1;
break;
case KEY_ENTER:
pressed_down = 1;
locked = 0;
changed_flag = 1;
key_used = 1;
break;
case KEY_ESC:
if (flags & UI_INPUTBOX_FLAG_ESC_CLR){
if (position > 0) {
set_text("");
key_used = 1;
} else {
key_used = 0;
clear_lastkey = 0;
}
}
if (flags & UI_INPUTBOX_FLAG_ESC_FOC) {
clear_focus();
}
break;
default:
if (!locked) {
// MWA -- determine if alt or ctrl held down on this key and don't process if it is. We
// need to be able to pass these keys back to the top level. (And anyway -- ctrl-a shouldn't
// print out an A in the input window
if ( key & (KEY_ALTED | KEY_CTRLED) ) {
clear_lastkey = 0;
break;
}
// get an ascii char from the input if possible
key_check = keypad_to_ascii(key);
if(key_check == -1){
key_check = key_to_ascii(key);
}
ascii = validate_input(key_check);
if ((ascii > 0) && (ascii < 255)) {
if (flags & UI_INPUTBOX_FLAG_LETTER_FIRST) {
if ((position == 0) && !is_letter((char) ascii))
break;
}
key_used = 1;
if ( position < length ) {
text[position] = (char) ascii;
text[position + 1] = 0;
if (flags & UI_INPUTBOX_FLAG_PASSWD) {
passwd_text[position] = (char) INPUTBOX_PASSWD_CHAR;
passwd_text[position + 1] = 0;
}
position++;
// check to see if we should limit by pixel width
if (pixel_limit > -1) {
int _w;
if (flags & UI_INPUTBOX_FLAG_PASSWD) {
gr_get_string_size(&_w, NULL, passwd_text);
} else {
gr_get_string_size(&_w, NULL, text);
}
if (_w > pixel_limit) {
position--;
locked = 1;
text[position] = 0;
if (flags & UI_INPUTBOX_FLAG_PASSWD) {
passwd_text[position] = 0;
}
}
}
}
changed_flag = 1;
}
}
break;
}
if (clear_lastkey || (key_used && (flags & UI_INPUTBOX_FLAG_EAT_USED)) )
my_wnd->last_keypress=0;
}
}
int UI_INPUTBOX::changed()
{
return changed_flag;
}
int UI_INPUTBOX::pressed()
{
return pressed_down;
}
void UI_INPUTBOX::get_text(char *out)
{
strncpy(out, text, length);
out[length] = 0;
}
void UI_INPUTBOX::set_text(const char *in)
{
int in_length;
in_length = strlen(in);
if (in_length > length)
Assert(0); // tried to force text into an input box that won't fit into allocated memory
strcpy(text, in);
if (flags & UI_INPUTBOX_FLAG_PASSWD) {
memset(passwd_text, INPUTBOX_PASSWD_CHAR, strlen(text));
passwd_text[strlen(text)] = 0;
}
position = in_length; // fixes the zero-length-I-don't-think-so bug
}