float keymaps into config

This commit is contained in:
Ryan Fleury
2025-10-16 15:19:18 -07:00
parent 2f315911a5
commit 7844761748
13 changed files with 218 additions and 182 deletions
+111
View File
@@ -0,0 +1,111 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal CFG_KeyMap *
cfg_key_map_from_cfg(Arena *arena)
{
Temp scratch = scratch_begin(&arena, 1);
CFG_KeyMap *key_map = push_array(arena, CFG_KeyMap, 1);
{
key_map->name_slots_count = 4096;
key_map->name_slots = push_array(arena, CFG_KeyMapSlot, key_map->name_slots_count);
key_map->binding_slots_count = 4096;
key_map->binding_slots = push_array(arena, CFG_KeyMapSlot, key_map->binding_slots_count);
//- rjf: gather & parse all explicitly stored keybinding sets
CFG_NodePtrList keybindings_cfg_list = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("keybindings"));
for(CFG_NodePtrNode *n = keybindings_cfg_list.first; n != 0; n = n->next)
{
CFG_Node *keybindings_root = n->v;
for(CFG_Node *keybinding = keybindings_root->first; keybinding != &cfg_nil_node; keybinding = keybinding->next)
{
String8 name = {0};
CFG_Binding binding = {0};
for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next)
{
if(0){}
else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; }
else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; }
else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; }
else
{
OS_Key key = OS_Key_Null;
for EachEnumVal(OS_Key, k)
{
if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive))
{
key = k;
break;
}
}
if(key != OS_Key_Null)
{
binding.key = key;
}
else
{
name = child->string;
}
}
}
if(name.size != 0)
{
U64 name_hash = d_hash_from_string(name);
U64 binding_hash = d_hash_from_string(str8_struct(&binding));
U64 name_slot_idx = name_hash%key_map->name_slots_count;
U64 binding_slot_idx = binding_hash%key_map->binding_slots_count;
CFG_KeyMapNode *n = push_array(arena, CFG_KeyMapNode, 1);
n->cfg_id = keybinding->id;
n->name = push_str8_copy(arena, name);
n->binding = binding;
SLLQueuePush_N(key_map->name_slots[name_slot_idx].first, key_map->name_slots[name_slot_idx].last, n, name_hash_next);
SLLQueuePush_N(key_map->binding_slots[binding_slot_idx].first, key_map->binding_slots[binding_slot_idx].last, n, binding_hash_next);
}
}
}
}
scratch_end(scratch);
return key_map;
}
internal CFG_KeyMapNodePtrList
cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string)
{
CFG_KeyMapNodePtrList list = {0};
{
U64 hash = d_hash_from_string(string);
U64 slot_idx = hash%key_map->name_slots_count;
for(CFG_KeyMapNode *n = key_map->name_slots[slot_idx].first; n != 0; n = n->name_hash_next)
{
if(str8_match(n->name, string, 0))
{
CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1);
ptr->v = n;
SLLQueuePush(list.first, list.last, ptr);
list.count += 1;
}
}
}
return list;
}
internal CFG_KeyMapNodePtrList
cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding)
{
CFG_KeyMapNodePtrList list = {0};
{
U64 hash = d_hash_from_string(str8_struct(&binding));
U64 slot_idx = hash%key_map->binding_slots_count;
for(CFG_KeyMapNode *n = key_map->binding_slots[slot_idx].first; n != 0; n = n->binding_hash_next)
{
if(MemoryMatchStruct(&binding, &n->binding))
{
CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1);
ptr->v = n;
SLLQueuePush(list.first, list.last, ptr);
list.count += 1;
}
}
}
return list;
}
+59
View File
@@ -0,0 +1,59 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CONFIG_BINDINGS_H
#define CONFIG_BINDINGS_H
typedef struct CFG_Binding CFG_Binding;
struct CFG_Binding
{
OS_Key key;
OS_Modifiers modifiers;
};
typedef struct CFG_KeyMapNode CFG_KeyMapNode;
struct CFG_KeyMapNode
{
CFG_KeyMapNode *name_hash_next;
CFG_KeyMapNode *binding_hash_next;
CFG_ID cfg_id;
String8 name;
CFG_Binding binding;
};
typedef struct CFG_KeyMapNodePtr CFG_KeyMapNodePtr;
struct CFG_KeyMapNodePtr
{
CFG_KeyMapNodePtr *next;
CFG_KeyMapNode *v;
};
typedef struct CFG_KeyMapNodePtrList CFG_KeyMapNodePtrList;
struct CFG_KeyMapNodePtrList
{
CFG_KeyMapNodePtr *first;
CFG_KeyMapNodePtr *last;
U64 count;
};
typedef struct CFG_KeyMapSlot CFG_KeyMapSlot;
struct CFG_KeyMapSlot
{
CFG_KeyMapNode *first;
CFG_KeyMapNode *last;
};
typedef struct CFG_KeyMap CFG_KeyMap;
struct CFG_KeyMap
{
U64 name_slots_count;
CFG_KeyMapSlot *name_slots;
U64 binding_slots_count;
CFG_KeyMapSlot *binding_slots;
};
internal CFG_KeyMap *cfg_key_map_from_cfg(Arena *arena);
internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string);
internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding);
#endif // CONFIG_BINDINGS_H
@@ -1,8 +1,8 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CONFIG_H
#define CONFIG_H
#ifndef CONFIG_CORE_H
#define CONFIG_CORE_H
////////////////////////////////
//~ rjf: IDs
@@ -230,4 +230,4 @@ internal CFG_Node *cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Nod
//- rjf: deserialization
internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string);
#endif // CONFIG_H
#endif // CONFIG_CORE_H
+7
View File
@@ -0,0 +1,7 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "config_core.c"
#if defined(OS_GFX_H)
# include "config_bindings.c"
#endif
+12
View File
@@ -0,0 +1,12 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef CONFIG_INC_H
#define CONFIG_INC_H
#include "config_core.h"
#if defined(OS_GFX_H)
# include "config_bindings.h"
#endif
#endif // CONFIG_INC_H
+1 -1
View File
@@ -795,7 +795,7 @@ RD_CmdKindInfo rd_cmd_kind_info_table[245] =
{ str8_lit_comp("geo3d"), str8_lit_comp("Opens a Geometry (3D) tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab},
};
struct {String8 string; RD_Binding binding;} rd_default_binding_table[116] =
struct {String8 string; CFG_Binding binding;} rd_default_binding_table[116] =
{
{str8_lit_comp("kill_all"), {OS_Key_F5, 0 |OS_Modifier_Shift }},
{str8_lit_comp("step_into_inst"), {OS_Key_F11, 0 |OS_Modifier_Alt}},
+1 -2
View File
@@ -1301,7 +1301,7 @@ RD_DefaultBindingTable:
{ "toggle_dev_menu" D ctrl shift alt }
}
@data(`struct {String8 string; RD_Binding binding;}`) @c_file rd_default_binding_table:
@data(`struct {String8 string; CFG_Binding binding;}`) @c_file rd_default_binding_table:
{
@expand(RD_DefaultBindingTable a) ```{str8_lit_comp("$(a.name)"), {OS_Key_$(a.key), 0 $(a.ctrl != 0 -> `|OS_Modifier_Ctrl`) $(a.shift != 0 -> `|OS_Modifier_Shift`) $(a.alt != 0 -> `|OS_Modifier_Alt`)}}```;
}
@@ -1320,7 +1320,6 @@ RD_BindingVersionRemapTable:
{"address_breakpoint" "add_address_breakpoint"}
{"function_breakpoint" "add_function_breakpoint"}
{"toggle_breakpoint_cursor" "toggle_breakpoint"}
}
@data(String8) rd_binding_version_remap_old_name_table:
+13 -112
View File
@@ -356,48 +356,6 @@ rd_cfg_is_project_filtered(CFG_Node *cfg)
return result;
}
internal RD_KeyMapNodePtrList
rd_key_map_node_ptr_list_from_name(Arena *arena, String8 string)
{
RD_KeyMapNodePtrList list = {0};
{
U64 hash = d_hash_from_string(string);
U64 slot_idx = hash%rd_state->key_map->name_slots_count;
for(RD_KeyMapNode *n = rd_state->key_map->name_slots[slot_idx].first; n != 0; n = n->name_hash_next)
{
if(str8_match(n->name, string, 0))
{
RD_KeyMapNodePtr *ptr = push_array(arena, RD_KeyMapNodePtr, 1);
ptr->v = n;
SLLQueuePush(list.first, list.last, ptr);
list.count += 1;
}
}
}
return list;
}
internal RD_KeyMapNodePtrList
rd_key_map_node_ptr_list_from_binding(Arena *arena, RD_Binding binding)
{
RD_KeyMapNodePtrList list = {0};
{
U64 hash = d_hash_from_string(str8_struct(&binding));
U64 slot_idx = hash%rd_state->key_map->binding_slots_count;
for(RD_KeyMapNode *n = rd_state->key_map->binding_slots[slot_idx].first; n != 0; n = n->binding_hash_next)
{
if(MemoryMatchStruct(&binding, &n->binding))
{
RD_KeyMapNodePtr *ptr = push_array(arena, RD_KeyMapNodePtr, 1);
ptr->v = n;
SLLQueuePush(list.first, list.last, ptr);
list.count += 1;
}
}
}
return list;
}
internal Vec4F32
rd_hsva_from_cfg(CFG_Node *cfg)
{
@@ -10825,72 +10783,7 @@ rd_frame(void)
//
ProfScope("build key map from config")
{
//- rjf: set up table
rd_state->key_map = push_array(rd_frame_arena(), RD_KeyMap, 1);
RD_KeyMap *key_map = rd_state->key_map;
key_map->name_slots_count = 4096;
key_map->name_slots = push_array(rd_frame_arena(), RD_KeyMapSlot, key_map->name_slots_count);
key_map->binding_slots_count = 4096;
key_map->binding_slots = push_array(rd_frame_arena(), RD_KeyMapSlot, key_map->binding_slots_count);
//- rjf: gather & parse all explicitly stored keybinding sets
CFG_NodePtrList keybindings_cfg_list = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("keybindings"));
for(CFG_NodePtrNode *n = keybindings_cfg_list.first; n != 0; n = n->next)
{
CFG_Node *keybindings_root = n->v;
for(CFG_Node *keybinding = keybindings_root->first; keybinding != &cfg_nil_node; keybinding = keybinding->next)
{
String8 name = {0};
RD_Binding binding = {0};
for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next)
{
if(0){}
else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; }
else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; }
else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; }
else
{
OS_Key key = OS_Key_Null;
for EachEnumVal(OS_Key, k)
{
if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive))
{
key = k;
break;
}
}
if(key != OS_Key_Null)
{
binding.key = key;
}
else
{
name = child->string;
for(U64 idx = 0; idx < ArrayCount(rd_binding_version_remap_old_name_table); idx += 1)
{
if(str8_match(rd_binding_version_remap_old_name_table[idx], name, StringMatchFlag_CaseInsensitive))
{
name = rd_binding_version_remap_new_name_table[idx];
}
}
}
}
}
if(name.size != 0)
{
U64 name_hash = d_hash_from_string(name);
U64 binding_hash = d_hash_from_string(str8_struct(&binding));
U64 name_slot_idx = name_hash%key_map->name_slots_count;
U64 binding_slot_idx = binding_hash%key_map->binding_slots_count;
RD_KeyMapNode *n = push_array(rd_frame_arena(), RD_KeyMapNode, 1);
n->cfg_id = keybinding->id;
n->name = push_str8_copy(rd_frame_arena(), name);
n->binding = binding;
SLLQueuePush_N(key_map->name_slots[name_slot_idx].first, key_map->name_slots[name_slot_idx].last, n, name_hash_next);
SLLQueuePush_N(key_map->binding_slots[binding_slot_idx].first, key_map->binding_slots[binding_slot_idx].last, n, binding_hash_next);
}
}
}
rd_state->key_map = cfg_key_map_from_cfg(rd_frame_arena());
}
//////////////////////////////
@@ -10991,14 +10884,22 @@ rd_frame(void)
//- rjf: try hotkey presses
if(!take && event->kind == OS_EventKind_Press)
{
RD_Binding binding = {event->key, event->modifiers};
RD_KeyMapNodePtrList key_map_nodes = rd_key_map_node_ptr_list_from_binding(scratch.arena, binding);
CFG_Binding binding = {event->key, event->modifiers};
CFG_KeyMapNodePtrList key_map_nodes = cfg_key_map_node_ptr_list_from_binding(scratch.arena, rd_state->key_map, binding);
if(key_map_nodes.first != 0)
{
U32 hit_char = os_codepoint_from_modifiers_and_key(event->modifiers, event->key);
if(hit_char == 0 || allow_text_hotkeys)
{
rd_cmd(RD_CmdKind_RunCommand, .cmd_name = key_map_nodes.first->v->name);
String8 cmd_name = key_map_nodes.first->v->name;
for(U64 idx = 0; idx < ArrayCount(rd_binding_version_remap_old_name_table); idx += 1)
{
if(str8_match(rd_binding_version_remap_old_name_table[idx], cmd_name, StringMatchFlag_CaseInsensitive))
{
cmd_name = rd_binding_version_remap_new_name_table[idx];
}
}
rd_cmd(RD_CmdKind_RunCommand, .cmd_name = cmd_name);
if(allow_text_hotkeys)
{
os_text(&events, event->window, hit_char);
@@ -12313,7 +12214,7 @@ rd_frame(void)
for EachElement(idx, rd_default_binding_table)
{
String8 name = rd_default_binding_table[idx].string;
RD_Binding binding = rd_default_binding_table[idx].binding;
CFG_Binding binding = rd_default_binding_table[idx].binding;
CFG_Node *binding_root = cfg_node_new(rd_state->cfg, keybindings, str8_zero());
cfg_node_new(rd_state->cfg, binding_root, name);
cfg_node_new(rd_state->cfg, binding_root, os_g_key_cfg_string_table[binding.key]);
+1 -54
View File
@@ -4,57 +4,6 @@
#ifndef RADDBG_CORE_H
#define RADDBG_CORE_H
////////////////////////////////
//~ rjf: Key Bindings
typedef struct RD_Binding RD_Binding;
struct RD_Binding
{
OS_Key key;
OS_Modifiers modifiers;
};
typedef struct RD_KeyMapNode RD_KeyMapNode;
struct RD_KeyMapNode
{
RD_KeyMapNode *name_hash_next;
RD_KeyMapNode *binding_hash_next;
CFG_ID cfg_id;
String8 name;
RD_Binding binding;
};
typedef struct RD_KeyMapNodePtr RD_KeyMapNodePtr;
struct RD_KeyMapNodePtr
{
RD_KeyMapNodePtr *next;
RD_KeyMapNode *v;
};
typedef struct RD_KeyMapNodePtrList RD_KeyMapNodePtrList;
struct RD_KeyMapNodePtrList
{
RD_KeyMapNodePtr *first;
RD_KeyMapNodePtr *last;
U64 count;
};
typedef struct RD_KeyMapSlot RD_KeyMapSlot;
struct RD_KeyMapSlot
{
RD_KeyMapNode *first;
RD_KeyMapNode *last;
};
typedef struct RD_KeyMap RD_KeyMap;
struct RD_KeyMap
{
U64 name_slots_count;
RD_KeyMapSlot *name_slots;
U64 binding_slots_count;
RD_KeyMapSlot *binding_slots;
};
////////////////////////////////
//~ rjf: Evaluation Spaces
@@ -513,7 +462,7 @@ struct RD_State
RD_AmbiguousPathNode **ambiguous_path_slots;
// rjf: key map (constructed from-scratch each frame)
RD_KeyMap *key_map;
CFG_KeyMap *key_map;
// rjf: slot -> font tag map (constructed from-scratch each frame)
FNT_Tag font_slot_table[RD_FontSlot_COUNT];
@@ -686,8 +635,6 @@ internal Rng2F32 rd_target_rect_from_panel_node_child(Rng2F32 parent_rect, RD_Pa
internal Rng2F32 rd_target_rect_from_panel_node(Rng2F32 root_rect, RD_PanelNode *root, RD_PanelNode *panel);
internal B32 rd_cfg_is_project_filtered(CFG_Node *cfg);
internal RD_KeyMapNodePtrList rd_key_map_node_ptr_list_from_name(Arena *arena, String8 string);
internal RD_KeyMapNodePtrList rd_key_map_node_ptr_list_from_binding(Arena *arena, RD_Binding binding);
internal Vec4F32 rd_hsva_from_cfg(CFG_Node *cfg);
internal Vec4F32 rd_color_from_cfg(CFG_Node *cfg);
+2 -2
View File
@@ -43,8 +43,8 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(commands)
FuzzyMatchRangeList name_matches = fuzzy_match_find(scratch.arena, filter, display_name);
FuzzyMatchRangeList tags_matches = fuzzy_match_find(scratch.arena, filter, search_tags);
B32 binding_matches_good = 0;
RD_KeyMapNodePtrList bindings = rd_key_map_node_ptr_list_from_name(scratch.arena, code_name);
for(RD_KeyMapNodePtr *n = bindings.first; n != 0; n = n->next)
CFG_KeyMapNodePtrList bindings = cfg_key_map_node_ptr_list_from_name(scratch.arena, rd_state->key_map, code_name);
for(CFG_KeyMapNodePtr *n = bindings.first; n != 0; n = n->next)
{
String8 binding_text = os_string_from_modifiers_key(scratch.arena, n->v->binding.modifiers, n->v->binding.key);
FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, binding_text);
+2 -2
View File
@@ -223,7 +223,7 @@
#include "rdi/rdi_local.h"
#include "rdi_make/rdi_make_local.h"
#include "mdesk/mdesk.h"
#include "config/config.h"
#include "config/config_inc.h"
#include "content/content.h"
#include "file_stream/file_stream.h"
#include "text/text.h"
@@ -271,7 +271,7 @@
#include "rdi/rdi_local.c"
#include "rdi_make/rdi_make_local.c"
#include "mdesk/mdesk.c"
#include "config/config.c"
#include "config/config_inc.c"
#include "content/content.c"
#include "file_stream/file_stream.c"
#include "text/text.c"
+6 -6
View File
@@ -754,22 +754,22 @@ internal void
rd_cmd_binding_buttons(String8 name, String8 filter, B32 add_new)
{
Temp scratch = scratch_begin(0, 0);
RD_KeyMapNodePtrList key_map_nodes = rd_key_map_node_ptr_list_from_name(scratch.arena, name);
CFG_KeyMapNodePtrList key_map_nodes = cfg_key_map_node_ptr_list_from_name(scratch.arena, rd_state->key_map, name);
//- rjf: build buttons for each binding
UI_CornerRadius(ui_top_font_size()*0.5f) for(RD_KeyMapNodePtr *n = key_map_nodes.first; n != 0; n = n->next)
UI_CornerRadius(ui_top_font_size()*0.5f) for(CFG_KeyMapNodePtr *n = key_map_nodes.first; n != 0; n = n->next)
{
ui_spacer(ui_em(1.f, 1.f));
RD_Binding binding = n->v->binding;
CFG_Binding binding = n->v->binding;
B32 rebinding_active_for_this_binding = (rd_state->bind_change_active &&
str8_match(rd_state->bind_change_cmd_name, name, 0) &&
n->v->cfg_id == rd_state->bind_change_binding_id);
//- rjf: grab all conflicts
B32 has_conflicts = 0;
RD_KeyMapNodePtrList nodes_with_this_binding = rd_key_map_node_ptr_list_from_binding(scratch.arena, binding);
CFG_KeyMapNodePtrList nodes_with_this_binding = cfg_key_map_node_ptr_list_from_binding(scratch.arena, rd_state->key_map, binding);
{
for(RD_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next)
for(CFG_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next)
{
if(!str8_match(n->v->name, n2->v->name, 0))
{
@@ -840,7 +840,7 @@ rd_cmd_binding_buttons(String8 name, String8 filter, B32 add_new)
if(ui_hovering(sig) && has_conflicts) UI_Tooltip
{
UI_PrefWidth(ui_children_sum(1)) rd_error_label(str8_lit("This binding conflicts with those for:"));
for(RD_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next)
for(CFG_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next)
{
if(!str8_match(n2->v->name, n->v->name, 0))
{