07a90d2416813c16d693d9609aafda80c2e44c3a
1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
26 int persistent
; // Should be stored to cfg/auto.conf
32 int (*function
)( int argc
, char const *argv
[] );
41 int cursor_user
, cursor_pos
, string_length
;
43 char history
[32][512];
44 int history_last
, history_pos
, history_count
;
49 vg_console
= { .scale
= 1 };
55 static void vg_convar_push( struct vg_convar cv
);
56 static void vg_function_push( struct vg_cmd cmd
);
58 static void vg_console_draw( void );
59 void vg_console_println( const char *str
);
60 static int vg_console_list( int argc
, char const *argv
[] );
61 static void vg_console_init(void);
62 static void vg_console_write_persistent(void);
63 static void vg_console_free(void);
64 static void execute_console_input( const char *cmd
);
69 static void console_make_selection( int* start
, int* end
);
70 static void console_move_cursor( int* cursor0
, int* cursor1
, int dir
, int snap_together
);
71 static int console_makeroom( int datastart
, int length
);
72 static int console_delete_char( int direction
);
73 static void console_to_clipboard(void);
74 static void console_clipboard_paste(void);
75 static void console_put_char( char c
);
76 static void console_history_get( char* buf
, int entry_num
);
77 static void console_proc_key( GLFWwindow
* ptrW
, int key
, int scancode
, int action
, int mods
);
78 static void console_proc_wchar( GLFWwindow
* ptrW
, u32 uWchar
);
79 static int vg_console_enabled(void);
81 // =========================================================================================================
84 static int vg_console_enabled(void)
86 return vg_console
.enabled
;
89 static void vg_convar_push( struct vg_convar cv
)
91 arrpush( vg_console
.convars
, cv
);
94 static void vg_function_push( struct vg_cmd cmd
)
96 arrpush( vg_console
.functions
, cmd
);
99 static void vg_console_draw( void )
101 if( !vg_console
.enabled
)
104 int ptr
= vg_console
.current
-1;
108 ui_global_ctx
.cursor
[0] = 0;
109 ui_global_ctx
.cursor
[1] = 0;
110 ui_global_ctx
.cursor
[3] = vg_list_size( vg_console
.lines
)*fh
*vg_console
.scale
;
111 ui_fill_x( &ui_global_ctx
);
113 ui_new_node( &ui_global_ctx
);
115 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x77333333 );
117 ui_global_ctx
.cursor
[3] = fh
*vg_console
.scale
;
118 ui_align_bottom( &ui_global_ctx
);
120 for( int i
= 0; i
< vg_console
.len
; i
++ )
123 ptr
= vg_list_size( vg_console
.lines
)-1;
125 ui_text( &ui_global_ctx
, ui_global_ctx
.cursor
, vg_console
.lines
[ptr
], vg_console
.scale
, 0 );
126 ui_global_ctx
.cursor
[1] -= fh
*vg_console
.scale
;
131 ui_end_down( &ui_global_ctx
);
133 ui_global_ctx
.cursor
[1] += 2;
134 ui_global_ctx
.cursor
[3] = fh
*vg_console
.scale
;
136 ui_new_node( &ui_global_ctx
);
138 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x77333333 );
140 ui_text( &ui_global_ctx
, ui_global_ctx
.cursor
, vg_console
.input
, vg_console
.scale
, 0 );
142 int start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
),
143 end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
145 ui_global_ctx
.cursor
[0] = (start
* UI_GLYPH_SPACING_X
* vg_console
.scale
);
146 ui_global_ctx
.cursor
[2] = (start
== end
? 0.5f
: (float)(end
-start
)) * (float)UI_GLYPH_SPACING_X
* (float)vg_console
.scale
;
148 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x66ffffff );
150 ui_end_down( &ui_global_ctx
);
153 void vg_console_println( const char *str
)
155 if( vg_console
.len
< vg_list_size( vg_console
.lines
) )
158 strcpy( vg_console
.lines
[ vg_console
.current
++ ], str
);
160 if( vg_console
.current
>= vg_list_size( vg_console
.lines
) )
161 vg_console
.current
= 0;
164 static int vg_console_list( int argc
, char const *argv
[] )
166 for( int i
= 0; i
< arrlen( vg_console
.functions
); i
++ )
168 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
169 vg_info( "* %s\n", cmd
->name
);
172 vg_info( "* snowsound\n" );
174 for( int i
= 0; i
< arrlen( vg_console
.convars
); i
++ )
176 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
177 vg_info( "%s\n", cv
->name
);
183 static int vg_console_chartest( int argc
, char const *argv
[] )
185 vg_info( "\"THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\"\n" );
186 vg_info( "'the quick brown fox jumps over the lazy dog'\n" );
187 vg_info( ":;!@#$%^& 0123456789 +-*/=~ ()[]{}<>\n" );
191 static void vg_console_init(void)
193 vg_log_callback
= vg_console_println
;
195 vg_convar_push( (struct vg_convar
)
196 { .name
= "console_scale", .data
= &vg_console
.scale
, .data_type
= k_convar_dtype_i32
,
197 .opt_i32
= { .clamp
= 1, .min
= 1, .max
= 7 } } );
199 vg_function_push( (struct vg_cmd
){
201 .function
= vg_console_list
204 vg_function_push( (struct vg_cmd
){
206 .function
= vg_console_chartest
209 // Read and exec persistent commands
210 FILE *fp
= fopen( "cfg/auto.conf", "r" );
215 while( fgets( line
, sizeof( line
), fp
) )
217 line
[ strcspn( line
, "\r\n#" ) ] = 0x00;
219 if( line
[0] != 0x00 )
221 execute_console_input( line
);
229 static void vg_console_write_persistent(void)
231 FILE *fp
= fopen( "cfg/auto.conf", "w" );
233 for( int i
= 0; i
< arrlen( vg_console
.convars
); i
++ )
235 struct vg_convar
*cv
= &vg_console
.convars
[i
];
239 switch( cv
->data_type
)
241 case k_convar_dtype_i32
:
242 fprintf( fp
, "%s %d\n", cv
->name
, *(i32
*)(cv
->data
) );
244 case k_convar_dtype_u32
:
245 fprintf( fp
, "%s %u\n", cv
->name
, *(u32
*)(cv
->data
) );
247 case k_convar_dtype_f32
:
248 fprintf( fp
, "%s %.5f\n", cv
->name
, *(float *)(cv
->data
) );
257 static void vg_console_free(void)
259 vg_console_write_persistent();
261 arrfree( vg_console
.convars
);
262 arrfree( vg_console
.functions
);
265 static void execute_console_input( const char *cmd
)
273 // Split string into tokens
274 for( int i
= 0; i
< vg_list_size( temp
); i
++ )
278 if( isspace( cmd
[i
] ) )
283 if( arg_count
== vg_list_size( args
) )
292 args
[ arg_count
++ ] = temp
+ i
;
309 for( int i
= 0; i
< arrlen( vg_console
.convars
); i
++ )
311 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
312 if( !strcmp( cv
->name
, args
[0] ) )
314 // Cvar Matched, try get value
317 switch( cv
->data_type
)
319 case k_convar_dtype_u32
:
320 case k_convar_dtype_i32
:
322 data_int
= atoi( args
[1] );
323 *((int *)cv
->data
) = cv
->opt_i32
.clamp
? VG_MIN( VG_MAX(data_int
, cv
->opt_i32
.min
), cv
->opt_i32
.max
): data_int
;
326 case k_convar_dtype_f32
: *((float *)cv
->data
) = atof( temp
); break;
331 switch( cv
->data_type
)
333 case k_convar_dtype_i32
: vg_info( "= %d\n", *((int *)cv
->data
) ); break;
334 case k_convar_dtype_u32
: vg_info( "= %u\n", *((u32
*)cv
->data
) ); break;
335 case k_convar_dtype_f32
: vg_info( "= %.4f\n", *((float *)cv
->data
) ); break;
344 for( int i
= 0; i
< arrlen( vg_console
.functions
); i
++ )
346 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
347 if( !strcmp( cmd
->name
, args
[0] ) )
350 cmd
->function( arg_count
-1, args
+1 );
355 vg_error( "No command/variable named '%s'. Use 'list' to view all\n", args
[0] );
358 // =============================================================================================================================
361 static void console_make_selection( int* start
, int* end
)
363 *start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
);
364 *end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
367 static void console_move_cursor( int* cursor0
, int* cursor1
, int dir
, int snap_together
)
369 *cursor0
= VG_MAX( 0, vg_console
.cursor_user
+ dir
);
370 *cursor0
= VG_MIN( VG_MIN( vg_list_size( vg_console
.input
), strlen( vg_console
.input
)), *cursor0
);
375 static int console_makeroom( int datastart
, int length
)
377 int move_to
= VG_MIN( datastart
+length
, vg_list_size( vg_console
.input
) );
378 int move_amount
= strlen( vg_console
.input
)-datastart
;
379 int move_end
= VG_MIN( move_to
+move_amount
, vg_list_size( vg_console
.input
) );
380 move_amount
= move_end
-move_to
;
383 memmove( &vg_console
.input
[ move_to
], &vg_console
.input
[ datastart
], move_end
-move_to
);
385 vg_console
.input
[ move_end
] = '\0';
387 return VG_MIN( length
, vg_list_size( vg_console
.input
)-datastart
);
390 static int console_delete_char( int direction
)
393 console_make_selection( &start
, &end
);
395 // There is no selection
398 if( direction
== 1 ) end
= VG_MIN( end
+1, strlen( vg_console
.input
) );
399 else if( direction
== -1 ) start
= VG_MAX( start
-1, 0 );
402 // Still no selction, no need to do anything
406 // Copy the end->terminator to start
407 int remaining_length
= strlen( vg_console
.input
)+1-end
;
408 memmove( &vg_console
.input
[ start
], &vg_console
.input
[ end
], remaining_length
);
412 static void console_to_clipboard(void)
415 console_make_selection( &start
, &end
);
420 memcpy( buffer
, &vg_console
.input
[ start
], end
-start
);
421 buffer
[ end
-start
] = 0x00;
422 glfwSetClipboardString( NULL
, buffer
);
426 static void console_clipboard_paste(void)
428 int datastart
= console_delete_char(0);
429 const char* clipboard
= glfwGetClipboardString(NULL
);
430 int length
= strlen(clipboard
);
432 int cpylength
= console_makeroom(datastart
, length
);
434 memcpy( vg_console
.input
+ datastart
, clipboard
, cpylength
);
436 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, cpylength
, 1 );
439 static void console_put_char( char c
)
441 if( !vg_console
.enabled
)
444 vg_console
.cursor_user
= console_delete_char(0);
446 if( console_makeroom( vg_console
.cursor_user
, 1 ) )
447 vg_console
.input
[ vg_console
.cursor_user
] = c
;
449 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, 1, 1 );
452 static void console_history_get( char* buf
, int entry_num
)
454 if( !vg_console
.history_count
)
457 int pick
= (vg_console
.history_last
- VG_MIN( entry_num
, vg_console
.history_count
-1 )) % vg_list_size( vg_console
.history
);
458 strcpy( buf
, vg_console
.history
[ pick
] );
461 static void console_proc_key( GLFWwindow
* ptrW
, int key
, int scancode
, int action
, int mods
)
465 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
467 if( key
== GLFW_KEY_GRAVE_ACCENT
)
469 vg_console
.enabled
= !vg_console
.enabled
;
473 if( !vg_console
.enabled
)
476 if( key
== GLFW_KEY_LEFT
)
478 if( mods
& GLFW_MOD_SHIFT
) // Receed secondary cursor
480 console_move_cursor( &vg_console
.cursor_user
, NULL
, -1, 0 );
482 else // Match and receed both cursors
484 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, -cursor_diff
, 1 );
487 else if( key
== GLFW_KEY_RIGHT
) // Advance secondary cursor
489 if( mods
& GLFW_MOD_SHIFT
)
491 console_move_cursor( &vg_console
.cursor_user
, NULL
, 1, 0 );
493 else // Match and advance both cursors
495 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, +cursor_diff
, 1 );
498 else if( key
== GLFW_KEY_DOWN
)
500 if( mods
& GLFW_MOD_SHIFT
){}
503 vg_console
.history_pos
= VG_MAX( 0, vg_console
.history_pos
-1 );
504 console_history_get( vg_console
.input
, vg_console
.history_pos
);
505 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, vg_list_size( vg_console
.input
), 1 );
508 else if( key
== GLFW_KEY_UP
)
510 if( mods
& GLFW_MOD_SHIFT
){}
513 vg_console
.history_pos
= VG_MAX
518 vg_console
.history_pos
+1,
521 vg_list_size( vg_console
.history
),
522 vg_console
.history_count
- 1
527 console_history_get( vg_console
.input
, vg_console
.history_pos
);
528 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, vg_list_size( vg_console
.input
), 1);
531 else if( key
== GLFW_KEY_BACKSPACE
) // Lookback delete
533 vg_console
.cursor_user
= console_delete_char( -1 );
534 vg_console
.cursor_pos
= vg_console
.cursor_user
;
536 else if( key
== GLFW_KEY_DELETE
) // Lookforward delete
538 vg_console
.cursor_user
= console_delete_char( 1 );
539 vg_console
.cursor_pos
= vg_console
.cursor_user
;
541 else if( key
== GLFW_KEY_HOME
) // Home key
543 if( mods
& GLFW_MOD_SHIFT
)
544 console_move_cursor( &vg_console
.cursor_user
, NULL
, -10000, 0 );
546 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, -10000, 1 );
548 else if( key
== GLFW_KEY_END
) // End key
550 if( mods
& GLFW_MOD_SHIFT
)
551 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0 );
553 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, vg_list_size( vg_console
.input
), 1 );
555 else if( key
== GLFW_KEY_A
)
557 if( mods
& GLFW_MOD_CONTROL
) // Select all
559 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0);
560 console_move_cursor( &vg_console
.cursor_pos
, NULL
, -10000, 0);
563 else if( key
== GLFW_KEY_C
) // Copy
565 if( mods
& GLFW_MOD_CONTROL
)
567 console_to_clipboard();
570 else if( key
== GLFW_KEY_X
) // Cut
572 if( mods
& GLFW_MOD_CONTROL
)
574 console_to_clipboard();
575 vg_console
.cursor_user
= console_delete_char(0);
576 vg_console
.cursor_pos
= vg_console
.cursor_user
;
579 else if( key
== GLFW_KEY_V
) // Paste
581 if( mods
& GLFW_MOD_CONTROL
)
583 console_clipboard_paste();
586 else if( key
== GLFW_KEY_ENTER
)
588 if( !strlen( vg_console
.input
) )
591 vg_info( "%s\n", vg_console
.input
);
593 if( strcmp( vg_console
.input
, vg_console
.history
[ vg_console
.history_last
]) )
595 vg_console
.history_last
= ( vg_console
.history_last
+ 1) % vg_list_size(vg_console
.history
);
596 vg_console
.history_count
= VG_MIN( vg_list_size( vg_console
.history
), vg_console
.history_count
+ 1 );
597 strcpy( vg_console
.history
[ vg_console
.history_last
], vg_console
.input
);
600 vg_console
.history_pos
= -1;
601 execute_console_input( vg_console
.input
);
602 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, -10000, 1 );
603 vg_console
.input
[0] = '\0';
608 // Handle an OS based input of UTF32 character from the keyboard or such
609 static void console_proc_wchar( GLFWwindow
* ptrW
, u32 uWchar
)
611 //LOG_INFO("Recieved wchar: %u\n", uWchar);
612 if( uWchar
<= 0x7F && (char)uWchar
!= 0x60)
614 console_put_char((char)uWchar
);