X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=vg_console.h;h=1024b82ac468b0b6e6c08d557e7561e965ffc387;hb=76d234b7dc5e6500e8a54009b367e7620f11ef97;hp=8d35aa286fdce8933e35b39720cd5dfd6534d850;hpb=a7938c00a8c486ad0e2a765c3092017487ba761e;p=vg.git diff --git a/vg_console.h b/vg_console.h index 8d35aa2..1024b82 100644 --- a/vg_console.h +++ b/vg_console.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */ +/* Copyright (C) 2021-2023 Harry Godden (hgn) - All Rights Reserved */ #ifndef VG_CONSOLE_H #define VG_CONSOLE_H @@ -7,256 +7,226 @@ #define VG_GAME #endif -#include "vg/vg_ui.h" +#include "vg/vg_imgui.h" #include "vg/vg_log.h" -typedef struct vg_convar vg_convar; +#define VG_VAR_F32( NAME, ... ) \ + { u32 flags=0x00; __VA_ARGS__ ;\ + vg_console_reg_var( #NAME, &NAME, k_var_dtype_f32, flags ); } + +#define VG_VAR_I32( NAME, ... ) \ + { u32 flags=0x00; __VA_ARGS__ ;\ + vg_console_reg_var( #NAME, &NAME, k_var_dtype_i32, flags ); } + +#define VG_VAR_PERSISTENT 0x1 +#define VG_VAR_CHEAT 0x2 +#define VG_VAR_CHEATTOGGLE 0x4 + +typedef struct vg_var vg_var; typedef struct vg_cmd vg_cmd; -struct vg_console -{ - struct vg_convar - { +struct vg_console{ + struct vg_var{ void *data; - void (*update)(void); const char *name; - enum vg_convar_dtype - { - k_convar_dtype_i32, - k_convar_dtype_u32, - k_convar_dtype_f32 + enum vg_var_dtype{ + k_var_dtype_i32, + k_var_dtype_u32, + k_var_dtype_f32 } data_type; - - union - { - struct - { - int min, max, clamp; - } - opt_i32; - - struct - { - float min, max; - int clamp; - } - opt_f32; - }; + u32 flags; - int persistent; /* Should this var be stored to cfg/auto.conf? */ + union{ u32 _u32; f32 _f32; i32 _i32; } defaults; } - convars[ 32 ]; + vars[ 128 ]; - struct vg_cmd - { - int (*function)( int argc, char const *argv[] ); + struct vg_cmd{ + int (*function)( int argc, char const *argv[] ); + void (*poll_suggest)( int argc, char const *argv[] ); const char *name; } functions[ 32 ]; - u32 convar_count, function_count; + struct { + const char *str; + int len; + + u32 lev_score; + } + suggestions[12]; + u32 suggestion_count; + int suggestion_select, + suggestion_pastepos, + suggestion_maxlen; + + u32 var_count, function_count; - char input[96]; - int cursor_user, cursor_pos, string_length; + char input[96], + input_copy[96]; char history[32][96]; int history_last, history_pos, history_count; - int enabled; + i32 enabled, cheats; } -vg_console; +static vg_console; -VG_STATIC void vg_convar_push( struct vg_convar cv ); -VG_STATIC void vg_function_push( struct vg_cmd cmd ); - -VG_STATIC void _vg_console_draw( void ); +static void _vg_console_draw( void ); void _vg_console_println( const char *str ); -VG_STATIC int _vg_console_list( int argc, char const *argv[] ); -VG_STATIC void _vg_console_init(void); -VG_STATIC void _vg_console_write_persistent(void); -VG_STATIC void _vg_console_free(void); -VG_STATIC void vg_execute_console_input( const char *cmd ); +static int _vg_console_list( int argc, char const *argv[] ); +static void _vg_console_init(void); +static void _vg_console_write_persistent(void); +static void _vg_console_free(void); +static void vg_execute_console_input( const char *cmd ); /* * Console interface */ -VG_STATIC void console_make_selection( int* start, int* end ); -VG_STATIC void console_move_cursor( int* cursor0, int* cursor1, - int dir, int snap_together ); -VG_STATIC int console_makeroom( int datastart, int length ); -VG_STATIC int console_delete_char( int direction ); -VG_STATIC void console_to_clipboard(void); -VG_STATIC void console_clipboard_paste(void); -VG_STATIC void console_put_char( char c ); -VG_STATIC void console_history_get( char* buf, int entry_num ); -VG_STATIC int _vg_console_enabled(void); -VG_STATIC void console_proc_key( SDL_Keysym ev ); +static void console_history_get( char* buf, int entry_num ); +static int _vg_console_enabled(void); +static void console_proc_key( SDL_Keysym ev ); /* * Implementation */ -VG_STATIC int _vg_console_enabled(void) -{ +static int _vg_console_enabled(void){ return vg_console.enabled; } -VG_STATIC void vg_convar_push( vg_convar cv ) +static +void vg_console_reg_var( const char *alias, void *ptr, enum vg_var_dtype type, + u32 flags ) { - if( vg_console.convar_count > vg_list_size(vg_console.convars) ) - vg_fatal_exit_loop( "Too many convars registered" ); + if( vg_console.var_count > vg_list_size(vg_console.vars) ) + vg_fatal_error( "Too many vars registered" ); - vg_info( "Console variable '%s' registered\n", cv.name ); - vg_console.convars[ vg_console.convar_count ++ ] = cv; -} + vg_var *var = &vg_console.vars[ vg_console.var_count ++ ]; + var->name = alias; + var->data = ptr; + var->data_type = type; + var->flags = flags; -VG_STATIC void vg_function_push( struct vg_cmd cmd ) -{ - if( vg_console.function_count > vg_list_size(vg_console.functions) ) - vg_fatal_exit_loop( "Too many functions registered" ); + if ( type == k_var_dtype_f32 ) var->defaults._f32 = *((f32 *)ptr); + else if( type == k_var_dtype_i32 ) var->defaults._i32 = *((i32 *)ptr); + else if( type == k_var_dtype_u32 ) var->defaults._u32 = *((u32 *)ptr); - vg_console.functions[ vg_console.function_count ++ ] = cmd; + vg_info( "Console variable '%s' registered\n", alias ); } -VG_STATIC void _vg_console_draw( void ) +static +void vg_console_reg_cmd( const char *alias, + int (*function)(int argc, const char *argv[]), + void (*poll_suggest)(int argc, const char *argv[]) ) { - if( !vg_console.enabled ) - return; + if( vg_console.function_count > vg_list_size(vg_console.functions) ) + vg_fatal_error( "Too many functions registered" ); - SDL_AtomicLock( &log_print_sl ); + vg_cmd *cmd = &vg_console.functions[ vg_console.function_count ++ ]; - int ptr = vg_log.buffer_line_current; - int const fh = 14, - log_lines = 32; - int console_lines = VG_MIN( log_lines, vg_log.buffer_line_count ); - - vg_uictx.cursor[0] = 0; - vg_uictx.cursor[1] = 0; - vg_uictx.cursor[3] = log_lines*fh; - ui_fill_x(); - - ui_new_node(); - { - ui_fill_rect( vg_uictx.cursor, 0x77333333 ); - - vg_uictx.cursor[3] = fh; - ui_align_bottom(); - - for( int i=0; ifunction = function; + cmd->poll_suggest = poll_suggest; + cmd->name = alias; - } - ui_end_down(); - - vg_uictx.cursor[1] += 2; - vg_uictx.cursor[3] = fh; - - ui_new_node(); - { - ui_fill_rect( vg_uictx.cursor, 0x77333333 ); - ui_text( vg_uictx.cursor, vg_console.input, 1, 0 ); - - int start = VG_MIN( vg_console.cursor_pos, vg_console.cursor_user ), - end = VG_MAX( vg_console.cursor_pos, vg_console.cursor_user ); - - vg_uictx.cursor[0] = start * UI_GLYPH_SPACING_X; - vg_uictx.cursor[2] = (start == end? 0.5f: (float)(end-start)) - * (float)UI_GLYPH_SPACING_X; - - ui_fill_rect( vg_uictx.cursor, 0x66ffffff ); - } - ui_end_down(); - SDL_AtomicUnlock( &log_print_sl ); + vg_info( "Console function '%s' registered\n", alias ); } -VG_STATIC int _vg_console_list( int argc, char const *argv[] ) -{ - for( int i=0; iname ); } - for( int i=0; iname ); } return 0; } -int _test_break( int argc, const char *argv[] ) -{ - vg_fatal_exit_loop( "Test crash from main, after loading (console)" ); +int _test_break( int argc, const char *argv[] ){ + vg_fatal_error( "Test crash from main, after loading (console)" ); return 0; } -VG_STATIC void _vg_console_init(void) -{ - vg_function_push( (struct vg_cmd) - { - .name = "list", - .function = _vg_console_list - }); - - vg_function_push( (struct vg_cmd) - { - .name = "crash", - .function = _test_break - }); -} +int _vg_console_exec( int argc, const char *argv[] ){ + if( argc < 1 ) return 0; -VG_STATIC void vg_console_load_autos(void) -{ - /* Read and exec persistent commands */ - FILE *fp = fopen( "cfg/auto.conf", "r" ); - if( fp ) - { + char path[256]; + strcpy( path, "cfg/" ); + strncat( path, argv[0], 250 ); + + FILE *fp = fopen( path, "r" ); + if( fp ){ char line[256]; - while( fgets( line, sizeof( line ), fp ) ) - { + while( fgets( line, sizeof( line ), fp ) ){ line[ strcspn( line, "\r\n#" ) ] = 0x00; - if( line[0] != 0x00 ) - { + if( line[0] != 0x00 ){ vg_execute_console_input( line ); } } fclose( fp ); } + else{ + vg_error( "Could not open '%s'\n", path ); + } + + return 0; } -VG_STATIC void _vg_console_write_persistent(void) -{ +int _ccmd_vg_console_defaults( int argc, const char *argv[] ){ + for( int i=0; idata_type; + void *ptr = cv->data; + + if ( type == k_var_dtype_f32 ) *((f32 *)ptr) = cv->defaults._f32; + else if( type == k_var_dtype_i32 ) *((i32 *)ptr) = cv->defaults._i32; + else if( type == k_var_dtype_u32 ) *((u32 *)ptr) = cv->defaults._u32; + } + + return 0; +} + +static void _vg_console_init(void){ + vg_console_reg_cmd( "list", _vg_console_list, NULL ); + vg_console_reg_cmd( "crash", _test_break, NULL ); + vg_console_reg_cmd( "exec", _vg_console_exec, NULL ); + vg_console_reg_cmd( "defaults", _ccmd_vg_console_defaults, NULL ); + vg_console_reg_var( "cheats", &vg_console.cheats, k_var_dtype_i32, +#ifdef VG_DEVWINDOW + VG_VAR_PERSISTENT +#else + 0 +#endif + ); +} + +static void vg_console_load_autos(void){ + _vg_console_exec( 1, (const char *[]){ "auto.conf" } ); +} + +static void _vg_console_write_persistent(void){ FILE *fp = fopen( "cfg/auto.conf", "w" ); - for( int i=0; ipersistent ) - { - switch( cv->data_type ) - { - case k_convar_dtype_i32: + for( int i=0; iflags & VG_VAR_PERSISTENT ){ + switch( cv->data_type ){ + case k_var_dtype_i32: fprintf( fp, "%s %d\n", cv->name, *(i32 *)(cv->data) ); break; - case k_convar_dtype_u32: + case k_var_dtype_u32: fprintf( fp, "%s %u\n", cv->name, *(u32 *)(cv->data) ); break; - case k_convar_dtype_f32: + case k_var_dtype_f32: fprintf( fp, "%s %.5f\n", cv->name, *(float *)(cv->data ) ); break; } @@ -266,457 +236,523 @@ VG_STATIC void _vg_console_write_persistent(void) fclose( fp ); } -VG_STATIC void _vg_console_free(void) +static void _vg_console_free(void) { _vg_console_write_persistent(); } -VG_STATIC void vg_execute_console_input( const char *cmd ) +/* + * splits src into tokens and fills out args as pointers to those tokens + * returns number of tokens + * dst must be as long as src + */ +static int vg_console_tokenize( const char *src, char *dst, + const char *args[8] ) { - char temp[512]; - char const *args[9]; - int arg_count = 0; + int arg_count = 0, + in_token = 0; - int in_token = 0; - - /* Split string into tokens */ - for( int i = 0; i < vg_list_size( temp ); i ++ ) - { - if( cmd[i] ) - { - if( cmd[i] == ' ' || cmd[i] == '\t' ) - { - temp[i] = '\0'; + for( int i=0;; i ++ ){ + if( src[i] ){ + if( src[i] == ' ' || src[i] == '\t' ){ + if( in_token ) + dst[i] = '\0'; + in_token = 0; - if( arg_count == vg_list_size( args ) ) + if( arg_count == 8 ) break; } - else - { - temp[i] = cmd[i]; + else{ + dst[i] = src[i]; - if( !in_token ) - { - args[ arg_count ++ ] = temp + i; + if( !in_token ){ + args[ arg_count ++ ] = &dst[i]; in_token = 1; } } } - else - { - temp[i] = '\0'; + else{ + dst[i] = '\0'; break; } } - - if( arg_count == 0 ) - return; - - int data_int; - float data_float; - - for( int i=0; iname, args[0] ) ) - { - /* Cvar Matched, try get value */ - if( arg_count >= 2 ) - { - switch( cv->data_type ) - { - case k_convar_dtype_u32: - case k_convar_dtype_i32: - - data_int = atoi( args[1] ); - - *((int *)cv->data) = cv->opt_i32.clamp? - VG_MIN( VG_MAX(data_int, cv->opt_i32.min), cv->opt_i32.max ): - data_int; - - break; - case k_convar_dtype_f32: - data_float = atof( args[1] ); - *((float *)cv->data) = cv->opt_f32.clamp? - vg_minf( vg_maxf( data_float, cv->opt_f32.min), - cv->opt_f32.max ): - data_float; - break; - } - if( cv->update ) - cv->update(); - } - else - { - switch( cv->data_type ) - { - case k_convar_dtype_i32: - vg_info( "= %d\n", *((int *)cv->data) ); - break; - case k_convar_dtype_u32: - vg_info( "= %u\n", *((u32 *)cv->data) ); - break; - case k_convar_dtype_f32: - vg_info( "= %.4f\n", *((float *)cv->data) ); - break; - } - } - - return; - } - } - - /* - * Find and excecute command - */ - for( int i=0; iname, args[0] ) ) - { - cmd->function( arg_count-1, args+1 ); - return; - } - } - - vg_error( "No command/var named '%s'. Use 'list' to view all\n", args[0] ); + return arg_count; } -/* - * Console Interface - */ -VG_STATIC void console_make_selection( int* start, int* end ) +static vg_var *vg_console_match_var( const char *kw ) { - *start = VG_MIN( vg_console.cursor_pos, vg_console.cursor_user ); - *end = VG_MAX( vg_console.cursor_pos, vg_console.cursor_user ); -} + for( int i=0; iname, kw ) ){ + return cv; + } + } -VG_STATIC void console_move_cursor( int* cursor0, int* cursor1, - int dir, int snap_together ) -{ - *cursor0 = VG_MAX( 0, vg_console.cursor_user + dir ); - *cursor0 = - VG_MIN( - VG_MIN( vg_list_size( vg_console.input ), strlen( vg_console.input )), - *cursor0 ); - - if( snap_together ) - *cursor1 = *cursor0; + return NULL; } -VG_STATIC int console_makeroom( int datastart, int length ) +static vg_cmd *vg_console_match_cmd( const char *kw ) { - int move_to = VG_MIN( datastart+length, vg_list_size( vg_console.input ) ); - int move_amount = strlen( vg_console.input )-datastart; - int move_end = - VG_MIN( move_to+move_amount, vg_list_size( vg_console.input ) ); - move_amount = move_end-move_to; - - if( move_amount ) - memmove( &vg_console.input[ move_to ], - &vg_console.input[ datastart ], - move_end-move_to ); - - vg_console.input[ move_end ] = '\0'; - - return VG_MIN( length, vg_list_size( vg_console.input )-datastart ); + for( int i=0; iname, kw ) ){ + return cmd; + } + } + + return NULL; } -VG_STATIC int console_delete_char( int direction ) +static void vg_execute_console_input( const char *cmd ) { - int start, end; - console_make_selection( &start, &end ); + char temp[512]; + char const *args[8]; + int arg_count = vg_console_tokenize( cmd, temp, args ); - /* There is no selection */ - if( !(end-start) ) - { - if( direction == 1 ) end = VG_MIN( end+1, strlen( vg_console.input ) ); - else if( direction == -1 ) start = VG_MAX( start-1, 0 ); + if( arg_count == 0 ) + return; + + vg_var *cv = vg_console_match_var( args[0] ); + vg_cmd *fn = vg_console_match_cmd( args[0] ); + + assert( !(cv && fn) ); + + if( cv ){ + /* Cvar Matched, try get value */ + if( arg_count >= 2 ){ + if( cv->flags & VG_VAR_CHEAT ){ + if( !vg_console.cheats ){ + vg_error( "variable is cheat protected\n" ); + return; + } + } + + if( (cv->data_type == k_var_dtype_u32) || + (cv->data_type == k_var_dtype_i32) ) + { + int *ptr = cv->data; + *ptr = atoi( args[1] ); + + if( cv->flags & VG_VAR_CHEATTOGGLE ){ + if( *ptr ){ + _ccmd_vg_console_defaults( 0, NULL ); + } + } + } + else if( cv->data_type == k_var_dtype_f32 ){ + float *ptr = cv->data; + *ptr = atof( args[1] ); + } + } + else{ + if( cv->data_type == k_var_dtype_i32 ) + vg_info( "= %d\n", *((int *)cv->data) ); + else if( cv->data_type == k_var_dtype_u32 ) + vg_info( "= %u\n", *((u32 *)cv->data) ); + else if( cv->data_type == k_var_dtype_f32 ) + vg_info( "= %.4f\n", *((float *)cv->data) ); + } + + return; } + else if( fn ){ + fn->function( arg_count-1, args+1 ); + return; + } - /* Still no selction, no need to do anything */ - if( !(end-start) ) - return start; - - /* Copy the end->terminator to start */ - int remaining_length = strlen( vg_console.input )+1-end; - memmove( &vg_console.input[ start ], - &vg_console.input[ end ], - remaining_length ); - return start; + vg_error( "No command/var named '%s'. Use 'list' to view all\n", args[0] ); } -VG_STATIC void console_to_clipboard(void) -{ - int start, end; - console_make_selection( &start, &end ); - char buffer[512]; - - if( end-start ) - { - memcpy( buffer, &vg_console.input[ start ], end-start ); - buffer[ end-start ] = 0x00; - SDL_SetClipboardText( buffer ); - } -} +u32 str_lev_distance( const char *s1, const char *s2 ){ + u32 m = strlen( s1 ), + n = strlen( s2 ); -VG_STATIC void console_clipboard_paste(void) -{ - if( !SDL_HasClipboardText() ) - return; + if( m==0 ) return n; + if( n==0 ) return m; - char *text = SDL_GetClipboardText(); + assert( n+1 <= 256 ); - if( !text ) - return; + u32 costs[ 256 ]; - int datastart = console_delete_char( 0 ); - int length = strlen( text ); - int cpylength = console_makeroom( datastart, length ); + for( u32 k=0; k<=n; k++ ) + costs[k] = k; - memcpy( vg_console.input + datastart, text, cpylength); - console_move_cursor( &vg_console.cursor_user, - &vg_console.cursor_pos, cpylength, 1 ); - - SDL_free( text ); -} + u32 i = 0; + for( u32 i=0; i=0; j -- ) + if( score > vg_console.suggestions[j].lev_score ) + best_pos = j; - console_history_get( vg_console.input, vg_console.history_pos ); - console_move_cursor( &vg_console.cursor_user, - &vg_console.cursor_pos, - vg_list_size( vg_console.input ), 1); + /* insert if good score */ + if( best_pos < vg_list_size( vg_console.suggestions ) ){ + int start = VG_MIN( vg_console.suggestion_count, + vg_list_size( vg_console.suggestions )-1 ); + for( int j=start; j>best_pos; j -- ) + vg_console.suggestions[j] = vg_console.suggestions[j-1]; + + vg_console.suggestions[ best_pos ].str = str; + vg_console.suggestions[ best_pos ].len = strlen( str ); + vg_console.suggestions[ best_pos ].lev_score = score; + + if( vg_console.suggestion_count < + vg_list_size( vg_console.suggestions ) ) + vg_console.suggestion_count ++; + } } -VG_STATIC void _console_backspace(void) +static void console_update_suggestions(void) { - vg_console.cursor_user = console_delete_char( -1 ); - vg_console.cursor_pos = vg_console.cursor_user; + if( vg_ui.focused_control_type != k_ui_control_textbox || + vg_ui.textbuf != vg_console.input ) + return; + + vg_console.suggestion_count = 0; + vg_console.suggestion_select = -1; + vg_console.suggestion_maxlen = 0; + + /* + * - must be typing something + * - must be at the end + * - prev char must not be a whitespace + * - cursors should match + */ + + if( vg_ui.textbox.cursor_pos == 0 ) return; + if( vg_ui.textbox.cursor_pos != vg_ui.textbox.cursor_user ) return; + if( vg_console.input[ vg_ui.textbox.cursor_pos ] != '\0' ) return; + + if( (vg_console.input[ vg_ui.textbox.cursor_pos -1 ] == ' ') || + (vg_console.input[ vg_ui.textbox.cursor_pos -1 ] == '\t') ) + return; + + char temp[128]; + const char *args[8]; + + int token_count = vg_console_tokenize( vg_console.input, temp, args ); + if( !token_count ) return; + vg_console.suggestion_pastepos = args[token_count-1]-temp; + + /* Score all our commands and cvars */ + if( token_count == 1 ){ + for( int i=0; iname, args[0], 1 ); + } + + for( int i=0; iname, args[0], 1 ); + } + } + else{ + vg_cmd *cmd = vg_console_match_cmd( args[0] ); + vg_var *var = vg_console_match_var( args[0] ); + + assert( !( cmd && var ) ); + + if( cmd ) + if( cmd->poll_suggest ) + cmd->poll_suggest( token_count-1, &args[1] ); + } + + /* some post processing */ + for( int i=0; i= vg_console.suggestion_count ) + vg_console.suggestion_select = -1; + + _console_fetch_suggestion(); + } } -VG_STATIC void _console_end_select(void) +static void _console_suggest_prev(void) { - console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0 ); + if( vg_console.suggestion_count ){ + _console_suggest_store_normal(); + + vg_console.suggestion_select --; + + if( vg_console.suggestion_select < -1 ) + vg_console.suggestion_select = vg_console.suggestion_count-1; + + _console_fetch_suggestion(); + } } -VG_STATIC void _console_end(void) +static void _vg_console_on_update( char *buf, u32 len ) { - console_move_cursor( &vg_console.cursor_user, - &vg_console.cursor_pos, - vg_list_size( vg_console.input ), 1 ); + if( buf == vg_console.input ){ + console_update_suggestions(); + } } -VG_STATIC void _console_select_all(void) +static void console_history_get( char* buf, int entry_num ) { - console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0); - console_move_cursor( &vg_console.cursor_pos, NULL, -10000, 0); + if( !vg_console.history_count ) + return; + + int offset = VG_MIN( entry_num, vg_console.history_count -1 ), + pick = (vg_console.history_last - offset) % + vg_list_size( vg_console.history ); + strcpy( buf, vg_console.history[ pick ] ); } -VG_STATIC void _console_cut(void) +static void _vg_console_on_up( char *buf, u32 len ) { - console_to_clipboard(); - vg_console.cursor_user = console_delete_char(0); - vg_console.cursor_pos = vg_console.cursor_user; + if( buf == vg_console.input ){ + vg_console.history_pos = + VG_MAX + ( + 0, + VG_MIN + ( + vg_console.history_pos+1, + VG_MIN + ( + vg_list_size( vg_console.history ), + vg_console.history_count - 1 + ) + ) + ); + + console_history_get( vg_console.input, vg_console.history_pos ); + _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user, + &vg_ui.textbox.cursor_pos, + vg_list_size(vg_console.input)-1, 1); + } } -VG_STATIC void _console_enter(void) +static void _vg_console_on_down( char *buf, u32 len ) { - if( !strlen( vg_console.input ) ) - return; + if( buf == vg_console.input ){ + vg_console.history_pos = VG_MAX( 0, vg_console.history_pos-1 ); + console_history_get( vg_console.input, vg_console.history_pos ); - vg_info( "%s\n", vg_console.input ); - - if( strcmp( vg_console.input, - vg_console.history[ vg_console.history_last ]) ) - { - vg_console.history_last = ( vg_console.history_last + 1) % - vg_list_size(vg_console.history ); - vg_console.history_count = - VG_MIN( vg_list_size( vg_console.history ), - vg_console.history_count + 1 ); - strcpy( vg_console.history[ vg_console.history_last ], - vg_console.input ); + _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user, + &vg_ui.textbox.cursor_pos, + vg_list_size(vg_console.input)-1, 1 ); } - - vg_console.history_pos = -1; - vg_execute_console_input( vg_console.input ); - console_move_cursor( &vg_console.cursor_user, - &vg_console.cursor_pos, -10000, 1 ); - vg_console.input[0] = '\0'; } -VG_STATIC void console_proc_key( SDL_Keysym ev ) +static void _vg_console_on_enter( char *buf, u32 len ) { - /* Open / close console */ - if( ev.sym == SDLK_BACKQUOTE ) - { - vg_console.enabled = !vg_console.enabled; - - if( vg_console.enabled ) - SDL_StartTextInput(); - else - SDL_StopTextInput(); - } - - if( !vg_console.enabled ) return; - - struct console_mapping - { - u16 mod; - SDL_Keycode key; - - void (*handler)(void); - } - mapping[] = - { - { 0, SDLK_LEFT, _console_left }, - { KMOD_SHIFT, SDLK_LEFT, _console_left_select }, - { 0, SDLK_RIGHT, _console_right }, - { KMOD_SHIFT, SDLK_RIGHT, _console_right_select }, - { 0, SDLK_DOWN, _console_down }, - { 0, SDLK_UP, _console_up }, - { 0, SDLK_BACKSPACE, _console_backspace }, - { 0, SDLK_DELETE, _console_delete }, - { 0, SDLK_HOME, _console_home }, - { KMOD_SHIFT, SDLK_HOME, _console_home_select }, - { 0, SDLK_END, _console_end }, - { KMOD_SHIFT, SDLK_END, _console_end_select }, - { KMOD_CTRL, SDLK_a, _console_select_all }, - { KMOD_CTRL, SDLK_c, console_to_clipboard }, - { KMOD_CTRL, SDLK_x, _console_cut }, - { KMOD_CTRL, SDLK_v, console_clipboard_paste }, - { 0, SDLK_RETURN, _console_enter } - }; + if( buf == vg_console.input ){ + if( !strlen( vg_console.input ) ) + return; - for( int i=0; ikey == ev.sym ) + if( strcmp( vg_console.input, + vg_console.history[ vg_console.history_last ]) ) { - if( mk->mod == 0 ) - { - if( ev.mod == 0 ) - { - mk->handler(); - return; - } - } - else if( (ev.mod & mk->mod) == mk->mod ) - { - mk->handler(); - return; - } + vg_console.history_last = ( vg_console.history_last + 1) % + vg_list_size(vg_console.history ); + vg_console.history_count = + VG_MIN( vg_list_size( vg_console.history ), + vg_console.history_count + 1 ); + strcpy( vg_console.history[ vg_console.history_last ], + vg_console.input ); } + + vg_console.history_pos = -1; + vg_execute_console_input( vg_console.input ); + _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user, + &vg_ui.textbox.cursor_pos, -10000, 1 ); + + vg_console.input[0] = '\0'; + console_update_suggestions(); } } -VG_STATIC void console_proc_utf8( const char *text ) +static void _vg_console_draw(void) { - const char *ptr = text; + if( !vg_console.enabled ) return; + + SDL_AtomicLock( &log_print_sl ); + + int ptr = vg_log.log_line_current; + int const fh = vg_ui.font->line_height, log_lines = 32; + int console_lines = VG_MIN( log_lines, vg_log.log_line_count ); + + ui_rect rect_log = { 0, 0, vg.window_x, log_lines*fh }, + rect_input = { 0, log_lines*fh + 1, vg.window_x, fh*2 }, + rect_line = { 0, 0, vg.window_x, fh }; + + /* + * log + */ + u32 bg_colour = (ui_colour( k_ui_bg )&0x00ffffff)|0x9f000000; + + ui_fill( rect_log, bg_colour ); + rect_line[1] = rect_log[1]+rect_log[3]-fh; + + for( int i=0; ispacing*vg_console.suggestion_pastepos; + rect_suggest[1] += rect_input[3]; + rect_suggest[2] = vg_ui.font->spacing * vg_console.suggestion_maxlen; + rect_suggest[3] = vg_console.suggestion_count * fh; + + ui_fill( rect_suggest, bg_colour ); + + rect_suggest[3] = fh; + + for( int i=0; i