8f9020cfcf0a4d60c94933f4f664aec870483d1f
1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
38 int persistent
; /* Should this var be stored to cfg/auto.conf? */
44 int (*function
)( int argc
, char const *argv
[] );
53 int cursor_user
, cursor_pos
, string_length
;
55 char history
[32][512];
56 int history_last
, history_pos
, history_count
;
61 vg_console
= { .scale
= 1 };
63 static void vg_convar_push( struct vg_convar cv
);
64 static void vg_function_push( struct vg_cmd cmd
);
66 static void vg_console_draw( void );
67 void vg_console_println( const char *str
);
68 static int vg_console_list( int argc
, char const *argv
[] );
69 static void vg_console_init(void);
70 static void vg_console_write_persistent(void);
71 static void vg_console_free(void);
72 static void execute_console_input( const char *cmd
);
77 static void console_make_selection( int* start
, int* end
);
78 static void console_move_cursor( int* cursor0
, int* cursor1
,
79 int dir
, int snap_together
);
80 static int console_makeroom( int datastart
, int length
);
81 static int console_delete_char( int direction
);
82 static void console_to_clipboard(void);
83 static void console_clipboard_paste(void);
84 static void console_put_char( char c
);
85 static void console_history_get( char* buf
, int entry_num
);
86 static void console_proc_key( GLFWwindow
* ptrW
, int key
,
87 int scancode
, int action
, int mods
);
88 static void console_proc_wchar( GLFWwindow
* ptrW
, u32 uWchar
);
89 static int vg_console_enabled(void);
94 static int vg_console_enabled(void)
96 return vg_console
.enabled
;
99 static void vg_convar_push( struct vg_convar cv
)
101 arrpush( vg_console
.convars
, cv
);
104 static void vg_function_push( struct vg_cmd cmd
)
106 arrpush( vg_console
.functions
, cmd
);
109 static void vg_console_draw( void )
111 if( !vg_console
.enabled
)
114 int ptr
= vg_console
.current
-1;
118 ui_global_ctx
.cursor
[0] = 0;
119 ui_global_ctx
.cursor
[1] = 0;
120 ui_global_ctx
.cursor
[3] =
121 vg_list_size( vg_console
.lines
)*fh
*vg_console
.scale
;
122 ui_fill_x( &ui_global_ctx
);
124 ui_new_node( &ui_global_ctx
);
126 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x77333333 );
128 ui_global_ctx
.cursor
[3] = fh
*vg_console
.scale
;
129 ui_align_bottom( &ui_global_ctx
);
131 for( int i
= 0; i
< vg_console
.len
; i
++ )
134 ptr
= vg_list_size( vg_console
.lines
)-1;
136 ui_text( &ui_global_ctx
, ui_global_ctx
.cursor
,
137 vg_console
.lines
[ptr
], vg_console
.scale
, 0 );
138 ui_global_ctx
.cursor
[1] -= fh
*vg_console
.scale
;
143 ui_end_down( &ui_global_ctx
);
145 ui_global_ctx
.cursor
[1] += 2;
146 ui_global_ctx
.cursor
[3] = fh
*vg_console
.scale
;
148 ui_new_node( &ui_global_ctx
);
150 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x77333333 );
152 ui_text( &ui_global_ctx
, ui_global_ctx
.cursor
,
153 vg_console
.input
, vg_console
.scale
, 0 );
155 int start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
),
156 end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
158 ui_global_ctx
.cursor
[0] = (start
* UI_GLYPH_SPACING_X
* vg_console
.scale
);
159 ui_global_ctx
.cursor
[2] = (start
== end
? 0.5f
: (float)(end
-start
))
160 * (float)UI_GLYPH_SPACING_X
* (float)vg_console
.scale
;
162 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x66ffffff );
164 ui_end_down( &ui_global_ctx
);
167 void vg_console_println( const char *str
)
169 if( vg_console
.len
< vg_list_size( vg_console
.lines
) )
172 strcpy( vg_console
.lines
[ vg_console
.current
++ ], str
);
174 if( vg_console
.current
>= vg_list_size( vg_console
.lines
) )
175 vg_console
.current
= 0;
178 static int vg_console_list( int argc
, char const *argv
[] )
180 for( int i
= 0; i
< arrlen( vg_console
.functions
); i
++ )
182 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
183 vg_info( "* %s\n", cmd
->name
);
186 vg_info( "* snowsound\n" );
188 for( int i
= 0; i
< arrlen( vg_console
.convars
); i
++ )
190 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
191 vg_info( "%s\n", cv
->name
);
197 static int vg_console_chartest( int argc
, char const *argv
[] )
199 vg_info( "\"THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\"\n" );
200 vg_info( "'the quick brown fox jumps over the lazy dog'\n" );
201 vg_info( ":;!@#$%^& 0123456789 +-*/=~ ()[]{}<>\n" );
205 static void vg_console_init(void)
207 vg_log_callback
= vg_console_println
;
209 vg_convar_push( (struct vg_convar
)
210 { .name
= "console_scale", .data
= &vg_console
.scale
,
211 .data_type
= k_convar_dtype_i32
,
212 .opt_i32
= { .clamp
= 1, .min
= 1, .max
= 7 },
216 vg_function_push( (struct vg_cmd
){
218 .function
= vg_console_list
221 vg_function_push( (struct vg_cmd
){
223 .function
= vg_console_chartest
226 /* Read and exec persistent commands */
227 FILE *fp
= fopen( "cfg/auto.conf", "r" );
232 while( fgets( line
, sizeof( line
), fp
) )
234 line
[ strcspn( line
, "\r\n#" ) ] = 0x00;
236 if( line
[0] != 0x00 )
238 execute_console_input( line
);
246 static void vg_console_write_persistent(void)
248 FILE *fp
= fopen( "cfg/auto.conf", "w" );
250 for( int i
= 0; i
< arrlen( vg_console
.convars
); i
++ )
252 struct vg_convar
*cv
= &vg_console
.convars
[i
];
256 switch( cv
->data_type
)
258 case k_convar_dtype_i32
:
259 fprintf( fp
, "%s %d\n", cv
->name
, *(i32
*)(cv
->data
) );
261 case k_convar_dtype_u32
:
262 fprintf( fp
, "%s %u\n", cv
->name
, *(u32
*)(cv
->data
) );
264 case k_convar_dtype_f32
:
265 fprintf( fp
, "%s %.5f\n", cv
->name
, *(float *)(cv
->data
) );
274 static void vg_console_free(void)
276 vg_console_write_persistent();
278 arrfree( vg_console
.convars
);
279 arrfree( vg_console
.functions
);
282 static void execute_console_input( const char *cmd
)
290 /* Split string into tokens */
291 for( int i
= 0; i
< vg_list_size( temp
); i
++ )
295 if( cmd
[i
] == ' ' || cmd
[i
] == '\t' )
300 if( arg_count
== vg_list_size( args
) )
309 args
[ arg_count
++ ] = temp
+ i
;
327 for( int i
= 0; i
< arrlen( vg_console
.convars
); i
++ )
329 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
330 if( !strcmp( cv
->name
, args
[0] ) )
332 /* Cvar Matched, try get value */
335 switch( cv
->data_type
)
337 case k_convar_dtype_u32
:
338 case k_convar_dtype_i32
:
340 data_int
= atoi( args
[1] );
342 *((int *)cv
->data
) = cv
->opt_i32
.clamp
?
343 VG_MIN( VG_MAX(data_int
, cv
->opt_i32
.min
), cv
->opt_i32
.max
):
347 case k_convar_dtype_f32
:
348 data_float
= atof( args
[1] );
349 *((float *)cv
->data
) = cv
->opt_f32
.clamp
?
350 vg_minf( vg_maxf( data_float
, cv
->opt_f32
.min
), cv
->opt_f32
.max
):
360 switch( cv
->data_type
)
362 case k_convar_dtype_i32
:
363 vg_info( "= %d\n", *((int *)cv
->data
) );
365 case k_convar_dtype_u32
:
366 vg_info( "= %u\n", *((u32
*)cv
->data
) );
368 case k_convar_dtype_f32
:
369 vg_info( "= %.4f\n", *((float *)cv
->data
) );
379 * Find and excecute command
381 for( int i
= 0; i
< arrlen( vg_console
.functions
); i
++ )
383 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
384 if( !strcmp( cmd
->name
, args
[0] ) )
386 cmd
->function( arg_count
-1, args
+1 );
391 vg_error( "No command/var named '%s'. Use 'list' to view all\n", args
[0] );
397 static void console_make_selection( int* start
, int* end
)
399 *start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
);
400 *end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
403 static void console_move_cursor( int* cursor0
, int* cursor1
,
404 int dir
, int snap_together
)
406 *cursor0
= VG_MAX( 0, vg_console
.cursor_user
+ dir
);
409 VG_MIN( vg_list_size( vg_console
.input
), strlen( vg_console
.input
)),
416 static int console_makeroom( int datastart
, int length
)
418 int move_to
= VG_MIN( datastart
+length
, vg_list_size( vg_console
.input
) );
419 int move_amount
= strlen( vg_console
.input
)-datastart
;
421 VG_MIN( move_to
+move_amount
, vg_list_size( vg_console
.input
) );
422 move_amount
= move_end
-move_to
;
425 memmove( &vg_console
.input
[ move_to
],
426 &vg_console
.input
[ datastart
],
429 vg_console
.input
[ move_end
] = '\0';
431 return VG_MIN( length
, vg_list_size( vg_console
.input
)-datastart
);
434 static int console_delete_char( int direction
)
437 console_make_selection( &start
, &end
);
439 /* There is no selection */
442 if( direction
== 1 ) end
= VG_MIN( end
+1, strlen( vg_console
.input
) );
443 else if( direction
== -1 ) start
= VG_MAX( start
-1, 0 );
446 /* Still no selction, no need to do anything */
450 /* Copy the end->terminator to start */
451 int remaining_length
= strlen( vg_console
.input
)+1-end
;
452 memmove( &vg_console
.input
[ start
],
453 &vg_console
.input
[ end
],
458 static void console_to_clipboard(void)
461 console_make_selection( &start
, &end
);
466 memcpy( buffer
, &vg_console
.input
[ start
], end
-start
);
467 buffer
[ end
-start
] = 0x00;
468 glfwSetClipboardString( NULL
, buffer
);
472 static void console_clipboard_paste(void)
474 int datastart
= console_delete_char(0);
475 const char* clipboard
= glfwGetClipboardString(NULL
);
476 int length
= strlen(clipboard
);
478 int cpylength
= console_makeroom(datastart
, length
);
480 memcpy( vg_console
.input
+ datastart
, clipboard
, cpylength
);
481 console_move_cursor( &vg_console
.cursor_user
,
482 &vg_console
.cursor_pos
, cpylength
, 1 );
485 static void console_put_char( char c
)
487 if( !vg_console
.enabled
)
490 vg_console
.cursor_user
= console_delete_char(0);
492 if( console_makeroom( vg_console
.cursor_user
, 1 ) )
493 vg_console
.input
[ vg_console
.cursor_user
] = c
;
495 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, 1, 1 );
498 static void console_history_get( char* buf
, int entry_num
)
500 if( !vg_console
.history_count
)
503 int offset
= VG_MIN( entry_num
, vg_console
.history_count
-1 ),
504 pick
= (vg_console
.history_last
- offset
) %
505 vg_list_size( vg_console
.history
);
506 strcpy( buf
, vg_console
.history
[ pick
] );
509 static void console_proc_key( GLFWwindow
* ptrW
, int key
, int scancode
,
510 int action
, int mods
)
514 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
516 if( key
== GLFW_KEY_GRAVE_ACCENT
)
518 vg_console
.enabled
= !vg_console
.enabled
;
522 if( !vg_console
.enabled
)
525 if( key
== GLFW_KEY_LEFT
)
527 if( mods
& GLFW_MOD_SHIFT
) /* Receed secondary cursor */
529 console_move_cursor( &vg_console
.cursor_user
, NULL
, -1, 0 );
531 else /* Match and receed both cursors */
533 console_move_cursor( &vg_console
.cursor_user
,
534 &vg_console
.cursor_pos
, -cursor_diff
, 1 );
537 else if( key
== GLFW_KEY_RIGHT
) /* Advance secondary cursor */
539 if( mods
& GLFW_MOD_SHIFT
)
541 console_move_cursor( &vg_console
.cursor_user
, NULL
, 1, 0 );
543 else /* Match and advance both cursors */
545 console_move_cursor( &vg_console
.cursor_user
,
546 &vg_console
.cursor_pos
, +cursor_diff
, 1 );
549 else if( key
== GLFW_KEY_DOWN
)
551 if( mods
& GLFW_MOD_SHIFT
){}
554 vg_console
.history_pos
= VG_MAX( 0, vg_console
.history_pos
-1 );
555 console_history_get( vg_console
.input
, vg_console
.history_pos
);
556 console_move_cursor( &vg_console
.cursor_user
,
557 &vg_console
.cursor_pos
, vg_list_size( vg_console
.input
), 1 );
560 else if( key
== GLFW_KEY_UP
)
562 if( mods
& GLFW_MOD_SHIFT
){}
565 vg_console
.history_pos
= VG_MAX
570 vg_console
.history_pos
+1,
573 vg_list_size( vg_console
.history
),
574 vg_console
.history_count
- 1
579 console_history_get( vg_console
.input
, vg_console
.history_pos
);
580 console_move_cursor( &vg_console
.cursor_user
,
581 &vg_console
.cursor_pos
,
582 vg_list_size( vg_console
.input
), 1);
585 else if( key
== GLFW_KEY_BACKSPACE
) /* Lookback delete */
587 vg_console
.cursor_user
= console_delete_char( -1 );
588 vg_console
.cursor_pos
= vg_console
.cursor_user
;
590 else if( key
== GLFW_KEY_DELETE
) /* Lookforward delete */
592 vg_console
.cursor_user
= console_delete_char( 1 );
593 vg_console
.cursor_pos
= vg_console
.cursor_user
;
595 else if( key
== GLFW_KEY_HOME
) /* Home key */
597 if( mods
& GLFW_MOD_SHIFT
)
598 console_move_cursor( &vg_console
.cursor_user
, NULL
, -10000, 0 );
600 console_move_cursor( &vg_console
.cursor_user
,
601 &vg_console
.cursor_pos
, -10000, 1 );
603 else if( key
== GLFW_KEY_END
) /* End key */
605 if( mods
& GLFW_MOD_SHIFT
)
606 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0 );
608 console_move_cursor( &vg_console
.cursor_user
,
609 &vg_console
.cursor_pos
,
610 vg_list_size( vg_console
.input
), 1 );
612 else if( key
== GLFW_KEY_A
)
614 if( mods
& GLFW_MOD_CONTROL
) /* Select all */
616 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0);
617 console_move_cursor( &vg_console
.cursor_pos
, NULL
, -10000, 0);
620 else if( key
== GLFW_KEY_C
) /* Copy */
622 if( mods
& GLFW_MOD_CONTROL
)
624 console_to_clipboard();
627 else if( key
== GLFW_KEY_X
) /* Cut */
629 if( mods
& GLFW_MOD_CONTROL
)
631 console_to_clipboard();
632 vg_console
.cursor_user
= console_delete_char(0);
633 vg_console
.cursor_pos
= vg_console
.cursor_user
;
636 else if( key
== GLFW_KEY_V
) /* Paste */
638 if( mods
& GLFW_MOD_CONTROL
)
640 console_clipboard_paste();
643 else if( key
== GLFW_KEY_ENTER
)
645 if( !strlen( vg_console
.input
) )
648 vg_info( "%s\n", vg_console
.input
);
650 if( strcmp( vg_console
.input
,
651 vg_console
.history
[ vg_console
.history_last
]) )
653 vg_console
.history_last
= ( vg_console
.history_last
+ 1) %
654 vg_list_size(vg_console
.history
);
655 vg_console
.history_count
=
656 VG_MIN( vg_list_size( vg_console
.history
),
657 vg_console
.history_count
+ 1 );
658 strcpy( vg_console
.history
[ vg_console
.history_last
],
662 vg_console
.history_pos
= -1;
663 execute_console_input( vg_console
.input
);
664 console_move_cursor( &vg_console
.cursor_user
,
665 &vg_console
.cursor_pos
, -10000, 1 );
666 vg_console
.input
[0] = '\0';
671 /* Handle an OS based input of UTF32 character from the keyboard or such */
672 static void console_proc_wchar( GLFWwindow
* ptrW
, u32 uWchar
)
674 if( uWchar
<= 0x7F && (char)uWchar
!= 0x60)
676 console_put_char((char)uWchar
);
680 #endif /* VG_CONSOLE_H */