#include "base.h" #include "../util/input.h" #include const U32 TEXTBOX_TITLE_OFFSET = 15; U8 is_printable_char( U8 key ) { return key >= 32 && key < 127; } void gui_textbox_draw_newline_str( GUI_TEXTBOX* tb, I32 x, I32 y, CLR clr, I32* endposx, I32* endposy ) { char linebuf[GUI_TEXTBOX_MAX]; char* start = tb->value; I32 tw, th; for( char* c = start; !!*c; ++c ) { if( *c == '\n' ) { U32 len = (U32)( c - start ); memcpy( linebuf, start, len ); linebuf[len] = 0; gui_draw_str( x, y, ALIGN_L, FNT_JPN12, clr, linebuf ); gui_draw_get_str_bounds( &tw, &th, FNT_JPN12, linebuf ); y += th + 1; *endposx = x + tw; *endposy = y + th; if( *(c+1) == 0 ) break; start = ++c; } else if( (*c+1) == 0 ) { U32 len = (U32)( c - start ); memcpy( linebuf, start, len ); linebuf[len] = 0; gui_draw_str( x, y, ALIGN_L, FNT_JPN12, clr, linebuf ); gui_draw_get_str_bounds( &tw, &th, FNT_JPN12, linebuf ); y += th + 1; *endposx = x + tw; *endposy = y + th; break; } } } void gui_textbox_draw_blinker( GUI_TEXTBOX* tb, I32 x, I32 y, CLR clr ) { if( !tb->active ) return; if( gui_time() - tb->blinktime > 1.0f ) { tb->blink = !tb->blink; tb->blinktime = gui_time(); } if( tb->blink ) gui_draw_str( x, y, ALIGN_L, FNT_JPN12, clr, "|" ); } void gui_textbox_draw_fn( void* ptr ) { GUI_TEXTBOX* tb = (GUI_TEXTBOX*)ptr; I32 x = gui_relx( tb ); I32 y = gui_rely( tb ); gui_draw_str( x, y, ALIGN_L, FNT_JPN12, ui_clr.txt, tb->name ); y += TEXTBOX_TITLE_OFFSET; CLR col = gui_is_fg_window( tb )? ui_clr.border : ui_clr.border_inactive; gui_draw_frect( x, y, tb->w, tb->h, col ); gui_draw_frect( x+1, y+1, tb->w-2, tb->h-2, ui_clr.bg_sec ); CLR clr = tb->active? ui_clr.txt : ui_clr.txt_inactive; I32 ypos = y + 3; I32 xpos = x + 2; I32 endposx, endposy; if( tb->allow_newl ) { gui_textbox_draw_newline_str( tb, xpos, ypos, clr, &endposx, &endposy ); } else { gui_draw_str( xpos, ypos, ALIGN_L, FNT_JPN12, clr, tb->value ); I32 tw, th; gui_draw_get_str_bounds( &tw, &th, FNT_JPN12, tb->value ); endposx = xpos + tw; endposy = ypos; } gui_textbox_draw_blinker( tb, endposx, endposy, clr ); } void gui_textbox_handle_mouse( GUI_TEXTBOX* tb ) { I32 x = gui_relx( tb ); I32 y = gui_rely( tb ) + TEXTBOX_TITLE_OFFSET; I32 w = tb->w; I32 h = tb->h; U8 m1 = gui_mbutton_down( 0 ); I32 mx, my; gui_cursor_pos( &mx, &my ); U8 inbounds = mx >= x && mx <= x + w && my >= y && my <= y + h; if( m1 ) { if( inbounds ) tb->m1held = 1; else tb->active = 0; } else { if( inbounds && tb->m1held ) { tb->active = 1; tb->blink = 1; tb->blinktime = gui_time(); } tb->m1held = 0; } } void gui_textbox_loop_keys( GUI_TEXTBOX* tb ) { U32 len = strlen( tb->value ); for( U32 i = 0; i < 0xff; ++i ) { U8 key = tb->keys[i]; U8 prev = tb->prevkeys[i]; if( !key && prev && i == tb->heldkey ) tb->heldkey = 0; else if( key && !prev ) { if( is_printable_char( i ) && len < tb->maxlen - 1 ) { if( tb->keys[SDLK_LSHIFT & 0xff] || tb->keys[SDLK_RSHIFT & 0xff] ) tb->value[len] = (char)i + ('a' - 'A'); else tb->value[len] = (char)i; tb->value[++len] = 0; } else if( i == '\b' ) { if( len > 0 ) { tb->value[--len] = 0; } } else if( i == '\r' ) { if( tb->allow_newl ) { tb->value[len] = '\n'; tb->value[++len] = 0; } else { tb->active = 0; } } else { if( i == '\x1b' ) tb->active = 0; if( tb->cb ) tb->cb( tb ); continue; } tb->heldkey = i; tb->heldtime = gui_time(); if( tb->cb ) tb->cb( tb ); } } } void gui_textbox_handle_repeat( GUI_TEXTBOX* tb ) { if( !tb->heldkey ) return; F32 delta = gui_time() - tb->heldtime; if( delta <= 0.75f ) return; if( gui_time() - tb->repeattime > 0.05f ) { U32 len = strlen( tb->value ); if( is_printable_char( tb->heldkey ) && len < (tb->maxlen - 1) ) { if( tb->keys[SDLK_LSHIFT & 0xff] || tb->keys[SDLK_RSHIFT & 0xff] ) tb->value[len] = tb->heldkey + ('a' - 'A'); else tb->value[len] = tb->heldkey; tb->value[++len] = 0; if( tb->cb ) tb->cb( tb ); } else if( tb->heldkey == '\b' && len > 0 ) { tb->value[--len] = 0; if( tb->cb ) tb->cb( tb ); } tb->repeattime = gui_time(); } } void gui_textbox_handle_keyboard( GUI_TEXTBOX* tb ) { if( !tb->active ) return; memcpy( tb->prevkeys, tb->keys, 0xff ); memcpy( tb->keys, input.keys, 0xff ); gui_textbox_loop_keys( tb ); gui_textbox_handle_repeat( tb ); } void gui_textbox_input_fn( void* ptr ) { GUI_TEXTBOX* tb = (GUI_TEXTBOX*)ptr; gui_textbox_handle_mouse( tb ); gui_textbox_handle_keyboard( tb ); } GUI_TEXTBOX* gui_textbox( I32 x, I32 y, I32 w, I32 h, const char* title, U32 maxlen, U8 allow_newl ) { GUI_TEXTBOX* tb = new GUI_TEXTBOX; tb->x = x; tb->y = y; tb->w = w; tb->h = h; tb->xbound = tb->w; tb->ybound = tb->h + TEXTBOX_TITLE_OFFSET; tb->parent = _gui.cur_view; tb->draw_fn = gui_textbox_draw_fn; tb->input_fn = gui_textbox_input_fn; strcpy( tb->name, title ); tb->cb = 0; tb->active = 0; tb->m1held = 0; tb->heldkey = 0; tb->heldtime = 0; tb->repeattime = 0; tb->maxlen = maxlen; tb->allow_newl = allow_newl; memset( tb->value, 0, GUI_TEXTBOX_MAX ); memset( tb->keys, 0, 0xff ); memset( tb->prevkeys, 0, 0xff ); gui_get_view()->children.push( tb ); return tb; }