reimpliment console interface
authorhgn <hgodden00@gmail.com>
Tue, 2 Nov 2021 08:20:06 +0000 (08:20 +0000)
committerhgn <hgodden00@gmail.com>
Tue, 2 Nov 2021 08:20:06 +0000 (08:20 +0000)
vg/vg.h
vg/vg_console.h
vg/vg_input.h
vg/vg_ui.h

diff --git a/vg/vg.h b/vg/vg.h
index b0119ecf03458ac0f3c2abe0c6a3d895c04cb336..84991dbb1135754ab8519e4462df7f0465a3157d 100644 (file)
--- a/vg/vg.h
+++ b/vg/vg.h
@@ -6,6 +6,7 @@
 #include <stdint.h>
 #include <string.h>
 #include <stdarg.h>
+#include <ctype.h>
 
 #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) ) 
index 1a4813c7d7437ce1dc0ba2eebdfe6b41dcd7238c..3756897230c80d909f5293a4c788958503fb4ac4 100644 (file)
@@ -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);
+       }
+}
index 4d1ac0e31f68fbc1035ec26b2606df62165959d0..62dd4b15b39f381737d9a4f03f42da746541fd0f 100644 (file)
@@ -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 )
index 87821ec107d636662b86b36b06c63a2af1a67fa2..da50e081c3b53c39aa59297297e1340fb8946299 100644 (file)
@@ -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;