diff options
| author | navewindre <boneyaard@gmail.com> | 2025-09-03 20:10:09 +0200 |
|---|---|---|
| committer | navewindre <boneyaard@gmail.com> | 2025-09-03 20:10:09 +0200 |
| commit | f8b92ce3aa08b1445c9f956d8166830946562d12 (patch) | |
| tree | 94e63a5aec9f8f52b577f56799e0c9201fd976a5 /src/gui/textbox.cpp | |
a
Diffstat (limited to 'src/gui/textbox.cpp')
| -rw-r--r-- | src/gui/textbox.cpp | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp new file mode 100644 index 0000000..688450b --- /dev/null +++ b/src/gui/textbox.cpp @@ -0,0 +1,246 @@ +#include "base.h" +#include "../util/input.h" + +#include <SDL_keycode.h> + +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; +} |
