28 int (*function
)( int argc
, char const *argv
[] );
37 int cursor_user
, cursor_pos
, string_length
;
39 char history
[32][512];
40 int history_last
, history_pos
, history_count
;
45 vg_console
= { .scale
= 1 };
47 static int vg_console_enabled(void) { return vg_console
.enabled
; }
49 static void vg_convar_push( struct vg_convar cv
)
51 arrpush( vg_console
.convars
, cv
);
54 static void vg_function_push( struct vg_cmd cmd
)
56 arrpush( vg_console
.functions
, cmd
);
59 static void vg_console_draw( void )
61 if( !vg_console
.enabled
)
64 int ptr
= vg_console
.current
- vg_console
.len
;
66 ptr
+= vg_list_size( vg_console
.lines
);
69 ui_global_ctx
.cursor
[0] = 0;
70 ui_global_ctx
.cursor
[1] = 0;
71 ui_global_ctx
.cursor
[3] = vg_console
.len
*8*vg_console
.scale
;
72 ui_fill_x( &ui_global_ctx
);
74 ui_new_node( &ui_global_ctx
);
76 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x77333333 );
78 ui_global_ctx
.cursor
[3] = 8*vg_console
.scale
;
79 ui_align_bottom( &ui_global_ctx
);
81 for( int i
= 0; i
< vg_console
.len
; i
++ )
83 ui_text( &ui_global_ctx
, vg_console
.lines
[ptr
], vg_console
.scale
, 0 );
84 ui_global_ctx
.cursor
[1] -= 8*vg_console
.scale
;
88 ptr
= vg_list_size( vg_console
.lines
)-1;
91 ui_end_down( &ui_global_ctx
);
93 ui_global_ctx
.cursor
[1] += 2;
94 ui_global_ctx
.cursor
[3] = 8*vg_console
.scale
;
96 ui_new_node( &ui_global_ctx
);
98 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x77333333 );
100 ui_text( &ui_global_ctx
, vg_console
.input
, vg_console
.scale
, 0 );
102 int start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
),
103 end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
105 ui_global_ctx
.cursor
[0] = start
* 6 * vg_console
.scale
;
106 ui_global_ctx
.cursor
[2] = (start
== end
? 1: (end
-start
)) * 6 * vg_console
.scale
;
108 ui_fill_rect( &ui_global_ctx
, ui_global_ctx
.cursor
, 0x66ffffff );
110 ui_end_down( &ui_global_ctx
);
113 void vg_console_println( const char *str
)
115 if( vg_console
.len
< vg_list_size( vg_console
.lines
) )
118 strcpy( vg_console
.lines
[ vg_console
.current
++ ], str
);
120 if( vg_console
.current
>= vg_list_size( vg_console
.lines
) )
121 vg_console
.current
= 0;
124 static void vg_console_init(void)
126 vg_log_callback
= vg_console_println
;
128 vg_convar_push( (struct vg_convar
)
129 { .name
= "console_scale", .data
= &vg_console
.scale
, .data_type
= k_convar_dtype_i32
,
130 .opt_i32
= { .clamp
= 1, .min
= 1, .max
= 7 } } );
133 static void vg_console_free(void)
135 arrfree( vg_console
.convars
);
136 arrfree( vg_console
.functions
);
139 static void execute_console_input( const char *cmd
)
147 // Split string into tokens
148 for( int i
= 0; i
< vg_list_size( temp
); i
++ )
152 if( isspace( cmd
[i
] ) )
163 args
[ arg_count
++ ] = temp
+ i
;
180 for( int i
= 0; i
< arrlen( vg_console
.convars
); i
++ )
182 struct vg_convar
*cv
= &vg_console
.convars
[ i
];
183 if( !strcmp( cv
->name
, args
[0] ) )
185 // Cvar Matched, try get value
188 switch( cv
->data_type
)
190 case k_convar_dtype_u32
:
191 case k_convar_dtype_i32
:
193 data_int
= atoi( args
[1] );
194 *((int *)cv
->data
) = cv
->opt_i32
.clamp
? VG_MIN( VG_MAX(data_int
, cv
->opt_i32
.min
), cv
->opt_i32
.max
): data_int
;
197 case k_convar_dtype_f32
: *((float *)cv
->data
) = atof( temp
); break;
202 switch( cv
->data_type
)
204 case k_convar_dtype_i32
: vg_info( "= %d\n", *((int *)cv
->data
) ); break;
205 case k_convar_dtype_u32
: vg_info( "= %u\n", *((u32
*)cv
->data
) ); break;
206 case k_convar_dtype_f32
: vg_info( "= %.4f\n", *((float *)cv
->data
) ); break;
215 for( int i
= 0; i
< arrlen( vg_console
.functions
); i
++ )
217 struct vg_cmd
*cmd
= &vg_console
.functions
[ i
];
218 if( !strcmp( cmd
->name
, args
[0] ) )
221 cmd
->function( arg_count
-1, args
+1 );
226 vg_error( "No command/variable named '%s'\n", args
[0] );
229 // =============================================================================================================================
232 static void console_make_selection( int* start
, int* end
)
234 *start
= VG_MIN( vg_console
.cursor_pos
, vg_console
.cursor_user
);
235 *end
= VG_MAX( vg_console
.cursor_pos
, vg_console
.cursor_user
);
238 static void console_move_cursor( int* cursor0
, int* cursor1
, int dir
, int snap_together
)
240 *cursor0
= VG_MAX( 0, vg_console
.cursor_user
+ dir
);
241 *cursor0
= VG_MIN( VG_MIN( vg_list_size( vg_console
.input
), strlen( vg_console
.input
)), *cursor0
);
246 static int console_makeroom( int datastart
, int length
)
248 int move_to
= VG_MIN( datastart
+length
, vg_list_size( vg_console
.input
) );
249 int move_amount
= strlen( vg_console
.input
)-datastart
;
250 int move_end
= VG_MIN( move_to
+move_amount
, vg_list_size( vg_console
.input
) );
251 move_amount
= move_end
-move_to
;
254 memmove( &vg_console
.input
[ move_to
], &vg_console
.input
[ datastart
], move_end
-move_to
);
256 vg_console
.input
[ move_end
] = '\0';
258 return VG_MIN( length
, vg_list_size( vg_console
.input
)-datastart
);
261 static int console_delete_char( int direction
)
264 console_make_selection( &start
, &end
);
266 // There is no selection
269 if( direction
== 1 ) end
= VG_MIN( end
+1, strlen( vg_console
.input
) );
270 else if( direction
== -1 ) start
= VG_MAX( start
-1, 0 );
273 // Still no selction, no need to do anything
277 // Copy the end->terminator to start
278 int remaining_length
= strlen( vg_console
.input
)+1-end
;
279 memmove( &vg_console
.input
[ start
], &vg_console
.input
[ end
], remaining_length
);
283 static void console_to_clipboard(void)
286 console_make_selection( &start
, &end
);
291 memcpy( buffer
, &vg_console
.input
[ start
], end
-start
);
292 buffer
[ end
-start
] = 0x00;
293 glfwSetClipboardString( NULL
, buffer
);
297 static void console_clipboard_paste(void)
299 int datastart
= console_delete_char(0);
300 const char* clipboard
= glfwGetClipboardString(NULL
);
301 int length
= strlen(clipboard
);
303 int cpylength
= console_makeroom(datastart
, length
);
305 memcpy( vg_console
.input
+ datastart
, clipboard
, cpylength
);
307 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, cpylength
, 1 );
310 static void console_put_char( char c
)
312 if( !vg_console
.enabled
)
315 vg_console
.cursor_user
= console_delete_char(0);
317 if( console_makeroom( vg_console
.cursor_user
, 1 ) )
318 vg_console
.input
[ vg_console
.cursor_user
] = c
;
320 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, 1, 1 );
323 static void console_history_get( char* buf
, int entry_num
)
325 if( !vg_console
.history_count
)
328 int pick
= (vg_console
.history_last
- VG_MIN( entry_num
, vg_console
.history_count
-1 )) % vg_list_size( vg_console
.history
);
329 strcpy( buf
, vg_console
.history
[ pick
] );
332 static void console_proc_key( GLFWwindow
* ptrW
, int key
, int scancode
, int action
, int mods
)
336 int cursor_diff
= vg_console
.cursor_pos
- vg_console
.cursor_user
? 0: 1;
338 if( key
== GLFW_KEY_GRAVE_ACCENT
)
340 vg_console
.enabled
= !vg_console
.enabled
;
344 if( !vg_console
.enabled
)
347 if( key
== GLFW_KEY_LEFT
)
349 if( mods
& GLFW_MOD_SHIFT
) // Receed secondary cursor
351 console_move_cursor( &vg_console
.cursor_user
, NULL
, -1, 0 );
353 else // Match and receed both cursors
355 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, -cursor_diff
, 1 );
358 else if( key
== GLFW_KEY_RIGHT
) // Advance secondary cursor
360 if( mods
& GLFW_MOD_SHIFT
)
362 console_move_cursor( &vg_console
.cursor_user
, NULL
, 1, 0 );
364 else // Match and advance both cursors
366 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, +cursor_diff
, 1 );
369 else if( key
== GLFW_KEY_DOWN
)
371 if( mods
& GLFW_MOD_SHIFT
){}
374 vg_console
.history_pos
= VG_MAX( 0, vg_console
.history_pos
-1 );
375 console_history_get( vg_console
.input
, vg_console
.history_pos
);
376 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, vg_list_size( vg_console
.input
), 1 );
379 else if( key
== GLFW_KEY_UP
)
381 if( mods
& GLFW_MOD_SHIFT
){}
384 vg_console
.history_pos
= VG_MAX
389 vg_console
.history_pos
+1,
392 vg_list_size( vg_console
.history
),
393 vg_console
.history_count
- 1
398 console_history_get( vg_console
.input
, vg_console
.history_pos
);
399 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, vg_list_size( vg_console
.input
), 1);
402 else if( key
== GLFW_KEY_BACKSPACE
) // Lookback delete
404 vg_console
.cursor_user
= console_delete_char( -1 );
405 vg_console
.cursor_pos
= vg_console
.cursor_user
;
407 else if( key
== GLFW_KEY_DELETE
) // Lookforward delete
409 vg_console
.cursor_user
= console_delete_char( 1 );
410 vg_console
.cursor_pos
= vg_console
.cursor_user
;
412 else if( key
== GLFW_KEY_HOME
) // Home key
414 if( mods
& GLFW_MOD_SHIFT
)
415 console_move_cursor( &vg_console
.cursor_user
, NULL
, -10000, 0 );
417 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, -10000, 1 );
419 else if( key
== GLFW_KEY_END
) // End key
421 if( mods
& GLFW_MOD_SHIFT
)
422 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0 );
424 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, vg_list_size( vg_console
.input
), 1 );
426 else if( key
== GLFW_KEY_A
)
428 if( mods
& GLFW_MOD_CONTROL
) // Select all
430 console_move_cursor( &vg_console
.cursor_user
, NULL
, 10000, 0);
431 console_move_cursor( &vg_console
.cursor_pos
, NULL
, -10000, 0);
434 else if( key
== GLFW_KEY_C
) // Copy
436 if( mods
& GLFW_MOD_CONTROL
)
438 console_to_clipboard();
441 else if( key
== GLFW_KEY_X
) // Cut
443 if( mods
& GLFW_MOD_CONTROL
)
445 console_to_clipboard();
446 vg_console
.cursor_user
= console_delete_char(0);
447 vg_console
.cursor_pos
= vg_console
.cursor_user
;
450 else if( key
== GLFW_KEY_V
) // Paste
452 if( mods
& GLFW_MOD_CONTROL
)
454 console_clipboard_paste();
457 else if( key
== GLFW_KEY_ENTER
)
459 if( !strlen( vg_console
.input
) )
462 vg_info( "%s\n", vg_console
.input
);
464 if( strcmp( vg_console
.input
, vg_console
.history
[ vg_console
.history_last
]) )
466 vg_console
.history_last
= ( vg_console
.history_last
+ 1) % vg_list_size(vg_console
.history
);
467 vg_console
.history_count
= VG_MIN( vg_list_size( vg_console
.history
), vg_console
.history_count
+ 1 );
468 strcpy( vg_console
.history
[ vg_console
.history_last
], vg_console
.input
);
471 vg_console
.history_pos
= -1;
472 execute_console_input( vg_console
.input
);
473 console_move_cursor( &vg_console
.cursor_user
, &vg_console
.cursor_pos
, -10000, 1 );
474 vg_console
.input
[0] = '\0';
479 // Handle an OS based input of UTF32 character from the keyboard or such
480 static void console_proc_wchar( GLFWwindow
* ptrW
, u32 uWchar
)
482 //LOG_INFO("Recieved wchar: %u\n", uWchar);
483 if( uWchar
<= 0x7F && (char)uWchar
!= 0x60)
485 console_put_char((char)uWchar
);