}
{
+
if game_engine
+
{
add source/engine/main.c
hook
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"
+ }
}
{
event START
function _input_init
}
+ hook
+ {
+ event ENGINE_NEW_FRAME
+ function _input_update
+ }
ccmd
{
name bind
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
{
name console
}
+ input_layer
+ {
+ name ui
+ }
input
{
name console
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
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
{
#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);
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 );
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"
/* 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
--- /dev/null
+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"
#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;
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 };
_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) );
-}
#include "glfw.h"
#include "engine_interface.h"
+#include "input_api.h"
#include "console_core.h"
#include "generated/input.c"
}
_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 },
{
struct
{
- u8 activation_count;
- }
- action;
-
- struct
- {
- u8 press_count;
- bool up, down;
+ u8 hold_count, activation_count, release_count, repeat_count;
}
button;
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 )
{
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; i<stretchy_count( &_bind_allocator ); i ++ )
{
struct bind *bind = stretchy_get( &_bind_allocator, i );
- if( bind->device == 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 )
}
}
+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 );
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;
}
#include <math.h>
#include "engine_interface.h"
#include "engine_backend.h"
+#include "input_api.h"
#include "opengl.h"
#include "glfw.h"
void _character_callback( GLFWwindow *window, u32 codepoint )
{
- _engine_ui_input_character( codepoint );
+ if( _input_layer_filter( 1<<k_input_layer_ui ) )
+ _engine_ui_input_character( codepoint );
}
void _engine_options(void)
_engine.time = now;
next_frame_time = now + 1.0/_engine.framerate_limit;
- _input_update();
-
- /* pre-update */
- for( u8 j=0; j<_input_action( k_input_action_console ); j ++ )
- {
- _engine_backend.console_open ^= 0x1;
- //_input.layer_whitelist = _engine_backend.console_open? (1 << k_input_layer_console): 0;
- }
+ /* normal update */
+ EVENT_CALL( ENGINE_NEW_FRAME );
/* fixed update */
fixed_accumulator += _engine.time_delta;
_engine.time_delta = actual_delta;
_engine.time_fixed_extrapolate = fixed_accumulator / (1.0/60.0);
- /* normal update */
- EVENT_CALL( ENGINE_UPDATE );
-
glfwGetFramebufferSize( _engine.window_handle, &_engine.w, &_engine.h );
EVENT_CALL( ENGINE_RENDER );
_engine_ui_pre_render();
EVENT_CALL( ENGINE_UI );
- if( _engine_backend.console_open )
- _engine_console_ui();
_engine_ui_post_render();
glfwSwapBuffers(_engine.window_handle);
#include "graphics_api.h"
#include "engine_interface.h"
#include "engine_backend.h"
+#include "glfw.h"
struct graphics_target _ui_surface =
{
{
ASSERT_CRITICAL( _engine.w <= 1920 );
ASSERT_CRITICAL( _engine.h <= 1080 );
+
+ f64 x, y;
+ glfwGetCursorPos( _engine.window_handle, &x, &y );
+ _ui_set_mouse( x, y );
+ _ui_update();
_graphics_set_target( &_ui_surface );
_graphics_viewport( 0, 0, _engine.w, _engine.h );
_graphics_fill_rect( (i16[]){ 0, 0, _engine.w, _engine.h }, (union colour){{0,0,0,255}} );
- _graphics_fill_rect( (i16[]){ 4, 8, 20, 23 }, (union colour){{0,230,20,255}} );
- _graphics_line_rect( (i16[]){ 0, 0, _engine.w-1, _engine.h-1 }, (union colour){{255,230,20,255}} );
- _graphics_glyph( (i16[]){0,0}, 'w', 1, (union colour){{30,30,200,255}} );
-
- c8 buf[128];
- struct stream str;
- stream_open_buffer_write( &str, buf, sizeof(buf), k_stream_null_terminate );
- $v_string( &str, {"Hello! "}, $float( _engine.time, .decimals = 3 ) );
-
- _ui_text( (i16[]){32,32,400,20}, string_get(&str), k_ui_align_x_left, (union colour){{0,255,0,255}} );
-
- struct
- {
- enum input_id input_id;
- enum ui_action action_id;
- bool super;
- }
- ui_binds[] =
- {
- { k_input_action_ui_backspace, k_ui_action_backspace },
- { k_input_action_ui_delete, k_ui_action_delete },
- { k_input_action_ui_enter, k_ui_action_enter },
- { k_input_action_ui_indent, k_ui_action_indent },
- { k_input_action_ui_home, k_ui_action_home },
- { k_input_action_ui_home_select, k_ui_action_home, 1 },
- { k_input_action_ui_end, k_ui_action_end },
- { k_input_action_ui_end_select, k_ui_action_end, 1 },
- { k_input_action_ui_left, k_ui_action_left },
- { k_input_action_ui_left_select, k_ui_action_left, 1 },
- { k_input_action_ui_right, k_ui_action_right },
- { k_input_action_ui_right_select, k_ui_action_right, 1 },
- { k_input_action_ui_up, k_ui_action_up },
- { k_input_action_ui_up_select, k_ui_action_up, 1 },
- { k_input_action_ui_down, k_ui_action_down },
- { k_input_action_ui_down_select, k_ui_action_down, 1 }
- };
+}
- for( u32 i=0; i<ARRAY_COUNT( ui_binds ); i ++ )
- for( u8 j=0; j<_input_action( ui_binds[i].input_id ); j ++ )
- _ui_input_action( ui_binds[i].action_id, ui_binds[i].super );
+void _engine_ui_input_character( u32 codepoint )
+{
+ if( (codepoint >= (u32)' ') && (codepoint <= (u32)'~') )
+ _ui_input_text( (const c8[]){ codepoint, 0 } );
}
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 } );
-}
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; i<len; i ++ )
+ {
+ i64 value = 0;
+ if( string_parse_i64( &s, &value ) == k_string_parse_ok )
+ out_values[ i ] = (i32)value;
+ else
+ {
+ good = 0;
+ if( default_values ) out_values[ i ] = default_values[ i ];
+ else out_values[ i ] = 0;
+ }
+ }
+ return good;
+}
+
bool keyvalues_read_u32s( struct keyvalues *kvs, u32 root_offset, const c8 *key, u32 *default_values, u32 *out_values, u32 len )
{
bool good = 1;
#include "graphics_api.h"
+#include "input_api.h"
#include "maths/common_maths.h"
#define KEYBOARD_ALT 0x1
//i16 clipping_area[4];
i16 mouse_co[2], mouse_co_clicked[2];
- u32 mouse_clicking,
- mouse_click_down,
- mouse_click_up;
/* internal state */
enum ui_control_type
_ui.text_encoding = encoding;
}
-bool _ui_update(void)
-{
- _ui.mouse_click_down = 0x00;
- _ui.mouse_click_up = 0x00;
-
- if( _ui.active_control_type == k_ui_control_button )
- if( !(_ui.mouse_clicking & MOUSE_LEFT) )
- _ui.active_control_type = k_ui_control_none;
-
- 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}} );
-}
-
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]);
{
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 }};
}
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;
}
_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 )
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;
}
}
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 ) )
{
}
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}} );
+}
+
struct hook_user
{
struct stream function_name;
+ i32 affinity;
};
struct
{
ASSERT_CRITICAL( event_alias && function );
+ i32 affinity = 0;
+ keyvalues_read_i32s( kvs, block, "affinity", NULL, &affinity, 1 );
+
bool found = 0;
for( u32 i=0; i<stretchy_count( &_hooks.events ); i ++ )
struct hook_user *user = stretchy_append( &event->users );
stream_open_auto( &user->function_name, k_stream_null_terminate );
$v_string( &user->function_name, {function} );
+ user->affinity = affinity;
found = 1;
break;
}
}
$v_string( &source, {"\n"} );
+ bool sorted = 0;
+ while( !sorted )
+ {
+ sorted = 1;
+
+ for( u32 j=1; j<stretchy_count( &event->users ); 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; j<stretchy_count( &event->users ); j ++ )
{