From: hgn Date: Mon, 6 Oct 2025 22:47:35 +0000 (+0000) Subject: uh yeah X-Git-Url: https://skaterift.com/git/?a=commitdiff_plain;h=fb6937bda630c8994b8fec298687649cbf96d0e2;p=vg.git uh yeah --- diff --git a/foundation.kv b/foundation.kv index 20a0e3c..259175b 100644 --- a/foundation.kv +++ b/foundation.kv @@ -48,7 +48,9 @@ add source/foundation/temporary.c } { + if game_engine + { add source/engine/main.c hook @@ -56,6 +58,27 @@ add source/foundation/temporary.c event OPTIONS function _engine_options } + + event + { + name ENGINE_NEW_FRAME + prototype "void" + } + event + { + name ENGINE_FIXED_UPDATE + prototype "void" + } + event + { + name ENGINE_RENDER + prototype "void" + } + event + { + name ENGINE_UI + prototype "void" + } } { @@ -74,6 +97,11 @@ add source/foundation/temporary.c event START function _input_init } + hook + { + event ENGINE_NEW_FRAME + function _input_update + } ccmd { name bind @@ -119,6 +147,17 @@ add source/foundation/temporary.c event START function _engine_console_init } + hook + { + event ENGINE_NEW_FRAME + function _engine_console_update + } + hook + { + event ENGINE_UI + function _engine_console_ui + affinity 9999 + } } add source/engine/shader.c @@ -126,6 +165,10 @@ add source/foundation/temporary.c { name console } + input_layer + { + name ui + } input { name console @@ -177,101 +220,90 @@ add source/foundation/temporary.c config "bind ENTER ui_enter" config "bind TAB ui_indent" config "bind HOME ui_home" - config "bind SHIFT+HOME ui_home_select" config "bind END ui_end" - config "bind SHIFT+END ui_end_select" config "bind LEFT ui_left" - config "bind SHIFT+LEFT ui_left_select" config "bind RIGHT ui_right" - config "bind SHIFT+RIGHT ui_right_select" config "bind UP ui_up" - config "bind SHIFT+UP ui_up_select" config "bind DOWN ui_down" - config "bind SHIFT+DOWN ui_down_select" + config "bind MOUSE_LEFT ui_click" + + config "bind LEFT_SHIFT ui_select" + config "bind RIGHT_SHIFT ui_select" input { name ui_delete type action + layer_mask ui } input { name ui_backspace type action + layer_mask ui } input { name ui_enter type action + layer_mask ui } input { name ui_indent type action + layer_mask ui } input { - name ui_home - type action + name ui_select + type button + layer_mask ui } input { - name ui_home_select - type action + name ui_home + type button + layer_mask ui } input { name ui_end - type action - } - input - { - name ui_end_select - type action + type button + layer_mask ui } input { name ui_left - type action - } - input - { - name ui_left_select - type action + type button + layer_mask ui } input { name ui_right - type action - } - input - { - name ui_right_select - type action + type button + layer_mask ui } input { name ui_up - type action - } - input - { - name ui_up_select - type action + type button + layer_mask ui } input { name ui_down - type action + type button + layer_mask ui } - input + input { - name ui_down_select + name ui_click type action + layer_mask ui } - shader { name blit @@ -314,26 +346,6 @@ add source/foundation/temporary.c cheat 1 description "This is just a test variable!" } - event - { - name ENGINE_FIXED_UPDATE - prototype "void" - } - event - { - name ENGINE_UPDATE - prototype "void" - } - event - { - name ENGINE_RENDER - prototype "void" - } - event - { - name ENGINE_UI - prototype "void" - } hook { diff --git a/include/common_api.h b/include/common_api.h index 985bba4..da6de5e 100644 --- a/include/common_api.h +++ b/include/common_api.h @@ -299,7 +299,7 @@ enum string_parse_result string_parse_string( struct stream *string, u32 *out_st #define $TO_STRING( S ) $TO_STRING_1( S ) #define $TO_STRING_1( S ) #S #define $line __FILE__ ":" $TO_STRING(__LINE__) -#define $log( C, ... ) $v_string( _log_event( C, $line ), __VA_ARGS__ ); _log_end_event(); +#define $log( C, ... ) { $v_string( _log_event( C, $line ), __VA_ARGS__ ); _log_end_event(); } struct stream *_log_event( u32 type, const c8 *code_location ); void _log_init(void); @@ -375,3 +375,9 @@ void directory_close( struct directory *directory ); for( u32 ev_iter=0; _event_##NAME##_subscribers[ ev_iter ]; ev_iter ++ ) \ _event_##NAME##_subscribers[ ev_iter ]( __VA_ARGS__ ); +struct sort_index +{ + u32 index; + i32 value; +}; +void index_sort( struct sort_index *indices, u32 indice_count ); diff --git a/include/engine_interface.h b/include/engine_interface.h index be2c03e..58c7a1d 100644 --- a/include/engine_interface.h +++ b/include/engine_interface.h @@ -16,38 +16,4 @@ struct _engine i32 w, h; } extern _engine; - -enum input_type -{ - k_input_type_action, - k_input_type_button, - k_input_type_axis -}; - -enum input_device -{ - k_input_device_none = 0, - k_input_device_keyboard, - k_input_device_controller -}; - -struct input_info -{ - const c8 *name; - enum input_type type; - u32 layer_mask; -}; - -enum input_id; - -// TODO: These are backend? -void _input_init(void); -void _input_update(void); - -bool _input_button_down( enum input_id id ); -bool _input_button_up( enum input_id id ); -bool _input_button( enum input_id id ); -u8 _input_action( enum input_id id ); - -#include "generated/input.h" #include "generated/console.h" diff --git a/include/graphics_api.h b/include/graphics_api.h index 10c2bde..701e492 100644 --- a/include/graphics_api.h +++ b/include/graphics_api.h @@ -88,24 +88,7 @@ bool _font_decode_bitmap( i16 uv[2] ); /* Immediate mode UI * ------------------------------------------------------------------------------------------------------------------ */ - -enum ui_action -{ - k_ui_action_backspace, - k_ui_action_delete, - k_ui_action_enter, - k_ui_action_indent, - - /* + super -> editing selection */ - k_ui_action_home, - k_ui_action_end, - k_ui_action_left, - k_ui_action_right, - k_ui_action_up, - k_ui_action_down -}; - -void _ui_input_action( enum ui_action action, bool super ); +void _ui_set_mouse( i16 x, i16 y ); void _ui_input_text( const c8 *text ); #define UI_PADDING_PX 8 diff --git a/include/input_api.h b/include/input_api.h new file mode 100644 index 0000000..fa5dc52 --- /dev/null +++ b/include/input_api.h @@ -0,0 +1,32 @@ +enum input_type +{ + k_input_type_action, + k_input_type_button, + k_input_type_axis +}; + +enum input_device +{ + k_input_device_none = 0, + k_input_device_keyboard, + k_input_device_controller, + k_input_device_mouse +}; + +struct input_info +{ + const c8 *name; + enum input_type type; + u32 layer_mask; +}; + +enum input_id; + +u8 _input_button_down( enum input_id id, bool allow_repeats ); +u8 _input_button_up( enum input_id id ); +u8 _input_button( enum input_id id ); + +void _input_layer_whitelist( u32 whitelist ); +bool _input_layer_filter( u32 mask ); + +#include "generated/input.h" diff --git a/source/engine/console.c b/source/engine/console.c index 005ff54..28a79f4 100644 --- a/source/engine/console.c +++ b/source/engine/console.c @@ -1,10 +1,12 @@ #include "console_core.h" #include "graphics_api.h" #include "engine_interface.h" +#include "input_api.h" struct { struct queue_allocator input_history, log_history; + bool open; } _console; @@ -16,8 +18,42 @@ struct log_history_item static c8 _input_buffer[ 1024 ]; +static void _log_listener( const c8 *line, u32 length, u32 type ) +{ +again:; + struct log_history_item *item = queue_alloc( &_console.log_history, sizeof( struct log_history_item ) + length+1 ); + if( !item ) + { + queue_pop( &_console.log_history ); + goto again; + } + + item->type = type; + buffer_copy( line, 0, item->buffer, length+1 ); +} + +void _engine_console_init(void) +{ + _log_add_listener( _log_listener, ($info | $ok | $warning | $error | $fatal | $shell), 0 ); + queue_init( &_console.input_history, _heap_allocate( BYTES_KB(2) ), BYTES_KB(2) ); + queue_init( &_console.log_history, _heap_allocate( BYTES_KB(4) ), BYTES_KB(4) ); +} + +void _engine_console_update(void) +{ + for( u8 j=0; j<_input_button_down( k_input_action_console, 0 ); j ++ ) + { + _console.open ^= 0x1; + u32 console_mask = (1 << k_input_layer_console) | (1 << k_input_layer_ui); + _input_layer_whitelist( _console.open? console_mask: 0 ); + } +} + void _engine_console_ui(void) { + if( !_console.open ) + return; + i16 kerning[3]; _font_get_kerning( kerning ); i16 history_box[4] = { 0, 0, _engine.w, kerning[1] * 32 }; @@ -47,24 +83,3 @@ void _engine_console_ui(void) _input_buffer[0] = '\0'; } } - -static void _log_listener( const c8 *line, u32 length, u32 type ) -{ -again:; - struct log_history_item *item = queue_alloc( &_console.log_history, sizeof( struct log_history_item ) + length+1 ); - if( !item ) - { - queue_pop( &_console.log_history ); - goto again; - } - - item->type = type; - buffer_copy( line, 0, item->buffer, length+1 ); -} - -void _engine_console_init(void) -{ - _log_add_listener( _log_listener, ($info | $ok | $warning | $error | $fatal | $shell), 0 ); - queue_init( &_console.input_history, _heap_allocate( BYTES_KB(2) ), BYTES_KB(2) ); - queue_init( &_console.log_history, _heap_allocate( BYTES_KB(4) ), BYTES_KB(4) ); -} diff --git a/source/engine/input.c b/source/engine/input.c index 6c98055..d5e5c23 100644 --- a/source/engine/input.c +++ b/source/engine/input.c @@ -1,5 +1,6 @@ #include "glfw.h" #include "engine_interface.h" +#include "input_api.h" #include "console_core.h" #include "generated/input.c" @@ -12,6 +13,9 @@ struct input_alias } _input_aliases[] = { + { "MOUSE_LEFT", k_input_device_mouse, .key = GLFW_MOUSE_BUTTON_1 }, + { "MOUSE_RIGHT", k_input_device_mouse, .key = GLFW_MOUSE_BUTTON_2 }, + { "MOUSE_MIDDLE", k_input_device_mouse, .key = GLFW_MOUSE_BUTTON_3 }, { "SPACE", k_input_device_keyboard, .key = GLFW_KEY_SPACE }, { "APOSTROPHE", k_input_device_keyboard, .key = GLFW_KEY_APOSTROPHE }, { "COMMA", k_input_device_keyboard, .key = GLFW_KEY_COMMA }, @@ -157,14 +161,7 @@ union input_state { struct { - u8 activation_count; - } - action; - - struct - { - u8 press_count; - bool up, down; + u8 hold_count, activation_count, release_count, repeat_count; } button; @@ -237,7 +234,7 @@ i32 _input_bind_ccmd( struct console_arguments *args ) else new_bind.device = alias->device_type; - if( alias->device_type == k_input_device_keyboard ) + if( (alias->device_type == k_input_device_keyboard) || (alias->device_type == k_input_device_mouse) ) { if( alias->key ) { @@ -297,56 +294,52 @@ i32 _input_unbind_ccmd( struct console_arguments *args ) return -1; } -// bind LEFT ui_left <---- action -// bind RIGHT ui_right <---- action -// bind SHIFT ui_select -// bind CTRL+N console_suggest_next -// bind CTRL+P console_suggest_prev -// -// bind W forward <---- button -// bind S back -// -// bind X delete -// bind SHIFT+X move - -static void _input_key_callback( GLFWwindow *window, i32 key, i32 scancode, i32 action, i32 mods ) +static void _input_callback_buttonlike( enum input_device device, i32 id, i32 action, i32 mods ) { for( u32 i=0; idevice == k_input_device_keyboard ) + if( bind->device == device ) { - if( bind->id == key ) + if( bind->id == id ) { struct input_info *input = &_input_infos[ bind->input_index ]; union input_state *state = &_input_states[ _input_page^0x1 ][ bind->input_index ]; - if( input->type == k_input_type_action ) + if( (input->type == k_input_type_action) || (input->type == k_input_type_button) ) { - if( (action == GLFW_PRESS) || (action == GLFW_REPEAT) ) + if( input->type == k_input_type_action ) { - if( bind->modifiers == mods ) - { - ASSERT_CRITICAL( state->action.activation_count < 255 ); - state->action.activation_count ++; - } + if( bind->modifiers != mods ) + continue; } - } - else if( input->type == k_input_type_button ) - { + + if( action == GLFW_REPEAT || action == GLFW_PRESS ) + { + ASSERT_CRITICAL( state->button.repeat_count < 255 ); + state->button.repeat_count ++; + } + if( action == GLFW_PRESS ) { - ASSERT_CRITICAL( state->button.press_count < 255 ); - if( state->button.press_count == 0 ) - state->button.down = 1; - state->button.press_count ++; + ASSERT_CRITICAL( state->button.activation_count < 255 ); + state->button.activation_count ++; + + if( input->type == k_input_type_button ) + { + ASSERT_CRITICAL( state->button.hold_count < 255 ); + state->button.hold_count ++; + } } - else if( action == GLFW_RELEASE ) + + if( action == GLFW_RELEASE ) { - ASSERT_CRITICAL( state->button.press_count > 0 ); - state->button.press_count --; - if( state->button.press_count == 0 ) - state->button.up = 1; + if( input->type == k_input_type_button ) + { + ASSERT_CRITICAL( state->button.hold_count > 0 ); + state->button.hold_count --; + state->button.release_count ++; + } } } else if( input->type == k_input_type_axis ) @@ -358,6 +351,16 @@ static void _input_key_callback( GLFWwindow *window, i32 key, i32 scancode, i32 } } +static void _input_mouse_callback( GLFWwindow *window, i32 button, i32 action, i32 mods ) +{ + _input_callback_buttonlike( k_input_device_mouse, button, action, mods ); +} + +static void _input_key_callback( GLFWwindow *window, i32 key, i32 scancode, i32 action, i32 mods ) +{ + _input_callback_buttonlike( k_input_device_keyboard, key, action, mods ); +} + void _input_init(void) { glfwSetKeyCallback( _engine.window_handle, _input_key_callback ); @@ -375,42 +378,55 @@ void _input_update(void) union input_state *back_state = &_input_states[ _input_page^0x1 ][ i ], *state = &_input_states[ _input_page ][ i ]; - if( input->type == k_input_type_action ) + if( (input->type == k_input_type_action) || (input->type == k_input_type_button) ) { - back_state->action.activation_count = 0; - } - else if( input->type == k_input_type_button ) - { - back_state->button.down = 0; - back_state->button.up = 0; - back_state->button.press_count = state->button.press_count; + back_state->button.activation_count = 0; + back_state->button.repeat_count = 0; + back_state->button.release_count = 0; + back_state->button.hold_count = state->button.hold_count; } } } -static union input_state *_get_input_of_type( enum input_type type, enum input_id id ) +static union input_state *_get_input_state( enum input_id id ) { - struct input_info *input = &_input_infos[ id ]; - ASSERT_CRITICAL( input->type == type ); return &_input_states[ _input_page ][ id ]; } -bool _input_button_down( enum input_id id ) +static u32 _whitelist = 0x00; + + +bool _input_layer_filter( u32 mask ) { - return _get_input_of_type( k_input_type_button, id )->button.down; + return (_whitelist & mask) || !_whitelist; +} + +bool _filter_input( enum input_id id ) +{ + return _input_layer_filter( _input_infos[ id ].layer_mask ); +} + +u8 _input_button_down( enum input_id id, bool allow_repeats ) +{ + if( _filter_input(id) ) + { + union input_state *state = _get_input_state( id ); + return allow_repeats? state->button.repeat_count: state->button.activation_count; + } + else return 0; } -bool _input_button_up( enum input_id id ) +u8 _input_button_up( enum input_id id ) { - return _get_input_of_type( k_input_type_button, id )->button.up; + return _filter_input(id) && _get_input_state( id )->button.release_count; } -bool _input_button( enum input_id id ) +u8 _input_button( enum input_id id ) { - return _get_input_of_type( k_input_type_button, id )->button.press_count > 0; + return _filter_input(id) && _get_input_state( id )->button.hold_count; } -u8 _input_action( enum input_id id ) +void _input_layer_whitelist( u32 whitelist ) { - return _get_input_of_type( k_input_type_action, id )->action.activation_count; + _whitelist = whitelist; } diff --git a/source/engine/main.c b/source/engine/main.c index 20fc9fe..c4615f5 100644 --- a/source/engine/main.c +++ b/source/engine/main.c @@ -2,6 +2,7 @@ #include #include "engine_interface.h" #include "engine_backend.h" +#include "input_api.h" #include "opengl.h" #include "glfw.h" @@ -35,7 +36,8 @@ static void _engine_set_framerate( f64 hz, bool vsync ) void _character_callback( GLFWwindow *window, u32 codepoint ) { - _engine_ui_input_character( codepoint ); + if( _input_layer_filter( 1<= (u32)' ') && (codepoint <= (u32)'~') ) + _ui_input_text( (const c8[]){ codepoint, 0 } ); } void _engine_ui_post_render(void) @@ -104,9 +76,3 @@ void _engine_ui_post_render(void) glBindVertexArray( quad_vao ); glDrawArrays( GL_TRIANGLES, 0, 6 ); } - -void _engine_ui_input_character( u32 codepoint ) -{ - if( (codepoint >= (u32)' ') && (codepoint <= (u32)'~') ) - _ui_input_text( (const c8[]){ codepoint, 0 } ); -} diff --git a/source/foundation/keyvalues.c b/source/foundation/keyvalues.c index 1bb4b63..039982c 100644 --- a/source/foundation/keyvalues.c +++ b/source/foundation/keyvalues.c @@ -192,6 +192,30 @@ u32 keyvalues_get( struct keyvalues *kvs, u32 root_offset, const c8 *key ) return 0; } +bool keyvalues_read_i32s( struct keyvalues *kvs, u32 root_offset, const c8 *key, i32 *default_values, i32 *out_values, u32 len ) +{ + bool good = 1; + + u32 value_length; + char *value = keyvalues_value( kvs, keyvalues_get( kvs, root_offset, key ), &value_length ); + struct stream s; + stream_open_buffer_read( &s, value, value_length, 0 ); + + for( u32 i=0; ivalue; - } - - c8 temp[32]; - struct stream string; - stream_open_buffer_write( &string, temp, sizeof(temp), k_stream_null_terminate ); - string_append_i64( &string, option->value, 10 ); - _ui_text( button_rect, temp, k_ui_align_y_center, (union colour){{128,128,128,255}} ); - _ui_text( button_rect, option->display_name, k_ui_align_center, (union colour){{255,255,255,255}} ); - - if( current_value == option->value ) - { - i16 tick_rect[4] = { button_rect[0]+button_rect[2]-UI_PADDING_PX*2, button_rect[1], - UI_PADDING_PX*2, button_rect[3] }; - _ui_text( tick_rect, "\xB3", k_ui_align_center, (union colour){{0,255,0,255}} ); - } - } - _ui.active_control_type = k_ui_control_dropdown; - } - - _ui.redraw = 0; - _graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 4,4 }, (union colour){{0,0,0,255}} ); - _graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 3,3 }, (union colour){{255,255,255,255}} ); -} - static bool ui_inside_rect( i16 rect[4], i16 co[2] ) { return (co[0] >= rect[0]) && (co[1] >= rect[1]) && (co[0] < rect[0]+rect[2]) && (co[1] < rect[1]+rect[3]); @@ -272,7 +216,7 @@ enum button_action _ui_button( i16 rect[4] ) { if( ui_inside_rect( rect, _ui.mouse_co ) ) { - if( _ui.mouse_click_down & MOUSE_LEFT ) + if( _input_button_down( k_input_action_ui_click, 0 ) ) { action = k_button_click; debug_colour = (union colour){{ 255, 255, 255, 255 }}; @@ -280,19 +224,23 @@ enum button_action _ui_button( i16 rect[4] ) } else { - action = (_ui.mouse_clicking & MOUSE_LEFT)? k_button_repeat: k_button_hover; + action = _input_button( k_input_action_ui_click )? k_button_repeat: k_button_hover; debug_colour = (union colour){{ 0, 0, 255, 170 }}; } } else - if( _ui.mouse_clicking & MOUSE_LEFT ) + if( _input_button( k_input_action_ui_click ) ) if( ui_inside_rect( rect, _ui.mouse_co_clicked ) ) { action = k_button_repeat; debug_colour = (union colour){{ 255, 0, 255, 140 }}; } } + _graphics_line_rect( rect, debug_colour ); + + if( action == k_button_click || action == k_button_repeat ) + _ui.active_control_touched = 1; return action; } @@ -389,111 +337,10 @@ static void _ui_textbox_set_cursor_user( i32 position, bool super ) _ui.controls.textbox.cursor_pos = position; } -void _ui_input_action( enum ui_action action, bool super ) +void _ui_set_mouse( i16 x, i16 y ) { - if( _ui.active_control_type == k_ui_control_textbox ) - { - if( action == k_ui_action_backspace ) - { - i32 i0 = i32_min( _ui.controls.textbox.cursor_pos, _ui.controls.textbox.cursor_user ), - i1 = i32_max( _ui.controls.textbox.cursor_pos, _ui.controls.textbox.cursor_user ); - if( i0 || (i0!=i1) ) - { - if( i0 == i1 ) - _ui.controls.textbox.cursor_pos --; - _ui_textbox_input_string( (const c8[]){ 0 } ); - i32 i2 = i0; - if( i0 == i1 ) - i2 = i0-1; - _ui.controls.textbox.cursor_pos = i2; - _ui.controls.textbox.cursor_user = i2; - } - } - else if( action == k_ui_action_enter ) - { - if( _ui.controls.textbox.flags & UI_MULTILINE ) - _ui_textbox_input_string( (const c8[]){ '\n', 0 } ); - else - _ui.controls.textbox.action = k_textbox_enter; - } - else if( action == k_ui_action_home ) - _ui_textbox_set_cursor_user( 0, super ); - else if( action == k_ui_action_end ) - _ui_textbox_set_cursor_user( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), super ); - else if( action == k_ui_action_right ) - { - i32 p1 = i32_min( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), _ui.controls.textbox.cursor_user+1 ); - _ui_textbox_set_cursor_user( p1, super ); - } - else if( action == k_ui_action_left ) - { - i32 p1 = i32_max( 0, _ui.controls.textbox.cursor_user-1 ); - _ui_textbox_set_cursor_user( p1, super ); - } - else if( action == k_ui_action_up ) - { - if( _ui.controls.textbox.flags & UI_MULTILINE ) - { - i16 user_co[2] = {-1, -1}; - i32 result_index = -1; - struct ui_string_decoder decoder, decoder1; - ui_string_decode_init( &decoder, _ui.controls.textbox.text_buffer, _ui.controls.textbox.text_buffer_encoding ); - decoder1 = decoder; - bool loop; do - { - loop = ui_string_decode( &decoder ); - if( decoder.character_index == _ui.controls.textbox.cursor_user ) - { - user_co[0] = decoder.grid_co[0]; - user_co[1] = decoder.grid_co[1]; - loop = 0; - } - } while( loop ); - bool loop1; do - { - loop1 = ui_string_decode( &decoder1 ); - if( decoder1.grid_co[1] == user_co[1]-1 ) - if( decoder1.grid_co[0] <= user_co[0] ) - result_index = decoder1.character_index; - } while( loop1 ); - - if( result_index != -1 ) - _ui_textbox_set_cursor_user( result_index, super ); - } - else - _ui.controls.textbox.action = k_textbox_input_up; - } - else if( action == k_ui_action_down ) - { - if( _ui.controls.textbox.flags & UI_MULTILINE ) - { - i16 user_co[2] = { -1, -1 }; - i32 result_index = -1; - struct ui_string_decoder decoder; - ui_string_decode_init( &decoder, _ui.controls.textbox.text_buffer, _ui.controls.textbox.text_buffer_encoding ); - bool loop; do - { - loop = ui_string_decode( &decoder ); - if( decoder.character_index == _ui.controls.textbox.cursor_user ) - { - user_co[0] = decoder.grid_co[0]; - user_co[1] = decoder.grid_co[1]; - } - if( decoder.grid_co[1] == user_co[1]+1 ) - if( decoder.grid_co[0] <= user_co[0] ) - result_index = decoder.character_index; - } while( loop ); - - if( result_index != -1 ) - _ui_textbox_set_cursor_user( result_index, super ); - } - else - _ui.controls.textbox.action = k_textbox_input_up; - } - else if( action == k_ui_action_indent ) - { - } - } + _ui.mouse_co[0] = x; + _ui.mouse_co[1] = y; } void _ui_input_text( const c8 *text ) @@ -522,8 +369,9 @@ enum textbox_action _ui_textbox( i16 rect[4], c8 *text_buffer, u32 text_buffer_l if( init ) { - _ui.controls.textbox.cursor_pos = 0; - _ui.controls.textbox.cursor_user = 0; + i32 p = buffer_last_index( text_buffer, 0, 0 ); + _ui.controls.textbox.cursor_pos = p; + _ui.controls.textbox.cursor_user = p; } } @@ -585,7 +433,7 @@ enum textbox_action _ui_textbox( i16 rect[4], c8 *text_buffer, u32 text_buffer_l rect[1] + user_co[1]*kerning[1], kerning[0],kerning[1] }, (union colour){{255,255,0,255}} ); - if( _ui.mouse_clicking & MOUSE_LEFT ) + if( _input_button( k_input_action_ui_click ) ) { if( ui_inside_rect( rect, _ui.mouse_co_clicked ) ) { @@ -644,3 +492,167 @@ enum dropdown_action _ui_dropdown( i16 rect[4], struct ui_dropdown_option *optio } return k_dropdown_none; } + +bool _ui_update(void) +{ + if( _input_button_down( k_input_action_ui_click, 0 ) ) + { + _ui.mouse_co_clicked[0] = _ui.mouse_co[0]; + _ui.mouse_co_clicked[1] = _ui.mouse_co[1]; + } + + if( !_ui.active_control_touched ) + _ui.active_control_type = k_ui_control_none; + + if( _ui.active_control_type == k_ui_control_textbox ) + { + for( u8 i=0; i<_input_button_down( k_input_action_ui_backspace, 1 ); i ++ ) + { + i32 i0 = i32_min( _ui.controls.textbox.cursor_pos, _ui.controls.textbox.cursor_user ), + i1 = i32_max( _ui.controls.textbox.cursor_pos, _ui.controls.textbox.cursor_user ); + if( i0 || (i0!=i1) ) + { + if( i0 == i1 ) + _ui.controls.textbox.cursor_pos --; + _ui_textbox_input_string( (const c8[]){ 0 } ); + i32 i2 = i0; + if( i0 == i1 ) + i2 = i0-1; + _ui.controls.textbox.cursor_pos = i2; + _ui.controls.textbox.cursor_user = i2; + } + } + + for( u8 i=0; i<_input_button_down( k_input_action_ui_enter, 1 ); i ++ ) + { + if( _ui.controls.textbox.flags & UI_MULTILINE ) + _ui_textbox_input_string( (const c8[]){ '\n', 0 } ); + else + _ui.controls.textbox.action = k_textbox_enter; + } + + bool select_mode = _input_button( k_input_button_ui_select ); + + for( u8 i=0; i<_input_button_down( k_input_button_ui_home, 1 ); i ++ ) + _ui_textbox_set_cursor_user( 0, select_mode ); + for( u8 i=0; i<_input_button_down( k_input_button_ui_end, 1 ); i ++ ) + _ui_textbox_set_cursor_user( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), select_mode ); + for( u8 i=0; i<_input_button_down( k_input_button_ui_right, 1 ); i ++ ) + { + i32 p1 = i32_min( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), _ui.controls.textbox.cursor_user+1 ); + _ui_textbox_set_cursor_user( p1, select_mode ); + } + for( u8 i=0; i<_input_button_down( k_input_button_ui_left, 1 ); i ++ ) + { + i32 p1 = i32_max( 0, _ui.controls.textbox.cursor_user-1 ); + _ui_textbox_set_cursor_user( p1, select_mode ); + } + for( u8 i=0; i<_input_button_down( k_input_button_ui_up, 1 ); i ++ ) + { + if( _ui.controls.textbox.flags & UI_MULTILINE ) + { + i16 user_co[2] = {-1, -1}; + i32 result_index = -1; + struct ui_string_decoder decoder, decoder1; + ui_string_decode_init( &decoder, _ui.controls.textbox.text_buffer, _ui.controls.textbox.text_buffer_encoding ); + decoder1 = decoder; + bool loop; do + { + loop = ui_string_decode( &decoder ); + if( decoder.character_index == _ui.controls.textbox.cursor_user ) + { + user_co[0] = decoder.grid_co[0]; + user_co[1] = decoder.grid_co[1]; + loop = 0; + } + } while( loop ); + bool loop1; do + { + loop1 = ui_string_decode( &decoder1 ); + if( decoder1.grid_co[1] == user_co[1]-1 ) + if( decoder1.grid_co[0] <= user_co[0] ) + result_index = decoder1.character_index; + } while( loop1 ); + + if( result_index != -1 ) + _ui_textbox_set_cursor_user( result_index, select_mode ); + } + else + _ui.controls.textbox.action = k_textbox_input_up; + } + + for( u8 i=0; i<_input_button_down( k_input_button_ui_down, 1 ); i ++ ) + { + if( _ui.controls.textbox.flags & UI_MULTILINE ) + { + i16 user_co[2] = { -1, -1 }; + i32 result_index = -1; + struct ui_string_decoder decoder; + ui_string_decode_init( &decoder, _ui.controls.textbox.text_buffer, _ui.controls.textbox.text_buffer_encoding ); + bool loop; do + { + loop = ui_string_decode( &decoder ); + if( decoder.character_index == _ui.controls.textbox.cursor_user ) + { + user_co[0] = decoder.grid_co[0]; + user_co[1] = decoder.grid_co[1]; + } + if( decoder.grid_co[1] == user_co[1]+1 ) + if( decoder.grid_co[0] <= user_co[0] ) + result_index = decoder.character_index; + } while( loop ); + + if( result_index != -1 ) + _ui_textbox_set_cursor_user( result_index, select_mode ); + } + else + _ui.controls.textbox.action = k_textbox_input_up; + } + } + + _ui.active_control_touched = 0; + return _ui.redraw; +} + +void _ui_draw(void) +{ + if( _ui.active_control_type == k_ui_control_dropdown ) + { + _ui.active_control_type = k_ui_control_none; + i16 button_rect[4]; + rect_copy( _ui.controls.dropdown.source_rect, button_rect ); + i32 current_value = *_ui.controls.dropdown.value; + + for( u32 i=0; i<_ui.controls.dropdown.option_count; i ++ ) + { + button_rect[1] += button_rect[3]; + + struct ui_dropdown_option *option = &_ui.controls.dropdown.options[i]; + if( _ui_button( button_rect ) == k_button_click ) + { + _ui.controls.dropdown.action = k_dropdown_changed; + *_ui.controls.dropdown.value = option->value; + } + + c8 temp[32]; + struct stream string; + stream_open_buffer_write( &string, temp, sizeof(temp), k_stream_null_terminate ); + string_append_i64( &string, option->value, 10 ); + _ui_text( button_rect, temp, k_ui_align_y_center, (union colour){{128,128,128,255}} ); + _ui_text( button_rect, option->display_name, k_ui_align_center, (union colour){{255,255,255,255}} ); + + if( current_value == option->value ) + { + i16 tick_rect[4] = { button_rect[0]+button_rect[2]-UI_PADDING_PX*2, button_rect[1], + UI_PADDING_PX*2, button_rect[3] }; + _ui_text( tick_rect, "\xB3", k_ui_align_center, (union colour){{0,255,0,255}} ); + } + } + _ui.active_control_type = k_ui_control_dropdown; + } + + _ui.redraw = 0; + _graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 4,4 }, (union colour){{0,0,0,255}} ); + _graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 3,3 }, (union colour){{255,255,255,255}} ); +} + diff --git a/source/tools/metacompiler.c b/source/tools/metacompiler.c index d8a1c3b..c8c46e9 100644 --- a/source/tools/metacompiler.c +++ b/source/tools/metacompiler.c @@ -31,6 +31,7 @@ struct hook_event struct hook_user { struct stream function_name; + i32 affinity; }; struct { @@ -323,6 +324,9 @@ void _parse_kv_block( struct keyvalues *kvs, u32 block, struct block_context con ASSERT_CRITICAL( event_alias && function ); + i32 affinity = 0; + keyvalues_read_i32s( kvs, block, "affinity", NULL, &affinity, 1 ); + bool found = 0; for( u32 i=0; iusers ); stream_open_auto( &user->function_name, k_stream_null_terminate ); $v_string( &user->function_name, {function} ); + user->affinity = affinity; found = 1; break; } @@ -705,6 +710,25 @@ i32 main( i32 argc, const c8 *argv[] ) } $v_string( &source, {"\n"} ); + bool sorted = 0; + while( !sorted ) + { + sorted = 1; + + for( u32 j=1; jusers ); j ++ ) + { + struct hook_user *j1 = stretchy_get( &event->users, j ), + *j0 = stretchy_get( &event->users, j-1 ); + if( j1->affinity < j0->affinity ) + { + struct hook_user temp = *j0; + *j0 = *j1; + *j1 = temp; + sorted = 0; + } + } + } + $v_string( &source, {returns}, {" (*_event_"}, {alias}, {"_subscribers[])( "}, {prototype}, {" ) = \n{\n"} ); for( u32 j=0; jusers ); j ++ ) {