4coder/4ed_command.cpp

269 lines
6.7 KiB
C++

/*
* Mr. 4th Dimention - Allen Webster
*
* 19.08.2015
*
* Command management functions
*
*/
// TOP
internal i32
get_or_add_map_index(Mapping *mapping, i32 mapid){
i32 user_map_count = mapping->user_map_count;
i32 *map_id_table = mapping->map_id_table;
i32 result = 0;
for (; result < user_map_count; ++result){
if (map_id_table[result] == mapid){
break;
}
if (map_id_table[result] == -1){
map_id_table[result] = mapid;
break;
}
}
return(result);
}
internal i32
get_map_index(Mapping *mapping, i32 mapid){
i32 user_map_count = mapping->user_map_count;
i32 *map_id_table = mapping->map_id_table;
i32 result = 0;
for (; result < user_map_count; ++result){
if (map_id_table[result] == mapid){
break;
}
}
return(result);
}
internal Command_Map*
get_map_base(Mapping *mapping, i32 mapid, b32 add){
Command_Map *map = 0;
if (mapid < mapid_global){
i32 map_index = 0;
if (add){
map_index = get_or_add_map_index(mapping, mapid);
}
else{
map_index = get_map_index(mapping, mapid);
}
if (map_index < mapping->user_map_count){
map = &mapping->user_maps[map_index];
}
}
else if (mapid == mapid_global){
map = &mapping->map_top;
}
else if (mapid == mapid_file){
map = &mapping->map_file;
}
else if (mapid == mapid_ui){
map = &mapping->map_ui;
}
return(map);
}
internal Command_Map*
get_or_add_map(Mapping *mapping, i32 mapid){
Command_Map *map = get_map_base(mapping, mapid, true);
return(map);
}
internal Command_Map*
get_map(Mapping *mapping, i32 mapid){
Command_Map *map = get_map_base(mapping, mapid, false);
return(map);
}
#define COMMAND_HASH_EMPTY 0
#define COMMAND_HASH_ERASED max_u64
internal u64
map_hash(Key_Code event_code, u8 modifiers){
u64 result = (event_code << 8) | modifiers;
return(result);
}
internal b32
map_add(Command_Map *map, Key_Code event_code, u8 modifiers, Custom_Command_Function *custom){
b32 result = false;
Assert(map->count * 8 < map->max * 7);
u64 hash = map_hash(event_code, modifiers);
u32 max = map->max;
u32 index = hash % max;
Command_Binding entry = map->commands[index];
for (; entry.custom != 0 && entry.hash != COMMAND_HASH_ERASED;){
if (entry.hash == hash){
result = true;
break;
}
index = (index + 1) % max;
entry = map->commands[index];
}
Command_Binding bind = {};
bind.custom = custom;
bind.hash = hash;
map->commands[index] = bind;
if (!result){
++map->count;
}
return(result);
}
internal b32
map_find_entry(Command_Map *map, Key_Code event_code, u8 modifiers, u32 *index_out){
u64 hash = map_hash(event_code, modifiers);
u32 max = map->max;
u32 index = hash % max;
b32 result = false;
Command_Binding entry = map->commands[index];
for (; entry.custom != 0;){
if (entry.hash == hash){
*index_out = index;
result = true;
break;
}
index = (index + 1) % max;
entry = map->commands[index];
}
return(result);
}
internal b32
map_find(Command_Map *map, Key_Code event_code, u8 modifiers, Command_Binding *bind_out){
u32 index = 0;
b32 result = map_find_entry(map, event_code, modifiers, &index);
if (result){
*bind_out = map->commands[index];
}
return(result);
}
internal b32
map_drop(Command_Map *map, Key_Code event_code, u8 modifiers){
u32 index = 0;
b32 result = map_find_entry(map, event_code, modifiers, &index);
if (result){
map->commands[index].custom = 0;
map->commands[index].hash = COMMAND_HASH_ERASED;
}
return(result);
}
internal void
map_init(Command_Map *map, Cursor *cursor, i32 max, i32 parent){
Assert(max >= 6);
Assert(map->commands == 0);
map->parent = parent;
map->commands = push_array_zero(cursor, Command_Binding, max);
map->count = 0;
map->max = max;
block_zero_array(map->vanilla_keyboard_default);
}
internal b32
map_get_modifiers_hash(u8 modifiers, u32 *hash_out){
b32 result = true;
u32 hash = 0;
if (modifiers & MDFR_SHIFT){
hash += MDFR_SHIFT;
}
if (modifiers & MDFR_CTRL){
hash += MDFR_CTRL;
}
if (modifiers & MDFR_CMND){
hash += MDFR_CMND;
}
if (modifiers & MDFR_ALT){
hash += MDFR_ALT;
}
*hash_out = hash;
return(result);
}
internal void
map_get_vanilla_keyboard_default(Command_Map *map, u8 command, Command_Binding *bind_out){
u32 modifiers_hashed = 0;
if (map_get_modifiers_hash(command, &modifiers_hashed)){
*bind_out = map->vanilla_keyboard_default[modifiers_hashed];
}
}
internal Command_Binding
map_extract(Command_Map *map, Key_Event_Data key){
Command_Binding bind = {};
b32 ctrl = key.modifiers[MDFR_CONTROL_INDEX];
b32 alt = key.modifiers[MDFR_ALT_INDEX];
b32 command = key.modifiers[MDFR_COMMAND_INDEX];
b32 shift = key.modifiers[MDFR_SHIFT_INDEX];
u8 mod_flags = MDFR_NONE;
if (ctrl) mod_flags |= MDFR_CTRL;
if (alt) mod_flags |= MDFR_ALT;
if (command) mod_flags |= MDFR_CMND;
if (shift) mod_flags |= MDFR_SHIFT;
Key_Code code = key.character_no_caps_lock;
if (code == 0){
code = key.keycode;
map_find(map, code, mod_flags, &bind);
}
else{
if (code != '\n' && code != '\t' && code != ' '){
mod_flags &= ~(MDFR_SHIFT);
}
map_find(map, code, mod_flags, &bind);
if (bind.custom == 0){
map_get_vanilla_keyboard_default(map, mod_flags, &bind);
}
}
return(bind);
}
internal Command_Binding
map_extract_recursive(Mapping *mapping, i32 map_id, Key_Event_Data key){
Command_Map *map = get_map(mapping, map_id);
if (map == 0){
map = &mapping->map_top;
}
Command_Map *visited_maps[16] = {};
i32 visited_top = 0;
Command_Binding cmd_bind = {};
for (; map != 0; ){
cmd_bind = map_extract(map, key);
if (cmd_bind.custom == 0){
if (visited_top < ArrayCount(visited_maps)){
visited_maps[visited_top++] = map;
map = get_map(mapping, map->parent);
for (i32 i = 0; i < visited_top; ++i){
if (map == visited_maps[i]){
map = 0;
break;
}
}
}
else{
map = 0;
}
}
else{
map = 0;
}
}
return(cmd_bind);
}
// BOTTOM