yay, input mapping!

plugins
Patrick Cleavelin 2023-12-29 21:12:25 -06:00
parent c0e980f406
commit 2a5a5af40f
2 changed files with 158 additions and 29 deletions

View File

@ -1,5 +1,6 @@
package core
import "core:fmt"
import "vendor:raylib"
Mode :: enum {
@ -17,6 +18,69 @@ State :: struct {
current_buffer: int,
buffers: [dynamic]FileBuffer,
// TODO: replace this with generic pointer to floating window
buffer_list_window_is_visible: bool,
buffer_list_window_selected_buffer: int,
buffer_list_window_input_map: InputMap,
input_map: InputMap,
current_input_map: ^InputMap,
}
EditorAction :: proc(state: ^State);
InputGroup :: union {EditorAction, InputMap}
InputMap :: struct {
key_actions: map[raylib.KeyboardKey]InputGroup,
ctrl_key_actions: map[raylib.KeyboardKey]InputGroup,
}
new_input_map :: proc() -> InputMap {
input_map := InputMap {
key_actions = make(map[raylib.KeyboardKey]InputGroup),
ctrl_key_actions = make(map[raylib.KeyboardKey]InputGroup),
}
return input_map;
}
// NOTE(pcleavelin): might be a bug in the compiler where it can't coerce
// `EditorAction` to `InputGroup` when given as a proc parameter, that is why there
// are two functions
register_key_action_single :: proc(input_map: ^InputMap, key: raylib.KeyboardKey, action: EditorAction) {
if ok := key in input_map.key_actions; ok {
// TODO: log that key is already registered
fmt.println("key already registered with single action", key);
}
input_map.key_actions[key] = action;
}
register_key_action_group :: proc(input_map: ^InputMap, key: raylib.KeyboardKey, input_group: InputGroup) {
if ok := key in input_map.key_actions; ok {
// TODO: log that key is already registered
fmt.println("key already registered with single action", key);
}
input_map.key_actions[key] = input_group;
}
register_ctrl_key_action_single :: proc(input_map: ^InputMap, key: raylib.KeyboardKey, action: EditorAction) {
if ok := key in input_map.key_actions; ok {
// TODO: log that key is already registered
fmt.println("key already registered with single action", key);
}
input_map.ctrl_key_actions[key] = action;
}
register_ctrl_key_action_group :: proc(input_map: ^InputMap, key: raylib.KeyboardKey, input_group: InputGroup) {
if ok := key in input_map.key_actions; ok {
// TODO: log that key is already registered
fmt.println("key already registered with single action", key);
}
input_map.ctrl_key_actions[key] = input_group;
}
register_key_action :: proc{register_key_action_single, register_key_action_group};
register_ctrl_key_action :: proc{register_ctrl_key_action_single, register_ctrl_key_action_group};

View File

@ -18,33 +18,30 @@ FileBuffer :: core.FileBuffer;
// TODO: use buffer list in state
do_normal_mode :: proc(state: ^State, buffer: ^FileBuffer) {
if raylib.IsKeyPressed(.I) {
state.mode = .Insert;
return;
if state.current_input_map != nil {
if raylib.IsKeyDown(.LEFT_CONTROL) {
for key, action in state.current_input_map.ctrl_key_actions {
if raylib.IsKeyPressed(key) {
switch value in action {
case core.EditorAction:
value(state);
case core.InputMap:
// TODO: make this the current input map and display it
}
if raylib.IsKeyPressed(.W) {
core.move_cursor_forward_start_of_word(buffer);
}
if raylib.IsKeyPressed(.K) {
core.move_cursor_up(buffer);
}
if raylib.IsKeyPressed(.J) {
core.move_cursor_down(buffer);
} else {
for key, action in state.current_input_map.key_actions {
if raylib.IsKeyPressed(key) {
switch value in action {
case core.EditorAction:
value(state);
case core.InputMap:
// TODO: make this the current input map and display it
}
if raylib.IsKeyPressed(.H) {
core.move_cursor_left(buffer);
}
if raylib.IsKeyPressed(.L) {
core.move_cursor_right(buffer);
}
if raylib.IsKeyDown(.LEFT_CONTROL) && raylib.IsKeyDown(.U) {
core.scroll_file_buffer(buffer, .Up);
}
if raylib.IsKeyDown(.LEFT_CONTROL) && raylib.IsKeyDown(.D) {
core.scroll_file_buffer(buffer, .Down);
}
}
@ -86,10 +83,77 @@ switch_to_buffer :: proc(state: ^State, item: ^ui.MenuBarItem) {
}
}
register_default_input_actions :: proc(input_map: ^core.InputMap) {
core.register_key_action(input_map, .W, proc(state: ^State) {
core.move_cursor_forward_start_of_word(&state.buffers[state.current_buffer]);
});
core.register_key_action(input_map, .K, proc(state: ^State) {
core.move_cursor_up(&state.buffers[state.current_buffer]);
});
core.register_key_action(input_map, .J, proc(state: ^State) {
core.move_cursor_down(&state.buffers[state.current_buffer]);
});
core.register_key_action(input_map, .H, proc(state: ^State) {
core.move_cursor_left(&state.buffers[state.current_buffer]);
});
core.register_key_action(input_map, .L, proc(state: ^State) {
core.move_cursor_right(&state.buffers[state.current_buffer]);
});
core.register_ctrl_key_action(input_map, .U, proc(state: ^State) {
core.scroll_file_buffer(&state.buffers[state.current_buffer], .Up);
});
core.register_ctrl_key_action(input_map, .D, proc(state: ^State) {
core.scroll_file_buffer(&state.buffers[state.current_buffer], .Down);
});
core.register_key_action(input_map, .B, proc(state: ^State) {
state.buffer_list_window_is_visible = true;
state.current_input_map = &state.buffer_list_window_input_map;
});
core.register_key_action(input_map, .I, proc(state: ^State) {
state.mode = .Insert;
});
}
register_buffer_list_input_actions :: proc(input_map: ^core.InputMap) {
core.register_key_action(input_map, .K, proc(state: ^State) {
if state.buffer_list_window_selected_buffer > 0 {
state.buffer_list_window_selected_buffer -= 1;
} else {
state.buffer_list_window_selected_buffer = len(state.buffers)-1;
}
});
core.register_key_action(input_map, .J, proc(state: ^State) {
if state.buffer_list_window_selected_buffer >= len(state.buffers)-1 {
state.buffer_list_window_selected_buffer = 0;
} else {
state.buffer_list_window_selected_buffer += 1;
}
});
core.register_key_action(input_map, .ENTER, proc(state: ^State) {
state.current_buffer = state.buffer_list_window_selected_buffer;
state.buffer_list_window_is_visible = false;
state.current_input_map = &state.input_map;
});
core.register_key_action(input_map, .Q, proc(state: ^State) {
state.buffer_list_window_is_visible = false;
state.current_input_map = &state.input_map;
});
}
main :: proc() {
state := State {
buffer_list_window_is_visible = true,
input_map = core.new_input_map(),
buffer_list_window_input_map = core.new_input_map(),
};
state.current_input_map = &state.input_map;
register_default_input_actions(&state.input_map);
register_buffer_list_input_actions(&state.buffer_list_window_input_map);
for arg in os.args[1:] {
buffer, err := core.new_file_buffer(context.allocator, arg);
@ -133,7 +197,8 @@ main :: proc() {
buffer := &state.buffers[state.current_buffer];
buffer.glyph_buffer_height = math.min(256, int((state.screen_height - 32 - core.source_font_height) / core.source_font_height));
buffer.glyph_buffer_height = math.min(256, int((state.screen_height - core.source_font_height*2) / core.source_font_height)) + 1;
buffer.glyph_buffer_width = math.min(256, int((state.screen_width - core.source_font_width) / core.source_font_width));
{
raylib.BeginDrawing();