summaryrefslogtreecommitdiff
path: root/src/gui/textbox.cpp
diff options
context:
space:
mode:
authornavewindre <boneyaard@gmail.com>2025-09-03 20:10:09 +0200
committernavewindre <boneyaard@gmail.com>2025-09-03 20:10:09 +0200
commitf8b92ce3aa08b1445c9f956d8166830946562d12 (patch)
tree94e63a5aec9f8f52b577f56799e0c9201fd976a5 /src/gui/textbox.cpp
a
Diffstat (limited to 'src/gui/textbox.cpp')
-rw-r--r--src/gui/textbox.cpp246
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;
+}