6ef2d7837774fc01f29331915e0a148e46fbd6a2
1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
42 int persistent
; /* Should this var be stored to cfg/auto.conf? */
48 int (*function
)( int argc
, char const *argv
[] );
54 int cursor_user
, cursor_pos
, string_length
;
57 int history_last
, history_pos
, history_count
;
62 vg_console
= { .scale
= 1 };
64 static void vg_convar_push( struct vg_convar cv
);
65 static void vg_function_push( struct vg_cmd cmd
);
67 static void vg_console_draw( void );
68 void vg_console_println( const char *str
);
69 static int vg_console_list( int argc
, char const *argv
[] );
70 static void vg_console_init(void);
71 static void vg_console_write_persistent(void);
72 static void vg_console_free(void);
73 static void execute_console_input( const char *cmd
);
78 static void console_make_selection( int* start
, int* end
);
79 static void console_move_cursor( int* cursor0
, int* cursor1
,
80 int dir
, int snap_together
);
81 static int console_makeroom( int datastart
, int length
);
82 static int console_delete_char( int direction
);
83 static void console_to_clipboard(void);
84 static void console_clipboard_paste(void);
85 static void console_put_char( char c
);
86 static void console_history_get( char* buf
, int entry_num
);
87 static void console_proc_key( GLFWwindow
* ptrW
, int key
,
88 int scancode
, int action
, int mods
);
89 static void console_proc_wchar( GLFWwindow
* ptrW
, u32 uWchar
);
90 static int vg_console_enabled(void);
95 static int vg_console_enabled(void)
97 return vg_console
.enabled
;
100 static void vg_convar_push( struct vg_convar cv
)
102 arrpush( vg_console
.convars
, cv
);
105 static void vg_function_push( struct vg_cmd cmd
)
107 arrpush( vg_console
.functions
, cmd
);
110 static void vg_console_draw( void )
112 if( !vg_console
.enabled
)
115 vg_mutex_lock( &log_print_mutex
);
117 int ptr
= vg_log
.buffer_line_current
;
119 int console_lines
= VG_MIN( 16, vg_log
.buffer_line_count
);
121 ui_global_ctx
.cursor
[0] = 0;
122 ui_global_ctx
.cursor
[1] = 0;
123 ui_global_ctx
.cursor
[3] = 16*fh
*vg_console
.scale
;
124 ui_fill_x( &ui_global_ctx
);
126 ui_new_node( &ui_global_ctx
);
128 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x77333333 );
130 ui_global_ctx
.cursor
[3] = fh
*vg_console
.scale
;
131 ui_align_bottom( &ui_global_ctx
);
133 for( int i
=0; i
<console_lines
; i
++ )
138 ptr
= vg_list_size( vg_log
.buffer
)-1;
140 ui_text( &ui_global_ctx
, ui_global_ctx
.cursor
,
141 vg_log
.buffer
[ptr
], vg_console
.scale
, 0 );
142 ui_global_ctx
.cursor
[1] -= fh
*vg_console
.scale
;
146 ui_end_down( &ui_global_ctx
);
148 ui_global_ctx
.cursor
[1] += 2;
149 ui_global_ctx
.cursor
[3] = fh
*vg_console
.scale
;
151 ui_new_node( &ui_global_ctx
);
153 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x77333333 );
155 ui_text( &ui_global_ctx
, ui_global_ctx
.cursor
,
156 vg_console
.input
, vg_console
.scale
, 0 );
158 int start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
),
159 end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
161 ui_global_ctx
.cursor
[0] = (start
* UI_GLYPH_SPACING_X
* vg_console
.scale
);
162 ui_global_ctx
.cursor
[2] = (start
== end
? 0.5f
: (float)(end
-start
))
163 * (float)UI_GLYPH_SPACING_X
* (float)vg_console
.scale
;
165 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x66ffffff );
167 ui_end_down( &ui_global_ctx
);
168 vg_mutex_unlock( &log_print_mutex
);
171 static int vg_console_list( int argc
, char const *argv
[] )
173 for( int i
= 0; i
< arrlen( vg_console
.functions
); i
++ )
175 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
176 vg_info( "* %s\n", cmd
->name
);
179 vg_info( "* snowsound\n" );
181 for( int i
= 0; i
< arrlen( vg_console
.convars
); i
++ )
183 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
184 vg_info( "%s\n", cv
->name
);
190 static int vg_console_chartest( int argc
, char const *argv
[] )
192 vg_info(" Copyright . . . -----, ,----- ,---. .---. " );
193 vg_info(" 2021-2022 |\\ /| | / | | | | /| " );
194 vg_info(" | \\ / | +-- / +----- +---' | / | " );
195 vg_info(" | \\ / | | / | | \\ | / | " );
196 vg_info(" | \\/ | | / | | \\ | / | " );
197 vg_info(" ' ' '--' [] '----- '----- ' ' '---' "
200 vg_info( "\"THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\"\n" );
201 vg_info( "'the quick brown fox jumps over the lazy dog'\n" );
202 vg_info( ":;!@#$%^& 0123456789 +-*/=~ ()[]{}<>\n" );
206 static void vg_console_init(void)
208 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
)
219 .function
= vg_console_list
222 vg_function_push( (struct vg_cmd
)
225 .function
= vg_console_chartest
229 static void vg_console_load_autos(void)
231 /* Read and exec persistent commands */
232 FILE *fp
= fopen( "cfg/auto.conf", "r" );
237 while( fgets( line
, sizeof( line
), fp
) )
239 line
[ strcspn( line
, "\r\n#" ) ] = 0x00;
241 if( line
[0] != 0x00 )
243 execute_console_input( line
);
251 static void vg_console_write_persistent(void)
253 FILE *fp
= fopen( "cfg/auto.conf", "w" );
255 for( int i
= 0; i
< arrlen( vg_console
.convars
); i
++ )
257 struct vg_convar
*cv
= &vg_console
.convars
[i
];
261 switch( cv
->data_type
)
263 case k_convar_dtype_i32
:
264 fprintf( fp
, "%s %d\n", cv
->name
, *(i32
*)(cv
->data
) );
266 case k_convar_dtype_u32
:
267 fprintf( fp
, "%s %u\n", cv
->name
, *(u32
*)(cv
->data
) );
269 case k_convar_dtype_f32
:
270 fprintf( fp
, "%s %.5f\n", cv
->name
, *(float *)(cv
->data
) );
279 static void vg_console_free(void)
281 vg_console_write_persistent();
283 arrfree( vg_console
.convars
);
284 arrfree( vg_console
.functions
);
287 static void execute_console_input( const char *cmd
)
295 /* Split string into tokens */
296 for( int i
= 0; i
< vg_list_size( temp
); i
++ )
300 if( cmd
[i
] == ' ' || cmd
[i
] == '\t' )
305 if( arg_count
== vg_list_size( args
) )
314 args
[ arg_count
++ ] = temp
+ i
;
332 for( int i
= 0; i
< arrlen( vg_console
.convars
); i
++ )
334 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
335 if( !strcmp( cv
->name
, args
[0] ) )
337 /* Cvar Matched, try get value */
340 switch( cv
->data_type
)
342 case k_convar_dtype_u32
:
343 case k_convar_dtype_i32
:
345 data_int
= atoi( args
[1] );
347 *((int *)cv
->data
) = cv
->opt_i32
.clamp
?
348 VG_MIN( VG_MAX(data_int
, cv
->opt_i32
.min
), cv
->opt_i32
.max
):
352 case k_convar_dtype_f32
:
353 data_float
= atof( args
[1] );
354 *((float *)cv
->data
) = cv
->opt_f32
.clamp
?
355 vg_minf( vg_maxf( data_float
, cv
->opt_f32
.min
), cv
->opt_f32
.max
):
365 switch( cv
->data_type
)
367 case k_convar_dtype_i32
:
368 vg_info( "= %d\n", *((int *)cv
->data
) );
370 case k_convar_dtype_u32
:
371 vg_info( "= %u\n", *((u32
*)cv
->data
) );
373 case k_convar_dtype_f32
:
374 vg_info( "= %.4f\n", *((float *)cv
->data
) );
384 * Find and excecute command
386 for( int i
= 0; i
< arrlen( vg_console
.functions
); i
++ )
388 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
389 if( !strcmp( cmd
->name
, args
[0] ) )
391 cmd
->function( arg_count
-1, args
+1 );
396 vg_error( "No command/var named '%s'. Use 'list' to view all\n", args
[0] );
402 static void console_make_selection( int* start
, int* end
)
404 *start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
);
405 *end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
408 static void console_move_cursor( int* cursor0
, int* cursor1
,
409 int dir
, int snap_together
)
411 *cursor0
= VG_MAX( 0, vg_console
.cursor_user
+ dir
);
414 VG_MIN( vg_list_size( vg_console
.input
), strlen( vg_console
.input
)),
421 static int console_makeroom( int datastart
, int length
)
423 int move_to
= VG_MIN( datastart
+length
, vg_list_size( vg_console
.input
) );
424 int move_amount
= strlen( vg_console
.input
)-datastart
;
426 VG_MIN( move_to
+move_amount
, vg_list_size( vg_console
.input
) );
427 move_amount
= move_end
-move_to
;
430 memmove( &vg_console
.input
[ move_to
],
431 &vg_console
.input
[ datastart
],
434 vg_console
.input
[ move_end
] = '\0';
436 return VG_MIN( length
, vg_list_size( vg_console
.input
)-datastart
);
439 static int console_delete_char( int direction
)
442 console_make_selection( &start
, &end
);
444 /* There is no selection */
447 if( direction
== 1 ) end
= VG_MIN( end
+1, strlen( vg_console
.input
) );
448 else if( direction
== -1 ) start
= VG_MAX( start
-1, 0 );
451 /* Still no selction, no need to do anything */
455 /* Copy the end->terminator to start */
456 int remaining_length
= strlen( vg_console
.input
)+1-end
;
457 memmove( &vg_console
.input
[ start
],
458 &vg_console
.input
[ end
],
463 static void console_to_clipboard(void)
466 console_make_selection( &start
, &end
);
471 memcpy( buffer
, &vg_console
.input
[ start
], end
-start
);
472 buffer
[ end
-start
] = 0x00;
473 glfwSetClipboardString( NULL
, buffer
);
477 static void console_clipboard_paste(void)
479 int datastart
= console_delete_char(0);
480 const char* clipboard
= glfwGetClipboardString(NULL
);
481 int length
= strlen(clipboard
);
483 int cpylength
= console_makeroom(datastart
, length
);
485 memcpy( vg_console
.input
+ datastart
, clipboard
, cpylength
);
486 console_move_cursor( &vg_console
.cursor_user
,
487 &vg_console
.cursor_pos
, cpylength
, 1 );
490 static void console_put_char( char c
)
492 if( !vg_console
.enabled
)
495 vg_console
.cursor_user
= console_delete_char(0);
497 if( console_makeroom( vg_console
.cursor_user
, 1 ) )
498 vg_console
.input
[ vg_console
.cursor_user
] = c
;
500 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, 1, 1 );
503 static void console_history_get( char* buf
, int entry_num
)
505 if( !vg_console
.history_count
)
508 int offset
= VG_MIN( entry_num
, vg_console
.history_count
-1 ),
509 pick
= (vg_console
.history_last
- offset
) %
510 vg_list_size( vg_console
.history
);
511 strcpy( buf
, vg_console
.history
[ pick
] );
514 static void console_proc_key( GLFWwindow
* ptrW
, int key
, int scancode
,
515 int action
, int mods
)
519 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
521 if( key
== GLFW_KEY_GRAVE_ACCENT
)
523 vg_console
.enabled
= !vg_console
.enabled
;
527 if( !vg_console
.enabled
)
530 if( key
== GLFW_KEY_LEFT
)
532 if( mods
& GLFW_MOD_SHIFT
) /* Receed secondary cursor */
534 console_move_cursor( &vg_console
.cursor_user
, NULL
, -1, 0 );
536 else /* Match and receed both cursors */
538 console_move_cursor( &vg_console
.cursor_user
,
539 &vg_console
.cursor_pos
, -cursor_diff
, 1 );
542 else if( key
== GLFW_KEY_RIGHT
) /* Advance secondary cursor */
544 if( mods
& GLFW_MOD_SHIFT
)
546 console_move_cursor( &vg_console
.cursor_user
, NULL
, 1, 0 );
548 else /* Match and advance both cursors */
550 console_move_cursor( &vg_console
.cursor_user
,
551 &vg_console
.cursor_pos
, +cursor_diff
, 1 );
554 else if( key
== GLFW_KEY_DOWN
)
556 if( mods
& GLFW_MOD_SHIFT
){}
559 vg_console
.history_pos
= VG_MAX( 0, vg_console
.history_pos
-1 );
560 console_history_get( vg_console
.input
, vg_console
.history_pos
);
561 console_move_cursor( &vg_console
.cursor_user
,
562 &vg_console
.cursor_pos
, vg_list_size( vg_console
.input
), 1 );
565 else if( key
== GLFW_KEY_UP
)
567 if( mods
& GLFW_MOD_SHIFT
){}
570 vg_console
.history_pos
= VG_MAX
575 vg_console
.history_pos
+1,
578 vg_list_size( vg_console
.history
),
579 vg_console
.history_count
- 1
584 console_history_get( vg_console
.input
, vg_console
.history_pos
);
585 console_move_cursor( &vg_console
.cursor_user
,
586 &vg_console
.cursor_pos
,
587 vg_list_size( vg_console
.input
), 1);
590 else if( key
== GLFW_KEY_BACKSPACE
) /* Lookback 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_DELETE
) /* Lookforward delete */
597 vg_console
.cursor_user
= console_delete_char( 1 );
598 vg_console
.cursor_pos
= vg_console
.cursor_user
;
600 else if( key
== GLFW_KEY_HOME
) /* Home key */
602 if( mods
& GLFW_MOD_SHIFT
)
603 console_move_cursor( &vg_console
.cursor_user
, NULL
, -10000, 0 );
605 console_move_cursor( &vg_console
.cursor_user
,
606 &vg_console
.cursor_pos
, -10000, 1 );
608 else if( key
== GLFW_KEY_END
) /* End key */
610 if( mods
& GLFW_MOD_SHIFT
)
611 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0 );
613 console_move_cursor( &vg_console
.cursor_user
,
614 &vg_console
.cursor_pos
,
615 vg_list_size( vg_console
.input
), 1 );
617 else if( key
== GLFW_KEY_A
)
619 if( mods
& GLFW_MOD_CONTROL
) /* Select all */
621 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0);
622 console_move_cursor( &vg_console
.cursor_pos
, NULL
, -10000, 0);
625 else if( key
== GLFW_KEY_C
) /* Copy */
627 if( mods
& GLFW_MOD_CONTROL
)
629 console_to_clipboard();
632 else if( key
== GLFW_KEY_X
) /* Cut */
634 if( mods
& GLFW_MOD_CONTROL
)
636 console_to_clipboard();
637 vg_console
.cursor_user
= console_delete_char(0);
638 vg_console
.cursor_pos
= vg_console
.cursor_user
;
641 else if( key
== GLFW_KEY_V
) /* Paste */
643 if( mods
& GLFW_MOD_CONTROL
)
645 console_clipboard_paste();
648 else if( key
== GLFW_KEY_ENTER
)
650 if( !strlen( vg_console
.input
) )
653 vg_info( "%s\n", vg_console
.input
);
655 if( strcmp( vg_console
.input
,
656 vg_console
.history
[ vg_console
.history_last
]) )
658 vg_console
.history_last
= ( vg_console
.history_last
+ 1) %
659 vg_list_size(vg_console
.history
);
660 vg_console
.history_count
=
661 VG_MIN( vg_list_size( vg_console
.history
),
662 vg_console
.history_count
+ 1 );
663 strcpy( vg_console
.history
[ vg_console
.history_last
],
667 vg_console
.history_pos
= -1;
668 execute_console_input( vg_console
.input
);
669 console_move_cursor( &vg_console
.cursor_user
,
670 &vg_console
.cursor_pos
, -10000, 1 );
671 vg_console
.input
[0] = '\0';
676 /* Handle an OS based input of UTF32 character from the keyboard or such */
677 static void console_proc_wchar( GLFWwindow
* ptrW
, u32 uWchar
)
679 if( uWchar
<= 0x7F && (char)uWchar
!= 0x60)
681 console_put_char((char)uWchar
);
685 #endif /* VG_CONSOLE_H */