From d1f03ec872df15d17f12f3444d72e161bd73b147 Mon Sep 17 00:00:00 2001 From: hgn Date: Tue, 2 Nov 2021 08:20:06 +0000 Subject: [PATCH] reimpliment console interface --- vg/vg.h | 5 +- vg/vg_console.h | 397 +++++++++++++++++++++++++++++++++++++++++++++++- vg/vg_input.h | 8 +- vg/vg_ui.h | 2 +- 4 files changed, 400 insertions(+), 12 deletions(-) diff --git a/vg/vg.h b/vg/vg.h index b0119ec..84991db 100644 --- a/vg/vg.h +++ b/vg/vg.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "gl/glad/glad.h" #include "gl/glfw3.h" @@ -180,8 +181,8 @@ static void vg_init( int argc, char *argv[], const char *window_name ) glfwSetCursorPosCallback( vg_window, vg_mouse_callback ); glfwSetScrollCallback( vg_window, vg_scroll_callback ); - //glfwSetCharCallback( vg_window, console_proc_wchar ); - //glfwSetKeyCallback( vg_window, console_proc_key ); + glfwSetCharCallback( vg_window, console_proc_wchar ); + glfwSetKeyCallback( vg_window, console_proc_key ); //glfwSetInputMode(vg_window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); if( !gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) ) diff --git a/vg/vg_console.h b/vg/vg_console.h index 1a4813c..3756897 100644 --- a/vg/vg_console.h +++ b/vg/vg_console.h @@ -12,13 +12,32 @@ struct vg_console k_convar_dtype_f32 } data_type; + + union + { + struct + { + int min, max, clamp; + } opt_i32; + }; } *convars; char lines[16][512]; u32 current, len; + + char input[512]; + int cursor_user, cursor_pos, string_length; + + char history[32][512]; + int history_last, history_pos, history_count; + + int enabled; + int scale; } -vg_console; +vg_console = { .scale = 1 }; + +static int vg_console_enabled(void) { return vg_console.enabled; } static void vg_convar_push( struct vg_convar cv ) { @@ -26,7 +45,10 @@ static void vg_convar_push( struct vg_convar cv ) } static void vg_console_draw( void ) -{ +{ + if( !vg_console.enabled ) + return; + int ptr = vg_console.current - vg_console.len; if( ptr <= 0 ) ptr += vg_list_size( vg_console.lines ); @@ -34,20 +56,20 @@ static void vg_console_draw( void ) ui_global_ctx.cursor[0] = 0; ui_global_ctx.cursor[1] = 0; - ui_global_ctx.cursor[3] = vg_console.len*8; + ui_global_ctx.cursor[3] = vg_console.len*8*vg_console.scale; ui_fill_x( &ui_global_ctx ); ui_new_node( &ui_global_ctx ); { ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0x77333333 ); - ui_global_ctx.cursor[3] = 8; + ui_global_ctx.cursor[3] = 8*vg_console.scale; ui_align_bottom( &ui_global_ctx ); for( int i = 0; i < vg_console.len; i ++ ) { - ui_text( &ui_global_ctx, vg_console.lines[ptr], 1, 0 ); - ui_global_ctx.cursor[1] -= 8; + ui_text( &ui_global_ctx, vg_console.lines[ptr], vg_console.scale, 0 ); + ui_global_ctx.cursor[1] -= 8*vg_console.scale; ptr --; if( ptr < 0 ) @@ -55,6 +77,25 @@ static void vg_console_draw( void ) } } ui_end_down( &ui_global_ctx ); + + ui_global_ctx.cursor[1] += 2; + ui_global_ctx.cursor[3] = 8*vg_console.scale; + + ui_new_node( &ui_global_ctx ); + { + ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0x77333333 ); + + ui_text( &ui_global_ctx, vg_console.input, vg_console.scale, 0 ); + + int start = VG_MIN( vg_console.cursor_pos, vg_console.cursor_user ), + end = VG_MAX( vg_console.cursor_pos, vg_console.cursor_user ); + + ui_global_ctx.cursor[0] = start * 6 * vg_console.scale; + ui_global_ctx.cursor[2] = (start == end? 1: (end-start)) * 6 * vg_console.scale; + + ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0x66ffffff ); + } + ui_end_down( &ui_global_ctx ); } void vg_console_println( const char *str ) @@ -71,9 +112,353 @@ void vg_console_println( const char *str ) static void vg_console_init(void) { vg_log_callback = vg_console_println; + + vg_convar_push( (struct vg_convar) + { .name = "console_scale", .data = &vg_console.scale, .data_type = k_convar_dtype_i32, + .opt_i32 = { .clamp = 1, .min = 1, .max = 7 } } ); } static void vg_console_free(void) { arrfree( vg_console.convars ); } + +// Returns advance amount +static int console_token_read( char *buf, int buf_len, const char *src ) +{ + int wait_for_next = 0; + + for( int i = 0; i < buf_len; i ++ ) + { + if( src[i] ) + { + if( isspace( src[i] ) ) + { + buf[i] = '\0'; + wait_for_next = 1; + } + else + { + if( wait_for_next ) + return i; + + buf[i] = src[i]; + } + } + else + { + buf[i] = '\0'; + return i; + } + } + + return 0; +} + +static void execute_console_input( const char *cmd ) +{ + char temp[512]; + int cmd_pos = console_token_read( temp, 512, cmd ); + + int data_int; + + for( int i = 0; i < arrlen( vg_console.convars ); i ++ ) + { + struct vg_convar *cv = &vg_console.convars[ i ]; + if( !strcmp( cv->name, temp ) ) + { + // Matched, try get value + if( console_token_read( temp, 512, cmd+cmd_pos ) ) + { + switch( cv->data_type ) + { + case k_convar_dtype_u32: + case k_convar_dtype_i32: + + data_int = atoi( temp ); + *((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: *((float *)cv->data) = atof( temp ); break; + } + } + 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; + } + } + + vg_error( "No command/variable named '%s'\n", temp ); +} + +// ============================================================================================================================= +// Console interface + +static void console_make_selection( int* start, int* end ) +{ + *start = VG_MIN( vg_console.cursor_pos, vg_console.cursor_user ); + *end = VG_MAX( vg_console.cursor_pos, vg_console.cursor_user ); +} + +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; +} + +static int console_makeroom( int datastart, int length ) +{ + 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 ); +} + +static int console_delete_char( int direction ) +{ + int start, end; + console_make_selection( &start, &end ); + + // 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 ); + } + + // 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; +} + +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; + glfwSetClipboardString( NULL, buffer ); + } +} + +static void console_clipboard_paste(void) +{ + int datastart = console_delete_char(0); + const char* clipboard = glfwGetClipboardString(NULL); + int length = strlen(clipboard); + + int cpylength = console_makeroom(datastart, length); + + memcpy( vg_console.input + datastart, clipboard, cpylength); + + console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, cpylength, 1 ); +} + +static void console_put_char( char c ) +{ + if( !vg_console.enabled ) + return; + + vg_console.cursor_user = console_delete_char(0); + + if( console_makeroom( vg_console.cursor_user, 1 ) ) + vg_console.input[ vg_console.cursor_user ] = c; + + console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, 1, 1 ); +} + +static void console_add_to_history( const char* str ) +{ + if( strcmp( str, 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 ], str ); + } +} + +static void console_history_get( char* buf, int entry_num ) +{ + if( !vg_console.history_count ) + return; + + int pick = (vg_console.history_last - VG_MIN( entry_num, vg_console.history_count -1 )) % vg_list_size( vg_console.history ); + strcpy( buf, vg_console.history[ pick ] ); +} + +static void console_proc_key( GLFWwindow* ptrW, int key, int scancode, int action, int mods ) +{ + if( action ) + { + int cursor_diff = vg_console.cursor_pos - vg_console.cursor_user? 0: 1; + + if( key == GLFW_KEY_GRAVE_ACCENT ) + { + vg_console.enabled = !vg_console.enabled; + return; + } + + if( !vg_console.enabled ) + return; + + if( key == GLFW_KEY_LEFT ) + { + if( mods & GLFW_MOD_SHIFT ) // Receed secondary cursor + { + console_move_cursor( &vg_console.cursor_user, NULL, -1, 0 ); + } + else // Match and receed both cursors + { + console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, -cursor_diff, 1 ); + } + } + else if( key == GLFW_KEY_RIGHT ) // Advance secondary cursor + { + if( mods & GLFW_MOD_SHIFT ) + { + console_move_cursor( &vg_console.cursor_user, NULL, 1, 0 ); + } + else // Match and advance both cursors + { + console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, +cursor_diff, 1 ); + } + } + else if( key == GLFW_KEY_DOWN ) + { + if( mods & GLFW_MOD_SHIFT ){} + else + { + vg_console.history_pos = VG_MAX( 0, vg_console.history_pos-1 ); + 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 ); + } + } + else if( key == GLFW_KEY_UP ) + { + if( mods & GLFW_MOD_SHIFT ){} + else + { + 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 ); + console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, vg_list_size( vg_console.input ), 1); + } + } + else if( key == GLFW_KEY_BACKSPACE ) // Lookback delete + { + vg_console.cursor_user = console_delete_char( -1 ); + vg_console.cursor_pos = vg_console.cursor_user; + } + else if( key == GLFW_KEY_DELETE ) // Lookforward delete + { + vg_console.cursor_user = console_delete_char( 1 ); + vg_console.cursor_pos = vg_console.cursor_user; + } + else if( key == GLFW_KEY_HOME ) // Home key + { + if( mods & GLFW_MOD_SHIFT ) + console_move_cursor( &vg_console.cursor_user, NULL, -10000, 0 ); + else + console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, -10000, 1 ); + } + else if( key == GLFW_KEY_END ) // End key + { + if( mods & GLFW_MOD_SHIFT ) + console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0 ); + else + console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, vg_list_size( vg_console.input ), 1 ); + } + else if( key == GLFW_KEY_A ) + { + if( mods & GLFW_MOD_CONTROL ) // Select all + { + console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0); + console_move_cursor( &vg_console.cursor_pos, NULL, -10000, 0); + } + } + else if( key == GLFW_KEY_C ) // Copy + { + if( mods & GLFW_MOD_CONTROL ) + { + console_to_clipboard(); + } + } + else if( key == GLFW_KEY_X ) // Cut + { + if( mods & GLFW_MOD_CONTROL ) + { + console_to_clipboard(); + vg_console.cursor_user = console_delete_char(0); + vg_console.cursor_pos = vg_console.cursor_user; + } + } + else if( key == GLFW_KEY_V ) // Paste + { + if( mods & GLFW_MOD_CONTROL ) + { + console_clipboard_paste(); + } + } + else if( key == GLFW_KEY_ENTER ) + { + if( !strlen( vg_console.input ) ) + return; + + vg_info( "%s\n", vg_console.input ); + + console_add_to_history( vg_console.input ); + vg_console.history_pos = -1; + execute_console_input( vg_console.input ); + console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, -10000, 1 ); + vg_console.input[0] = '\0'; + } + } +} + +// Handle an OS based input of UTF32 character from the keyboard or such +static void console_proc_wchar( GLFWwindow* ptrW, u32 uWchar ) +{ + //LOG_INFO("Recieved wchar: %u\n", uWchar); + if( uWchar <= 0x7F && (char)uWchar != 0x60) + { + console_put_char((char)uWchar); + } +} diff --git a/vg/vg_input.h b/vg/vg_input.h index 4d1ac0e..62dd4b1 100644 --- a/vg/vg_input.h +++ b/vg/vg_input.h @@ -70,21 +70,23 @@ static inline struct button_binding *vg_get_button_ptr( const char *button ) } #pragma GCC diagnostic pop +static int vg_console_enabled(void); + static inline int vg_get_button( const char *button ) { - return vg_get_button_ptr( button )->value; + return vg_get_button_ptr( button )->value && !vg_console_enabled(); } static inline int vg_get_button_down( const char *button ) { struct button_binding *bind = vg_get_button_ptr( button ); - return bind->value & (bind->value ^ bind->prev); + return bind->value & (bind->value ^ bind->prev) && !vg_console_enabled(); } static inline int vg_get_button_up( const char *button ) { struct button_binding *bind = vg_get_button_ptr( button ); - return bind->prev & (bind->value ^ bind->prev); + return bind->prev & (bind->value ^ bind->prev) && !vg_console_enabled(); } static inline int key_is_keyboard( int const id ) diff --git a/vg/vg_ui.h b/vg/vg_ui.h index 87821ec..da50e08 100644 --- a/vg/vg_ui.h +++ b/vg/vg_ui.h @@ -476,7 +476,7 @@ static void ui_text( ui_ctx *ctx, const char *str, ui_px scale, int alignment ) switch( colour_id ) { case '0': current_colour = 0xffffffff; break; - case '3'|'1'<<8: current_colour = 0xff1fee20; break; + case '3'|'1'<<8: current_colour = 0xff201fee; break; case '3'|'2'<<8: current_colour = 0xff37e420; break; case '3'|'3'<<8: current_colour = 0xff0ed8e2; break; case '3'|'4'<<8: current_colour = 0xfff15010; break; -- 2.25.1