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 package core
import "core:fmt"
import "vendor:raylib" import "vendor:raylib"
Mode :: enum { Mode :: enum {
@ -17,6 +18,69 @@ State :: struct {
current_buffer: int, current_buffer: int,
buffers: [dynamic]FileBuffer, buffers: [dynamic]FileBuffer,
// TODO: replace this with generic pointer to floating window
buffer_list_window_is_visible: bool, buffer_list_window_is_visible: bool,
buffer_list_window_selected_buffer: int, 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 // TODO: use buffer list in state
do_normal_mode :: proc(state: ^State, buffer: ^FileBuffer) { do_normal_mode :: proc(state: ^State, buffer: ^FileBuffer) {
if raylib.IsKeyPressed(.I) { if state.current_input_map != nil {
state.mode = .Insert; if raylib.IsKeyDown(.LEFT_CONTROL) {
return; for key, action in state.current_input_map.ctrl_key_actions {
} if raylib.IsKeyPressed(key) {
switch value in action {
if raylib.IsKeyPressed(.W) { case core.EditorAction:
core.move_cursor_forward_start_of_word(buffer); value(state);
} case core.InputMap:
// TODO: make this the current input map and display it
if raylib.IsKeyPressed(.K) { }
core.move_cursor_up(buffer); }
} }
if raylib.IsKeyPressed(.J) { } else {
core.move_cursor_down(buffer); for key, action in state.current_input_map.key_actions {
} if raylib.IsKeyPressed(key) {
if raylib.IsKeyPressed(.H) { switch value in action {
core.move_cursor_left(buffer); case core.EditorAction:
} value(state);
if raylib.IsKeyPressed(.L) { case core.InputMap:
core.move_cursor_right(buffer); // TODO: make this the current input map and display it
} }
}
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() { main :: proc() {
state := State { 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:] { for arg in os.args[1:] {
buffer, err := core.new_file_buffer(context.allocator, arg); buffer, err := core.new_file_buffer(context.allocator, arg);
@ -133,7 +197,8 @@ main :: proc() {
buffer := &state.buffers[state.current_buffer]; 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(); raylib.BeginDrawing();