From 152cc709ce066aabdbf8c024960638e06b394fa6 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Mon, 30 Sep 2024 17:07:50 -0700 Subject: [PATCH] work on ctrl entity buttons in watch views --- src/raddbg/generated/raddbg.meta.c | 24 +++++-- src/raddbg/generated/raddbg.meta.h | 5 ++ src/raddbg/raddbg.mdesk | 31 ++++---- src/raddbg/raddbg_core.c | 66 ++++++++++++++++- src/raddbg/raddbg_views.c | 109 ++++++++++++++++++++++------- src/raddbg/raddbg_views.h | 1 + src/raddbg/raddbg_widgets.c | 1 + 7 files changed, 193 insertions(+), 44 deletions(-) diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 46f39503..1b36c0f4 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -702,6 +702,22 @@ RD_EntityKind_Nil, RD_EntityKind_Nil, }; +CTRL_EntityKind rd_collection_ctrl_entity_kind_table[12] = +{ +CTRL_EntityKind_Null, +CTRL_EntityKind_Null, +CTRL_EntityKind_Null, +CTRL_EntityKind_Null, +CTRL_EntityKind_Thread, +CTRL_EntityKind_Module, +CTRL_EntityKind_Null, +CTRL_EntityKind_Null, +CTRL_EntityKind_Null, +CTRL_EntityKind_Null, +CTRL_EntityKind_Null, +CTRL_EntityKind_Null, +}; + EV_ViewRuleExprExpandInfoHookFunctionType * rd_collection_expr_expand_info_hook_function_table[12] = { EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(watches), @@ -740,8 +756,8 @@ EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watches), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(targets), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(breakpoints), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watch_pins), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), +EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(threads), +EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(modules), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(globals), @@ -756,8 +772,8 @@ EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(watches), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(targets), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(breakpoints), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(watch_pins), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity), +EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(threads), +EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(modules), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(globals), diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index 0cfa0e72..5c6df18a 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -672,6 +672,8 @@ EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches); EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(targets); EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(breakpoints); EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watch_pins); +EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(threads); +EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(modules); EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(globals); EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(thread_locals); EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(types); @@ -680,6 +682,8 @@ EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches); EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(targets); EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(breakpoints); EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watch_pins); +EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(threads); +EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(modules); EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(globals); EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(thread_locals); EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(types); @@ -753,6 +757,7 @@ extern String8 rd_binding_version_remap_new_name_table[7]; extern String8 rd_icon_kind_text_table[69]; extern String8 rd_collection_name_table[12]; extern RD_EntityKind rd_collection_entity_kind_table[12]; +extern CTRL_EntityKind rd_collection_ctrl_entity_kind_table[12]; extern EV_ViewRuleExprExpandInfoHookFunctionType * rd_collection_expr_expand_info_hook_function_table[12]; extern EV_ViewRuleExprExpandRangeInfoHookFunctionType * rd_collection_expr_expand_range_info_hook_function_table[12]; extern EV_ViewRuleExprExpandIDFromNumHookFunctionType * rd_collection_expr_expand_id_from_num_hook_function_table[12]; diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 25c30791..20a76fdc 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -818,21 +818,21 @@ RD_IconTable: //////////////////////////////// //~ rjf: Collections -@table(name entity_kind id_space) +@table(name entity_kind ctrl_entity_kind id_space) RD_CollectionTable: { - {watches Watch x} - {targets Target x} - {breakpoints Breakpoint x} - {watch_pins WatchPin x} - {threads Nil -} - {modules Nil -} - {locals Nil -} - {registers Nil -} - {globals Nil x} - {thread_locals Nil x} - {types Nil x} - {procedures Nil x} + {watches Watch Null x} + {targets Target Null x} + {breakpoints Breakpoint Null x} + {watch_pins WatchPin Null x} + {threads Nil Thread x} + {modules Nil Module x} + {locals Nil Null -} + {registers Nil Null -} + {globals Nil Null x} + {thread_locals Nil Null x} + {types Nil Null x} + {procedures Nil Null x} } @gen @@ -854,6 +854,11 @@ RD_CollectionTable: @expand(RD_CollectionTable a) `RD_EntityKind_$(a.entity_kind)`, } +@data(CTRL_EntityKind) rd_collection_ctrl_entity_kind_table: +{ + @expand(RD_CollectionTable a) `CTRL_EntityKind_$(a.ctrl_entity_kind)`, +} + @data(`EV_ViewRuleExprExpandInfoHookFunctionType *`) rd_collection_expr_expand_info_hook_function_table: { @expand(RD_CollectionTable a) `EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME($(a.name))` diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index e24faab8..3c244ede 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1876,6 +1876,44 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, Vec4F32 secon dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, secondary_color, str8_lit(" ")); String8 name = rd_name_from_ctrl_entity(arena, entity); dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, color, name); + if(entity->kind == CTRL_EntityKind_Thread) + { + F32 ext_size = size*0.95f; + dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, secondary_color, str8_lit(" ")); + DI_Scope *di_scope = di_scope_open(); + CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); + Arch arch = entity->arch; + CTRL_Unwind unwind = d_query_cached_unwind_from_thread(entity); + for(U64 idx = 0, limit = 6; idx < unwind.frames.count && idx < limit; idx += 1) + { + CTRL_UnwindFrame *f = &unwind.frames.v[unwind.frames.count - 1 - idx]; + U64 rip_vaddr = regs_rip_from_arch_block(arch, f->regs); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); + U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); + if(rdi != &di_rdi_parsed_nil) + { + RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, rip_voff); + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &name.size); + name = push_str8_copy(arena, name); + if(name.size != 0) + { + dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), ext_size, rd_rgba_from_theme_color(RD_ThemeColor_CodeSymbol), name); + if(idx+1 < unwind.frames.count) + { + dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), ext_size, secondary_color, str8_lit(" > ")); + if(idx+1 == limit) + { + dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), ext_size, secondary_color, str8_lit("...")); + } + } + } + } + } + di_scope_close(di_scope); + } return result; } @@ -7955,8 +7993,12 @@ EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watch_pins) { return rd_ev_vie EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(threads) { return rd_ev_view_rule_expr_expand_info__meta_ctrl_entities(arena, view, filter, expr, params, CTRL_EntityKind_Thread); } EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(threads) { return rd_ev_view_rule_expr_expand_range_info__meta_ctrl_entities(arena, view, filter, expr, params, idx_range, user_data, CTRL_EntityKind_Thread); } +EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(threads) { return rd_ev_view_rule_expr_id_from_num__meta_ctrl_entities(num, user_data, CTRL_EntityKind_Thread); } +EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(threads) { return rd_ev_view_rule_expr_num_from_id__meta_ctrl_entities(id, user_data, CTRL_EntityKind_Thread); } EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(modules) { return rd_ev_view_rule_expr_expand_info__meta_ctrl_entities(arena, view, filter, expr, params, CTRL_EntityKind_Module); } EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(modules) { return rd_ev_view_rule_expr_expand_range_info__meta_ctrl_entities(arena, view, filter, expr, params, idx_range, user_data, CTRL_EntityKind_Module); } +EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(modules) { return rd_ev_view_rule_expr_id_from_num__meta_ctrl_entities(num, user_data, CTRL_EntityKind_Module); } +EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(modules) { return rd_ev_view_rule_expr_num_from_id__meta_ctrl_entities(id, user_data, CTRL_EntityKind_Module); } //- rjf: locals @@ -8224,13 +8266,33 @@ rd_ev_view_rule_expr_expand_range_info__meta_ctrl_entities(Arena *arena, EV_View internal U64 rd_ev_view_rule_expr_id_from_num__meta_ctrl_entities(U64 num, void *user_data, CTRL_EntityKind kind) { - + RD_CtrlEntityExpandAccel *accel = (RD_CtrlEntityExpandAccel *)user_data; + U64 id = 0; + if(1 <= num && num <= accel->entities.count) + { + id = d_hash_from_string(str8_struct(&accel->entities.v[num-1]->handle)); + } + return id; } internal U64 rd_ev_view_rule_expr_num_from_id__meta_ctrl_entities(U64 id, void *user_data, CTRL_EntityKind kind) { - + RD_CtrlEntityExpandAccel *accel = (RD_CtrlEntityExpandAccel *)user_data; + U64 num = 0; + if(id != 0) + { + for EachIndex(idx, accel->entities.count) + { + U64 idx_id = d_hash_from_string(str8_struct(&accel->entities.v[idx]->handle)); + if(idx_id == id) + { + num = idx+1; + break; + } + } + } + return num; } typedef struct RD_DebugInfoTableExpandAccel RD_DebugInfoTableExpandAccel; diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 2d5233e2..029b65c7 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -831,18 +831,35 @@ rd_watch_view_row_info_from_row(EV_Row *row) // rjf: determine collection entity kind, if any RD_EntityKind collection_entity_kind = RD_EntityKind_Nil; + CTRL_EntityKind collection_ctrl_entity_kind = CTRL_EntityKind_Null; for EachElement(idx, rd_collection_name_table) { if(str8_match(type->name, rd_collection_name_table[idx], 0)) { collection_entity_kind = rd_collection_entity_kind_table[idx]; + collection_ctrl_entity_kind = rd_collection_ctrl_entity_kind_table[idx]; break; } } - // rjf: extract collection entities, if any - RD_Entity *entity = rd_entity_from_id(key.child_id); + // rjf: extract collection entity, if any + RD_Entity *entity = &d_nil_entity; + if(collection_entity_kind != RD_EntityKind_Nil) + { + entity = rd_entity_from_id(key.child_id); + } + + // rjf: extract collection CTRL_Entity *ctrl_entity = &ctrl_entity_nil; + if(collection_ctrl_entity_kind != CTRL_EntityKind_Null && block->expand_view_rule_info_user_data != 0) + { + U64 block_relative_num = block->expand_view_rule_info->expr_expand_num_from_id(key.child_id, block->expand_view_rule_info_user_data); + RD_CtrlEntityExpandAccel *accel = block->expand_view_rule_info_user_data; + if(1 <= block_relative_num && block_relative_num <= accel->entities.count) + { + ctrl_entity = accel->entities.v[block_relative_num-1]; + } + } // rjf: extract callstack thread, if any CTRL_Entity *thread = &ctrl_entity_nil; @@ -892,12 +909,13 @@ rd_watch_view_row_info_from_row(EV_Row *row) } // rjf: fill - info.collection_entity_kind = collection_entity_kind; - info.collection_entity = entity; - info.collection_ctrl_entity = ctrl_entity; - info.callstack_thread = thread; - info.callstack_unwind_index = unwind_count; - info.callstack_inline_depth = inline_depth; + info.collection_entity_kind = collection_entity_kind; + info.collection_entity = entity; + info.collection_ctrl_entity_kind = collection_ctrl_entity_kind; + info.collection_ctrl_entity = ctrl_entity; + info.callstack_thread = thread; + info.callstack_unwind_index = unwind_count; + info.callstack_inline_depth = inline_depth; di_scope_close(di_scope); scratch_end(scratch); @@ -931,6 +949,10 @@ rd_watch_view_row_kind_from_flags_row_info(RD_WatchViewFlags flags, EV_Row *row, { row_kind = RD_WatchViewRowKind_PrettyEntityControls; } + else if(flags & RD_WatchViewFlag_PrettyEntityRows && info->collection_ctrl_entity_kind != CTRL_EntityKind_Null) + { + row_kind = RD_WatchViewRowKind_PrettyEntityControls; + } scratch_end(scratch); return row_kind; } @@ -2401,7 +2423,9 @@ rd_watch_view_build(RD_WatchViewState *ewv, RD_WatchViewFlags flags, String8 roo { //- rjf: unpack RD_EntityKind collection_entity_kind = row_info.collection_entity_kind; + CTRL_EntityKind collection_ctrl_entity_kind = row_info.collection_ctrl_entity_kind; RD_Entity *entity = row_info.collection_entity; + CTRL_Entity *ctrl_entity = row_info.collection_ctrl_entity; B32 entity_box_selected = (row_selected && selection_tbl.min.x <= 1 && 1 <= selection_tbl.max.x); //- rjf: pick palette @@ -2439,25 +2463,21 @@ rd_watch_view_build(RD_WatchViewState *ewv, RD_WatchViewFlags flags, String8 roo { UI_Parent(entity_box) { - // rjf: build expander, title - if(!rd_entity_is_nil(entity)) + UI_PrefWidth(ui_em(2.f, 1.f)) if(ui_pressed(ui_expander(row_expanded, str8_lit("###expanded")))) { - UI_PrefWidth(ui_em(2.f, 1.f)) if(ui_pressed(ui_expander(row_expanded, str8_lit("###expanded")))) + next_row_expanded = !row_expanded; + } + DR_FancyStringList fstrs = rd_title_fstrs_from_entity(scratch.arena, entity, ui_top_palette()->text_weak, ui_top_font_size()); + UI_Box *title_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); + ui_box_equip_display_fancy_strings(title_box, &fstrs); + UI_Signal sig = ui_signal_from_box(entity_box); + if(ui_clicked(sig)) + { + if(entity->kind == RD_EntityKind_Target) { - next_row_expanded = !row_expanded; - } - DR_FancyStringList fstrs = rd_title_fstrs_from_entity(scratch.arena, entity, ui_top_palette()->text_weak, ui_top_font_size()); - UI_Box *title_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(title_box, &fstrs); - UI_Signal sig = ui_signal_from_box(entity_box); - if(ui_clicked(sig)) - { - if(entity->kind == RD_EntityKind_Target) - { - rd_cmd(sig.event_flags & OS_Modifier_Ctrl && entity->disabled ? RD_CmdKind_EnableEntity : - sig.event_flags & OS_Modifier_Ctrl && !entity->disabled ? RD_CmdKind_DisableEntity : - RD_CmdKind_SelectEntity, .entity = rd_handle_from_entity(entity)); - } + rd_cmd(sig.event_flags & OS_Modifier_Ctrl && entity->disabled ? RD_CmdKind_EnableEntity : + sig.event_flags & OS_Modifier_Ctrl && !entity->disabled ? RD_CmdKind_DisableEntity : + RD_CmdKind_SelectEntity, .entity = rd_handle_from_entity(entity)); } } } @@ -2499,6 +2519,45 @@ rd_watch_view_build(RD_WatchViewState *ewv, RD_WatchViewFlags flags, String8 roo } } } + + //- rjf: build ctrl entity box + if(ctrl_entity != &ctrl_entity_nil) + { + ui_set_next_hover_cursor(OS_Cursor_HandPoint); + UI_Box *entity_box = &ui_nil_box; + UI_FocusHot(entity_box_selected ? UI_FocusKind_On : UI_FocusKind_Off) UI_Palette(palette) + { + entity_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + "###entity_%p", ctrl_entity); + } + { + UI_Parent(entity_box) + { + // rjf: build expander, title + UI_PrefWidth(ui_em(2.f, 1.f)) if(ui_pressed(ui_expander(row_expanded, str8_lit("###expanded")))) + { + next_row_expanded = !row_expanded; + } + DR_FancyStringList fstrs = rd_title_fstrs_from_ctrl_entity(scratch.arena, ctrl_entity, ui_top_palette()->text_weak, ui_top_font_size()); + UI_Box *title_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); + ui_box_equip_display_fancy_strings(title_box, &fstrs); + UI_Signal sig = ui_signal_from_box(entity_box); + if(ui_clicked(sig)) + { + if(entity->kind == RD_EntityKind_Target) + { + rd_cmd(sig.event_flags & OS_Modifier_Ctrl && entity->disabled ? RD_CmdKind_EnableEntity : + sig.event_flags & OS_Modifier_Ctrl && !entity->disabled ? RD_CmdKind_DisableEntity : + RD_CmdKind_SelectEntity, .entity = rd_handle_from_entity(entity)); + } + } + } + } + } }break; //////////////////// diff --git a/src/raddbg/raddbg_views.h b/src/raddbg/raddbg_views.h index 1216e99a..a6e8b0ea 100644 --- a/src/raddbg/raddbg_views.h +++ b/src/raddbg/raddbg_views.h @@ -122,6 +122,7 @@ struct RD_WatchViewRowInfo { RD_EntityKind collection_entity_kind; RD_Entity *collection_entity; + CTRL_EntityKind collection_ctrl_entity_kind; CTRL_Entity *collection_ctrl_entity; CTRL_Entity *callstack_thread; U64 callstack_unwind_index; diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index b797dbc6..1a633dc4 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -318,6 +318,7 @@ rd_cmd_spec_button(String8 name) ui_set_next_flags(UI_BoxFlag_Clickable); ui_set_next_group_key(ui_key_zero()); UI_PrefWidth(ui_children_sum(1)) + UI_Column UI_Padding(ui_em(0.5f, 1.f)) UI_FontSize(ui_top_font_size()*0.95f) UI_HeightFill UI_NamedRow(str8_lit("###bindings")) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_FastpathCodepoint(0)