Merge remote-tracking branch 'EpicGames/master' into odin

# Conflicts:
#	src/df/core/df_core.mdesk
#	src/df/core/generated/df_core.meta.c
This commit is contained in:
2024-05-18 12:03:19 -04:00
27 changed files with 2625 additions and 1190 deletions
+10
View File
@@ -234,4 +234,14 @@
# define LANG_C 0
#endif
////////////////////////////////
//~ rjf: Unsupported Errors
#if ARCH_X86
# error You tried to build in x86 (32 bit) mode, but currently, only building in x64 (64 bit) mode is supported.
#endif
#if !ARCH_X64
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
#endif
#endif // BASE_CONTEXT_CRACKING_H
+10 -7
View File
@@ -37,17 +37,17 @@ log_select(Log *log)
//~ rjf: Log Building/Clearing
internal void
log_msg(String8 string)
log_msg(LogMsgKind kind, String8 string)
{
if(log_active != 0 && log_active->top_scope != 0)
{
String8 string_copy = push_str8_copy(log_active->arena, string);
str8_list_push(log_active->arena, &log_active->top_scope->strings, string_copy);
str8_list_push(log_active->arena, &log_active->top_scope->strings[kind], string_copy);
}
}
internal void
log_msgf(char *fmt, ...)
log_msgf(LogMsgKind kind, char *fmt, ...)
{
if(log_active != 0)
{
@@ -55,7 +55,7 @@ log_msgf(char *fmt, ...)
va_list args;
va_start(args, fmt);
String8 string = push_str8fv(scratch.arena, fmt, args);
log_msg(string);
log_msg(kind, string);
va_end(args);
scratch_end(scratch);
}
@@ -76,10 +76,10 @@ log_scope_begin(void)
}
}
internal String8
internal LogScopeResult
log_scope_end(Arena *arena)
{
String8 result = {0};
LogScopeResult result = {0};
if(log_active != 0)
{
LogScope *scope = log_active->top_scope;
@@ -88,7 +88,10 @@ log_scope_end(Arena *arena)
SLLStackPop(log_active->top_scope);
if(arena != 0)
{
result = str8_list_join(arena, &scope->strings, 0);
for(EachEnumVal(LogMsgKind, kind))
{
result.strings[kind] = str8_list_join(arena, &scope->strings[kind], 0);
}
}
arena_pop_to(log_active->arena, scope->pos);
}
+22 -4
View File
@@ -7,12 +7,26 @@
////////////////////////////////
//~ rjf: Log Types
typedef enum LogMsgKind
{
LogMsgKind_Info,
LogMsgKind_UserError,
LogMsgKind_COUNT
}
LogMsgKind;
typedef struct LogScope LogScope;
struct LogScope
{
LogScope *next;
U64 pos;
String8List strings;
String8List strings[LogMsgKind_COUNT];
};
typedef struct LogScopeResult LogScopeResult;
struct LogScopeResult
{
String8 strings[LogMsgKind_COUNT];
};
typedef struct Log Log;
@@ -32,13 +46,17 @@ internal void log_select(Log *log);
////////////////////////////////
//~ rjf: Log Building
internal void log_msg(String8 string);
internal void log_msgf(char *fmt, ...);
internal void log_msg(LogMsgKind kind, String8 string);
internal void log_msgf(LogMsgKind kind, char *fmt, ...);
#define log_info(s) log_msg(LogMsgKind_Info, (s))
#define log_infof(fmt, ...) log_msgf(LogMsgKind_Info, (fmt), __VA_ARGS__)
#define log_user_error(s) log_msg(LogMsgKind_UserError, (s))
#define log_user_errorf(fmt, ...) log_msgf(LogMsgKind_UserError, (fmt), __VA_ARGS__)
////////////////////////////////
//~ rjf: Log Scopes
internal void log_scope_begin(void);
internal String8 log_scope_end(Arena *arena);
internal LogScopeResult log_scope_end(Arena *arena);
#endif // BASE_LOG_H
+39 -28
View File
@@ -743,6 +743,8 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list)
CTRL_Event *event = &n->v;
switch(event->kind)
{
default:{}break;
//- rjf: processes
case CTRL_EventKind_NewProc:
{
@@ -1794,8 +1796,17 @@ ctrl_thread__entry_point(void *p)
}
}
String8 log = log_scope_end(scratch.arena);
ctrl_thread__flush_log(log);
//- rjf: gather & output logs
LogScopeResult log = log_scope_end(scratch.arena);
ctrl_thread__flush_info_log(log.strings[LogMsgKind_Info]);
if(log.strings[LogMsgKind_UserError].size != 0)
{
CTRL_EventList evts = {0};
CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts);
evt->kind = CTRL_EventKind_Error;
evt->string = log.strings[LogMsgKind_UserError];
ctrl_c2u_push_events(&evts);
}
}
scratch_end(scratch);
@@ -1942,16 +1953,16 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
if(next_event_node != 0) CTRL_CtrlThreadLogScope
{
DMN_Event *ev = &next_event_node->v;
log_msgf("--- event ---\n");
log_msgf("kind: %S\n", dmn_event_kind_string_table[ev->kind]);
log_msgf("exception_kind: %S\n", dmn_exception_kind_string_table[ev->exception_kind]);
log_msgf("process: [%I64u]\n", ev->process.u64[0]);
log_msgf("thread: [%I64u]\n", ev->thread.u64[0]);
log_msgf("module: [%I64u]\n", ev->module.u64[0]);
log_msgf("arch: %S\n", string_from_architecture(ev->arch));
log_msgf("address: 0x%I64x\n", ev->address);
log_msgf("string: \"%S\"\n", ev->string);
log_msgf("ip_vaddr: 0x%I64x\n", ev->instruction_pointer);
log_infof("--- event ---\n");
log_infof("kind: %S\n", dmn_event_kind_string_table[ev->kind]);
log_infof("exception_kind: %S\n", dmn_exception_kind_string_table[ev->exception_kind]);
log_infof("process: [%I64u]\n", ev->process.u64[0]);
log_infof("thread: [%I64u]\n", ev->thread.u64[0]);
log_infof("module: [%I64u]\n", ev->module.u64[0]);
log_infof("arch: %S\n", string_from_architecture(ev->arch));
log_infof("address: 0x%I64x\n", ev->address);
log_infof("string: \"%S\"\n", ev->string);
log_infof("ip_vaddr: 0x%I64x\n", ev->instruction_pointer);
}
// rjf: determine if we should filter
@@ -2104,9 +2115,9 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
// rjf: run for new events
ProfScope("run for new events")
{
CTRL_CtrlThreadLogScope log_msgf("{dmn_ctrl_run ...");
CTRL_CtrlThreadLogScope log_infof("{dmn_ctrl_run ...");
DMN_EventList events = dmn_ctrl_run(scratch.arena, ctrl_ctx, run_ctrls);
CTRL_CtrlThreadLogScope log_msgf("}\n");
CTRL_CtrlThreadLogScope log_infof("}\n");
for(DMN_EventNode *src_n = events.first; src_n != 0; src_n = src_n->next)
{
DMN_EventNode *dst_n = ctrl_state->free_dmn_event_node;
@@ -2296,17 +2307,17 @@ ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size)
//- rjf: log flusher
internal void
ctrl_thread__flush_log(String8 string)
ctrl_thread__flush_info_log(String8 string)
{
os_append_data_to_file_path(ctrl_state->ctrl_thread_log_path, string);
}
internal void
ctrl_thread__end_and_flush_log(void)
ctrl_thread__end_and_flush_info_log(void)
{
Temp scratch = scratch_begin(0, 0);
String8 log = log_scope_end(scratch.arena);
ctrl_thread__flush_log(log);
LogScopeResult log = log_scope_end(scratch.arena);
ctrl_thread__flush_info_log(log.strings[LogMsgKind_Info]);
scratch_end(scratch);
}
@@ -2752,25 +2763,25 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
case DMN_EventKind_Trap:
{
hard_stop = 1;
log_msgf(">>> stepping >>> hard stop\n");
log_infof(">>> stepping >>> hard stop\n");
}break;
case DMN_EventKind_Exception:
case DMN_EventKind_Breakpoint:
{
use_stepping_logic = 1;
log_msgf(">>> stepping >>> exception or breakpoint - begin stepping logic\n");
log_infof(">>> stepping >>> exception or breakpoint - begin stepping logic\n");
}break;
case DMN_EventKind_CreateProcess:
{
DMN_TrapChunkList new_traps = {0};
ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, CTRL_MachineID_Local, event->process, &msg->user_bps, &new_traps);
log_msgf(">>> stepping >>> create process -> resolve new BPs\n");
log_infof(">>> stepping >>> create process -> resolve new BPs\n");
for(DMN_TrapChunkNode *n = new_traps.first; n != 0; n = n->next)
{
for(U64 idx = 0; idx < n->count; idx += 1)
{
DMN_Trap *trap = &n->v[idx];
log_msgf(" trap: {process:%I64d, vaddr:0x%I64x}\n", trap->process.u64[0], trap->vaddr);
log_infof(" trap: {process:%I64d, vaddr:0x%I64x}\n", trap->process.u64[0], trap->vaddr);
}
}
dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps);
@@ -2782,7 +2793,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, CTRL_MachineID_Local, event->process, event->module, &msg->user_bps, &new_traps);
dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps);
dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps);
log_msgf(">>> stepping >>> load module -> resolve new BPs\n");
log_infof(">>> stepping >>> load module -> resolve new BPs\n");
}break;
}
@@ -3156,13 +3167,13 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
{
hit_user_bp = 0;
hit_conditional_bp_but_filtered = 1;
log_msgf(">>> stepping >>> conditional breakpoint hit, but condition eval'd to 0, and so filtered\n");
log_infof(">>> stepping >>> conditional breakpoint hit, but condition eval'd to 0, and so filtered\n");
}
else
{
hit_user_bp = 1;
hit_conditional_bp_but_filtered = 0;
log_msgf(">>> stepping >>> conditional breakpoint hit\n");
log_infof(">>> stepping >>> conditional breakpoint hit\n");
break;
}
}
@@ -3183,8 +3194,8 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
}
}
log_msgf(">>> stepping >>> stepping logic - BP event -> hit_user_bp: %i\n", hit_user_bp);
log_msgf(">>> stepping >>> stepping logic - BP event -> hit_entry: %i\n", hit_entry);
log_infof(">>> stepping >>> stepping logic - BP event -> hit_user_bp: %i\n", hit_user_bp);
log_infof(">>> stepping >>> stepping logic - BP event -> hit_entry: %i\n", hit_entry);
temp_end(temp);
}
}
@@ -3418,7 +3429,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
{
stage_stop_cause = CTRL_EventCause_Finished;
}
log_msgf(">>> stepping >>> stage stop cause -> %i\n", stage_stop_cause);
log_infof(">>> stepping >>> stage stop cause -> %i\n", stage_stop_cause);
if(stage_stop_cause != CTRL_EventCause_Null)
{
stop_event = event;
+3 -3
View File
@@ -556,7 +556,7 @@ read_only global CTRL_Entity ctrl_entity_nil =
////////////////////////////////
//~ rjf: Logging Markup
#define CTRL_CtrlThreadLogScope DeferLoop(log_scope_begin(), ctrl_thread__end_and_flush_log())
#define CTRL_CtrlThreadLogScope DeferLoop(log_scope_begin(), ctrl_thread__end_and_flush_info_log())
////////////////////////////////
//~ rjf: Basic Type Functions
@@ -716,8 +716,8 @@ internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_
internal B32 ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size);
//- rjf: log flusher
internal void ctrl_thread__flush_log(String8 string);
internal void ctrl_thread__end_and_flush_log(void);
internal void ctrl_thread__flush_info_log(String8 string);
internal void ctrl_thread__end_and_flush_info_log(void);
//- rjf: msg kind implementations
internal void ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
+1 -1
View File
@@ -440,7 +440,7 @@ dasm_parse_thread__entry_point(void *p)
U64 jump_dst_vaddr = rel_voff;
// rjf: push strings derived from voff -> line info
if(params.style_flags & DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines)
if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines))
{
if(dbgi != &dbgi_parse_nil)
{
+19 -1
View File
@@ -1205,7 +1205,7 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options)
IsWow64Process(process_info.hProcess, &is_wow);
if(is_wow)
{
MessageBox(0, "Sorry, The RAD Debugger only debugs 64-bit applications currently.", "Process error", MB_OK|MB_ICONSTOP);
log_user_errorf("Only 64-bit applications can be debugged currently.");
DebugActiveProcessStop(process_info.dwProcessId);
TerminateProcess(process_info.hProcess,0xffffffff);
}
@@ -1242,6 +1242,23 @@ dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid)
{
result = 1;
dmn_w32_shared->new_process_pending = 1;
#if 0
// TODO(rjf): JIT debugging info
{
typedef struct JIT_DEBUG_INFO JIT_DEBUG_INFO;
struct JIT_DEBUG_INFO
{
DWORD dwSize;
DWORD dwProcessorArchitecture;
DWORD dwThreadID;
DWORD dwReserved0;
ULONG64 lpExceptionAddress;
ULONG64 lpExceptionRecord;
ULONG64 lpContextRecord;
};
}
#endif
}
return result;
}
@@ -1732,6 +1749,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
{
switch(child->kind)
{
default:{}break;
case DMN_W32_EntityKind_Thread:
{
DMN_Event *e = dmn_event_list_push(arena, &events);
+48 -17
View File
@@ -1799,7 +1799,7 @@ df_entity_alloc(DF_StateDeltaHistory *hist, DF_Entity *parent, DF_EntityKind kin
df_entity_notify_mutation(entity);
// rjf: log
log_msgf("new entity: %S $%I64d\n", df_g_entity_kind_display_string_table[kind], entity->id);
log_infof("new entity: %S $%I64d\n", df_g_entity_kind_display_string_table[kind], entity->id);
return entity;
}
@@ -1844,7 +1844,7 @@ df_entity_release(DF_StateDeltaHistory *hist, DF_Entity *entity)
t->e = child;
SLLQueuePush(first_task, last_task, t);
}
log_msgf("end entity: %S $%I64d\n", df_g_entity_kind_display_string_table[task->e->kind], task->e->id);
log_infof("end entity: %S $%I64d\n", df_g_entity_kind_display_string_table[task->e->kind], task->e->id);
df_state_delta_history_push_struct_delta(hist, &task->e->first);
df_state_delta_history_push_struct_delta(hist, &task->e->last);
df_state_delta_history_push_struct_delta(hist, &task->e->next);
@@ -6457,8 +6457,8 @@ df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec)
{
Temp scratch = scratch_begin(0, 0);
DF_Entity *entity = df_entity_from_handle(params->entity);
log_msgf("debug frontend command pushed: \"%S\"\n", spec->info.string);
#define HandleParamPrint(mem_name) if(!df_handle_match(df_handle_zero(), params->mem_name)) { log_msgf("| %s: [0x%I64x, 0x%I64x]\n", #mem_name, params->mem_name.u64[0], params->mem_name.u64[1]); }
log_infof("debug frontend command pushed: \"%S\"\n", spec->info.string);
#define HandleParamPrint(mem_name) if(!df_handle_match(df_handle_zero(), params->mem_name)) { log_infof("| %s: [0x%I64x, 0x%I64x]\n", #mem_name, params->mem_name.u64[0], params->mem_name.u64[1]); }
HandleParamPrint(window);
HandleParamPrint(panel);
HandleParamPrint(dest_panel);
@@ -6467,7 +6467,7 @@ df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec)
if(!df_entity_is_nil(entity))
{
String8 entity_name = df_display_string_from_entity(scratch.arena, entity);
log_msgf("| entity: \"%S\"\n", entity_name);
log_infof("| entity: \"%S\"\n", entity_name);
}
U64 idx = 0;
for(DF_HandleNode *n = params->entity_list.first; n != 0; n = n->next, idx += 1)
@@ -6476,22 +6476,40 @@ df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec)
if(!df_entity_is_nil(entity))
{
String8 entity_name = df_display_string_from_entity(scratch.arena, entity);
log_msgf("| entity_list[%I64u]: \"%S\"\n", idx, entity_name);
log_infof("| entity_list[%I64u]: \"%S\"\n", idx, entity_name);
}
}
if(!df_cmd_spec_is_nil(params->cmd_spec))
{
log_msgf("| cmd_spec: \"%S\"\n", params->cmd_spec->info.string);
log_infof("| cmd_spec: \"%S\"\n", params->cmd_spec->info.string);
}
if(params->string.size != 0) { log_infof("| string: \"%S\"\n", params->string); }
if(params->file_path.size != 0) { log_infof("| file_path: \"%S\"\n", params->file_path); }
if(params->text_point.line != 0){ log_infof("| text_point: [line:%I64d, col:%I64d]\n", params->text_point.line, params->text_point.column); }
if(params->vaddr != 0) { log_infof("| vaddr: 0x%I64x\n", params->vaddr); }
if(params->voff != 0) { log_infof("| voff: 0x%I64x\n", params->voff); }
if(params->index != 0) { log_infof("| index: 0x%I64x\n", params->index); }
if(params->id != 0) { log_infof("| id: 0x%I64x\n", params->id); }
if(params->os_event != 0)
{
String8 kind_string = str8_lit("<unknown>");
switch(params->os_event->kind)
{
default:{}break;
case OS_EventKind_Press: {kind_string = str8_lit("press");}break;
case OS_EventKind_Release: {kind_string = str8_lit("release");}break;
case OS_EventKind_MouseMove: {kind_string = str8_lit("mousemove");}break;
case OS_EventKind_Text: {kind_string = str8_lit("text");}break;
case OS_EventKind_Scroll: {kind_string = str8_lit("scroll");}break;
case OS_EventKind_WindowLoseFocus:{kind_string = str8_lit("losefocus");}break;
case OS_EventKind_WindowClose: {kind_string = str8_lit("closewindow");}break;
case OS_EventKind_FileDrop: {kind_string = str8_lit("filedrop");}break;
case OS_EventKind_Wakeup: {kind_string = str8_lit("wakeup");}break;
}
log_infof("| os_event->kind: %S\n", kind_string);
}
if(params->string.size != 0) { log_msgf("| string: \"%S\"\n", params->string); }
if(params->file_path.size != 0) { log_msgf("| file_path: \"%S\"\n", params->file_path); }
if(params->text_point.line != 0){ log_msgf("| text_point: [line:%I64d, col:%I64d]\n", params->text_point.line, params->text_point.column); }
if(params->vaddr != 0) { log_msgf("| vaddr: 0x%I64x\n", params->vaddr); }
if(params->voff != 0) { log_msgf("| voff: 0x%I64x\n", params->voff); }
if(params->index != 0) { log_msgf("| index: 0x%I64x\n", params->index); }
if(params->id != 0) { log_msgf("| id: 0x%I64x\n", params->id); }
#undef HandleParamPrint
log_msgf("--------------------------------\n");
log_infof("--------------------------------\n");
scratch_end(scratch);
}
df_cmd_list_push(df_state->root_cmd_arena, &df_state->root_cmds, params, spec);
@@ -6685,6 +6703,13 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
{
default:{}break;
//- rjf: errors
case CTRL_EventKind_Error:
{
log_user_error(event->string);
}break;
//- rjf: starts/stops
case CTRL_EventKind_Started:
@@ -7204,6 +7229,10 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
String8 args = df_entity_child_from_kind(target, DF_EntityKind_Arguments)->name;
String8 path = df_entity_child_from_kind(target, DF_EntityKind_ExecutionPath)->name;
String8 entry= df_entity_child_from_kind(target, DF_EntityKind_EntryPointName)->name;
name = str8_skip_chop_whitespace(name);
args = str8_skip_chop_whitespace(args);
path = str8_skip_chop_whitespace(path);
entry = str8_skip_chop_whitespace(entry);
if(path.size == 0)
{
String8List current_path_strs = {0};
@@ -8691,9 +8720,11 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
case DF_CoreCmdKind_RegisterAsJITDebugger:
{
#if OS_WINDOWS
String8 path_to_debugger_binary = os_string_from_system_path(scratch.arena, OS_SystemPath_Binary);
char filename_cstr[MAX_PATH] = {0};
GetModuleFileName(0, filename_cstr, sizeof(filename_cstr));
String8 debugger_binary_path = str8_cstring(filename_cstr);
String8 name8 = str8_lit("Debugger");
String8 data8 = push_str8f(scratch.arena, "%S --jit_pid:%%ld --jit_code:%%ld --jit_addr:0x%%p", path_to_debugger_binary);
String8 data8 = push_str8f(scratch.arena, "%S --jit_pid:%%ld --jit_code:%%ld --jit_addr:0x%%p", debugger_binary_path);
String16 name16 = str16_from_8(scratch.arena, name8);
String16 data16 = str16_from_8(scratch.arena, data8);
B32 likely_not_in_admin_mode = 0;
+1
View File
@@ -354,6 +354,7 @@ struct DF_CoreViewRuleSpecInfo
{
String8 string;
String8 display_string;
String8 schema;
String8 description;
DF_CoreViewRuleSpecInfoFlags flags;
DF_CoreViewRuleEvalResolutionHookFunctionType *eval_resolution;
+32 -21
View File
@@ -89,6 +89,7 @@ DF_CmdParamSlotTable:
{CmdSpec cmd_spec `struct DF_CmdSpec *`}
{ViewSpec view_spec `struct DF_ViewSpec *`}
{CfgNode cfg_node `struct DF_CfgNode *`}
{OSEvent os_event `struct OS_Event *`}
{VirtualAddr vaddr `U64`}
{VirtualOff voff `U64`}
{Index index `U64`}
@@ -114,6 +115,9 @@ DF_CoreCmdTable:// | | |
//- rjf: notifications
{Error 1 Null Nil 0 0 0 0 0 0 Null "error" "Error" "Notifies of an error." "" }
//- rjf: os event passthrough
{OSEvent 1 Null Nil 0 0 0 0 0 0 Null "os_event" "OS Event" "" "" }
//- rjf: low-level target control operations
{LaunchAndRun 0 EntityList Target 0 0 0 0 0 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" }
{LaunchAndInit 0 EntityList Target 0 0 0 0 0 1 PlayStepForward "launch_and_init" "Launch and Initialize" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" }
@@ -247,6 +251,11 @@ DF_CoreCmdTable:// | | |
{WriteUserData 1 Null Nil 0 0 0 0 0 0 Null "write_user_data" "Write User Data" "Writes user data to the active user file." "" }
{WriteProfileData 1 Null Nil 0 0 0 0 0 0 Null "write_profile_data" "Write Profile Data" "Writes profile data to the active profile file." "" }
//- rjf: meta controls
{Edit 0 Null Nil 0 0 0 0 0 0 Pencil "edit" "Edit" "Edits the current selection." "" }
{Accept 0 Null Nil 0 0 0 0 0 0 CheckFilled "accept" "Accept" "Accepts current changes, or answers prompts in the affirmative." "" }
{Cancel 0 Null Nil 0 0 0 0 0 0 X "cancel" "Cancel" "Rejects current changes, exits temporary menus, or answers prompts in the negative." "" }
//- rjf: directional movement & text controls
{MoveLeft 0 Null Nil 0 0 0 0 0 0 Null "move_left" "Move Left" "Moves the cursor or selection left." "" }
{MoveRight 0 Null Nil 0 0 0 0 0 0 Null "move_right" "Move Right" "Moves the cursor or selection right." "" }
@@ -272,6 +281,8 @@ DF_CoreCmdTable:// | | |
{MoveDownPageSelect 0 Null Nil 0 0 0 0 0 0 Null "move_down_page_select" "Move Down Page Select" "Moves the cursor or selection down one page, while selecting." "" }
{MoveUpWholeSelect 0 Null Nil 0 0 0 0 0 0 Null "move_up_whole_select" "Move Up Whole Select" "Moves the cursor or selection to the beginning of the relevant content, while selecting." "" }
{MoveDownWholeSelect 0 Null Nil 0 0 0 0 0 0 Null "move_down_whole_select" "Move Down Whole Select" "Moves the cursor or selection to the end of the relevant content, while selecting." "" }
{MoveUpReorder 0 Null Nil 0 0 0 0 0 0 Null "move_up_reorder" "Move Up Reorder" "Moves the cursor or selection up, while swapping the currently selected element with that upward." "" }
{MoveDownReorder 0 Null Nil 0 0 0 0 0 0 Null "move_down_reorder" "Move Down Reorder" "Moves the cursor or selection down, while swapping the currently selected element with that downward." "" }
{MoveHome 0 Null Nil 0 0 0 0 0 0 Null "move_home" "Move Home" "Moves the cursor to the beginning of the line." "" }
{MoveEnd 0 Null Nil 0 0 0 0 0 0 Null "move_end" "Move End" "Moves the cursor to the end of the line." "" }
{MoveHomeSelect 0 Null Nil 0 0 0 0 0 0 Null "move_home_select" "Move Home Select" "Moves the cursor to the beginning of the line, while selecting." "" }
@@ -493,28 +504,28 @@ DF_CoreCmdTable:// | | |
// For any view rules in this layer which also have graphical features, they
// are specified in both tables under the same name.
@table(name name_lower string ih ex er vb display_name docs description)
@table(name name_lower string ih ex er vb display_name docs schema description)
DF_CoreViewRuleTable:
{
{Null null "" - - - - "" - "" }
{Array array "array" - - x - "Array" x "Specifies that a pointer points to N elements, rather than only 1." }
{Slice slice "slice" - - x - "Slice" x "Specifies that a struct to be rendered as a slice." }
{List list "list" - - - x "List" x "Specifies that some struct, union, or class forms the top of a linked list, and the member which points at the following element in the list." }
{ByteSwap bswap "bswap" x - x - "Byte Swap" x "Specifies that all integer primitives should be byte-swapped, such that their endianness is reversed." }
{BaseDec base_dec "dec" x - - - "Decimal Base (Base 10)" x "Specifies that all integral evaluations should appear in base-10 form." }
{BaseBin base_bin "bin" x - - - "Binary Base (Base 2)" x "Specifies that all integral evaluations should appear in base-2 form." }
{BaseOct base_oct "oct" x - - - "Octal Base (Base 8)" x "Specifies that all integral evaluations should appear in base-8 form." }
{BaseHex base_hex "hex" x - - - "Hexadecimal Base (Base 16)" x "Specifies that all integral evaluations should appear in base-16 form." }
{Only only "only" x - - x "Only Specified Members" x "Specifies that only the specified members should appear in struct, union, or class evaluations." }
{Omit omit "omit" x - - x "Omit Specified Members" x "Omits a list of member names from appearing in struct, union, or class evaluations." }
{NoAddr no_addr "no_addr" x - - - "Disable Address Values" x "Displays only what pointers point to, if possible, without the pointer's address value." }
{RGBA rgba "rgba" - x - x "Color (RGBA)" x "Displays as a color, interpreting the data as encoding R, G, B, and A values." }
{Text text "text" - x - x "Text" x "Displays as text." }
{Disasm disasm "disasm" - x - x "Disassembly" x "Displays as disassembled instructions, interpreting the data as raw machine code." }
{Graph graph "graph" - x - x "Graph" x "Displays as a pointer graph, visualizing nodes and edges formed by pointers directly." }
{Bitmap bitmap "bitmap" - x - x "Bitmap" x "Displays as a bitmap, interpreting the data as raw pixel data." }
{Geo geo "geo" - x - x "Geometry" x "Displays as geometry, interpreting the data as vertex data." }
{OdinMap odin_map "odin_map" - x - x "Odin map" x "Specifies that a struct to be rendered as an Odin map type." }
{Null null "" - - - - "" - "" "" }
{Array array "array" - - x - "Array" x "x:{expr}" "Specifies that a pointer points to N elements, rather than only 1." }
{Slice slice "slice" - - x - "Slice" x "" "Specifies a struct of {data, len} should be rendered as a slice." }
{List list "list" - - - x "List" x "x:{member}" "Specifies that some struct, union, or class forms the top of a linked list, and the member which points at the following element in the list." }
{ByteSwap bswap "bswap" x - x - "Byte Swap" x "" "Specifies that all integer primitives should be byte-swapped, such that their endianness is reversed." }
{BaseDec base_dec "dec" x - - - "Decimal Base (Base 10)" x "" "Specifies that all integral evaluations should appear in base-10 form." }
{BaseBin base_bin "bin" x - - - "Binary Base (Base 2)" x "" "Specifies that all integral evaluations should appear in base-2 form." }
{BaseOct base_oct "oct" x - - - "Octal Base (Base 8)" x "" "Specifies that all integral evaluations should appear in base-8 form." }
{BaseHex base_hex "hex" x - - - "Hexadecimal Base (Base 16)" x "" "Specifies that all integral evaluations should appear in base-16 form." }
{Only only "only" x - - x "Only Specified Members" x "x:{member}" "Specifies that only the specified members should appear in struct, union, or class evaluations." }
{Omit omit "omit" x - - x "Omit Specified Members" x "x:{member}" "Omits a list of member names from appearing in struct, union, or class evaluations." }
{NoAddr no_addr "no_addr" x - - - "Disable Address Values" x "" "Displays only what pointers point to, if possible, without the pointer's address value." }
{RGBA rgba "rgba" - x - x "Color (RGBA)" x "" "Displays as a color, interpreting the data as encoding R, G, B, and A values." }
{Text text "text" - x - x "Text" x "x:{'lang':lang, 'size':expr}" "Displays as text." }
{Disasm disasm "disasm" - x - x "Disassembly" x "x:{'arch':arch, 'size':expr}" "Displays as disassembled instructions, interpreting the data as raw machine code." }
{Graph graph "graph" - x - x "Graph" x "" "Displays as a pointer graph, visualizing nodes and edges formed by pointers directly." }
{Bitmap bitmap "bitmap" - x - x "Bitmap" x "x:{'w':expr, 'h':expr, 'fmt':tex2dformat}" "Displays as a bitmap, interpreting the data as raw pixel data." }
{Geo geo "geo" - x - x "Geometry" x "x:{'count':expr, 'vertices_base':expr, 'vertices_size':expr}" "Displays as geometry, interpreting the data as vertex data." }
{OdinMap odin_map "odin_map" - x - x "Odin map" x "" "Specifies that a struct should be rendered as an Odin map type." }
}
////////////////////////////////
@@ -1823,7 +1834,7 @@ DF_DevToggleTable:
@data(DF_CoreViewRuleSpecInfo) @c_file df_g_core_view_rule_spec_info_table:
{
@expand(DF_CoreViewRuleTable a)
```{str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.display_name)"), str8_lit_comp("$(a.description)"), (DF_CoreViewRuleSpecInfoFlag_Inherited*$(a.ih == "x"))|(DF_CoreViewRuleSpecInfoFlag_Expandable*$(a.ex == "x"))|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*$(a.er == "x"))|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*$(a.vb == "x")), $(a.er == "x" -> "DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME("..a.name_lower..")") $(a.er != "x" -> 0), $(a.vb == "x" -> "DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME("..a.name_lower..")") $(a.vb != "x" -> 0), }```;
```{str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.display_name)"), str8_lit_comp("$(a.schema)"), str8_lit_comp("$(a.description)"), (DF_CoreViewRuleSpecInfoFlag_Inherited*$(a.ih == "x"))|(DF_CoreViewRuleSpecInfoFlag_Expandable*$(a.ex == "x"))|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*$(a.er == "x"))|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*$(a.vb == "x")), $(a.er == "x" -> "DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME("..a.name_lower..")") $(a.er != "x" -> 0), $(a.vb == "x" -> "DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME("..a.name_lower..")") $(a.vb != "x" -> 0), }```;
}
//- rjf: icon kinds
+9 -1
View File
@@ -53,6 +53,7 @@ DF_CoreCmdKind_Null,
DF_CoreCmdKind_Exit,
DF_CoreCmdKind_RunCommand,
DF_CoreCmdKind_Error,
DF_CoreCmdKind_OSEvent,
DF_CoreCmdKind_LaunchAndRun,
DF_CoreCmdKind_LaunchAndInit,
DF_CoreCmdKind_Kill,
@@ -146,6 +147,9 @@ DF_CoreCmdKind_ApplyUserData,
DF_CoreCmdKind_ApplyProfileData,
DF_CoreCmdKind_WriteUserData,
DF_CoreCmdKind_WriteProfileData,
DF_CoreCmdKind_Edit,
DF_CoreCmdKind_Accept,
DF_CoreCmdKind_Cancel,
DF_CoreCmdKind_MoveLeft,
DF_CoreCmdKind_MoveRight,
DF_CoreCmdKind_MoveUp,
@@ -170,6 +174,8 @@ DF_CoreCmdKind_MoveUpPageSelect,
DF_CoreCmdKind_MoveDownPageSelect,
DF_CoreCmdKind_MoveUpWholeSelect,
DF_CoreCmdKind_MoveDownWholeSelect,
DF_CoreCmdKind_MoveUpReorder,
DF_CoreCmdKind_MoveDownReorder,
DF_CoreCmdKind_MoveHome,
DF_CoreCmdKind_MoveEnd,
DF_CoreCmdKind_MoveHomeSelect,
@@ -380,6 +386,7 @@ DF_CmdParamSlot_TextPoint,
DF_CmdParamSlot_CmdSpec,
DF_CmdParamSlot_ViewSpec,
DF_CmdParamSlot_CfgNode,
DF_CmdParamSlot_OSEvent,
DF_CmdParamSlot_VirtualAddr,
DF_CmdParamSlot_VirtualOff,
DF_CmdParamSlot_Index,
@@ -407,6 +414,7 @@ TxtPt text_point;
struct DF_CmdSpec * cmd_spec;
struct DF_ViewSpec * view_spec;
struct DF_CfgNode * cfg_node;
struct OS_Event * os_event;
U64 vaddr;
U64 voff;
U64 index;
@@ -1526,7 +1534,7 @@ struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] =
{&DEV_updating_indicator, str8_lit_comp("updating_indicator")},
};
C_LINKAGE_BEGIN
extern Rng1U64 df_g_cmd_param_slot_range_table[21];
extern Rng1U64 df_g_cmd_param_slot_range_table[22];
extern DF_IconKind df_g_entity_kind_icon_kind_table[27];
extern String8 df_g_entity_kind_display_string_table[27];
extern String8 df_g_entity_kind_name_label_table[27];
+810 -180
View File
File diff suppressed because it is too large Load Diff
+33 -7
View File
@@ -108,13 +108,21 @@ enum
DF_ViewSpecFlag_TypingAutomaticallyFilters = (1<<6),
};
typedef enum DF_NameKind
{
DF_NameKind_Null,
DF_NameKind_EntityName,
DF_NameKind_COUNT
}
DF_NameKind;
typedef struct DF_ViewSpecInfo DF_ViewSpecInfo;
struct DF_ViewSpecInfo
{
DF_ViewSpecFlags flags;
String8 name;
String8 display_string;
enum DF_NameKind name_kind;
DF_NameKind name_kind;
DF_IconKind icon_kind;
DF_ViewSetupFunctionType *setup_hook;
DF_ViewStringFromStateFunctionType *string_from_state_hook;
@@ -408,6 +416,7 @@ struct DF_CodeSliceParams
F32 line_num_width_px;
F32 line_text_max_width_px;
DF_EntityList flash_ranges;
F32 margin_float_off_px;
};
typedef struct DF_CodeSliceSignal DF_CodeSliceSignal;
@@ -434,9 +443,14 @@ struct DF_CodeSliceSignal
typedef U32 DF_AutoCompListerFlags;
enum
{
DF_AutoCompListerFlag_Locals = (1<<0),
DF_AutoCompListerFlag_Registers = (1<<1),
DF_AutoCompListerFlag_ViewRules = (1<<2),
DF_AutoCompListerFlag_Locals = (1<<0),
DF_AutoCompListerFlag_Registers = (1<<1),
DF_AutoCompListerFlag_ViewRules = (1<<2),
DF_AutoCompListerFlag_ViewRuleParams= (1<<3),
DF_AutoCompListerFlag_Members = (1<<4),
DF_AutoCompListerFlag_Languages = (1<<5),
DF_AutoCompListerFlag_Architectures = (1<<6),
DF_AutoCompListerFlag_Tex2DFormats = (1<<7),
};
typedef struct DF_AutoCompListerItem DF_AutoCompListerItem;
@@ -472,6 +486,13 @@ struct DF_AutoCompListerItemArray
U64 count;
};
typedef struct DF_AutoCompListerParams DF_AutoCompListerParams;
struct DF_AutoCompListerParams
{
DF_AutoCompListerFlags flags;
String8List strings;
};
////////////////////////////////
//~ rjf: Per-Window State
@@ -517,9 +538,12 @@ struct DF_Window
// rjf: autocomplete lister state
U64 autocomp_last_frame_idx;
B32 autocomp_force_closed;
B32 autocomp_query_dirty;
UI_Key autocomp_root_key;
DF_CtrlCtx autocomp_ctrl_ctx;
DF_AutoCompListerFlags autocomp_lister_flags;
Arena *autocomp_lister_params_arena;
DF_AutoCompListerParams autocomp_lister_params;
U64 autocomp_cursor_off;
U8 autocomp_lister_query_buffer[1024];
U64 autocomp_lister_query_size;
F32 autocomp_open_t;
@@ -899,7 +923,7 @@ internal DF_Window *df_window_open(Vec2F32 size, OS_Handle preferred_monitor, DF
internal DF_Window *df_window_from_os_handle(OS_Handle os);
internal void df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, DF_CmdList *cmds);
internal void df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds);
////////////////////////////////
//~ rjf: Eval Viz
@@ -921,7 +945,9 @@ internal DF_AutoCompListerItemArray df_autocomp_lister_item_array_from_chunk_lis
internal int df_autocomp_lister_item_qsort_compare(DF_AutoCompListerItem *a, DF_AutoCompListerItem *b);
internal void df_autocomp_lister_item_array_sort__in_place(DF_AutoCompListerItemArray *array);
internal void df_set_autocomp_lister_query(DF_Window *ws, UI_Key root_key, DF_CtrlCtx ctrl_ctx, DF_AutoCompListerFlags flags, String8 query);
internal String8 df_autocomp_query_word_from_input_string_off(String8 input, U64 cursor_off);
internal DF_AutoCompListerParams df_view_rule_autocomp_lister_params_from_input_cursor(Arena *arena, String8 string, U64 cursor_off);
internal void df_set_autocomp_lister_query(DF_Window *ws, UI_Key root_key, DF_CtrlCtx ctrl_ctx, DF_AutoCompListerParams *params, String8 input, U64 cursor_off);
////////////////////////////////
//~ rjf: Search Strings
+9 -13
View File
@@ -90,6 +90,11 @@ DF_DefaultBindingTable:
{ "load_user" O ctrl shift alt }
{ "load_profile" O ctrl 0 alt }
//- rjf: meta controls
{ "edit" F2 0 0 0 }
{ "accept" Return 0 0 0 }
{ "cancel" Esc 0 0 0 }
//- rjf: directional movement & text controls
{ "move_left" Left 0 0 0 }
{ "move_right" Right 0 0 0 }
@@ -115,6 +120,8 @@ DF_DefaultBindingTable:
{ "move_down_page_select" PageDown 0 shift 0 }
{ "move_up_whole_select" Home ctrl shift 0 }
{ "move_down_whole_select" End ctrl shift 0 }
{ "move_up_reorder" Up 0 0 alt }
{ "move_down_reorder" Down 0 0 alt }
{ "move_home" Home 0 0 0 }
{ "move_end" End 0 0 0 }
{ "move_home_select" Home 0 shift 0 }
@@ -125,8 +132,10 @@ DF_DefaultBindingTable:
{ "backspace_single" Backspace 0 0 0 }
{ "backspace_chunk" Backspace ctrl 0 0 }
{ "copy" C ctrl 0 0 }
{ "copy" Insert ctrl 0 0 }
{ "cut" X ctrl 0 0 }
{ "paste" V ctrl 0 0 }
{ "paste" Insert 0 shift 0 }
{ "insert_text" Null 0 0 0 }
//- rjf: code navigation
@@ -178,13 +187,6 @@ DF_BindingVersionRemapTable:
////////////////////////////////
//~ rjf: Gfx Layer View Kinds
@table(name)
DF_NameKindTable:
{
{Null}
{EntityName}
}
@table(name, name_lower, display_string, name_kind, icon, parameterized_by_entity, can_serialize, can_serialize_entity_path, can_filter, filter_is_code, typing_automatically_filters, inc_in_docs, docs_desc)
DF_GfxViewTable:
{
@@ -414,12 +416,6 @@ DF_ThemePresetColorTable:
//- rjf: enums
@enum DF_NameKind:
{
@expand(DF_NameKindTable, a) `$(a.name)`,
COUNT,
}
@enum DF_GfxViewKind:
{
@expand(DF_GfxViewTable a) `$(a.name)`,
+956 -455
View File
File diff suppressed because it is too large Load Diff
+66 -40
View File
@@ -281,55 +281,70 @@ struct DF_EvalRoot
U8 *expr_buffer;
};
typedef enum DF_EvalWatchViewColumnKind
typedef enum DF_WatchViewColumnKind
{
DF_EvalWatchViewColumnKind_Expr,
DF_EvalWatchViewColumnKind_Value,
DF_EvalWatchViewColumnKind_Type,
DF_EvalWatchViewColumnKind_ViewRule,
DF_EvalWatchViewColumnKind_COUNT
DF_WatchViewColumnKind_Expr,
DF_WatchViewColumnKind_Value,
DF_WatchViewColumnKind_Type,
DF_WatchViewColumnKind_ViewRule,
DF_WatchViewColumnKind_COUNT
}
DF_EvalWatchViewColumnKind;
DF_WatchViewColumnKind;
typedef enum DF_EvalWatchViewFillKind
typedef enum DF_WatchViewFillKind
{
DF_EvalWatchViewFillKind_Mutable,
DF_EvalWatchViewFillKind_Registers,
DF_EvalWatchViewFillKind_Locals,
DF_EvalWatchViewFillKind_Globals,
DF_EvalWatchViewFillKind_ThreadLocals,
DF_EvalWatchViewFillKind_Types,
DF_EvalWatchViewFillKind_Procedures,
DF_EvalWatchViewFillKind_COUNT
DF_WatchViewFillKind_Mutable,
DF_WatchViewFillKind_Registers,
DF_WatchViewFillKind_Locals,
DF_WatchViewFillKind_Globals,
DF_WatchViewFillKind_ThreadLocals,
DF_WatchViewFillKind_Types,
DF_WatchViewFillKind_Procedures,
DF_WatchViewFillKind_COUNT
}
DF_EvalWatchViewFillKind;
DF_WatchViewFillKind;
typedef struct DF_EvalWatchViewPoint DF_EvalWatchViewPoint;
struct DF_EvalWatchViewPoint
typedef struct DF_WatchViewPoint DF_WatchViewPoint;
struct DF_WatchViewPoint
{
DF_EvalWatchViewColumnKind column_kind;
DF_WatchViewColumnKind column_kind;
DF_ExpandKey parent_key;
DF_ExpandKey key;
};
typedef struct DF_EvalWatchViewState DF_EvalWatchViewState;
struct DF_EvalWatchViewState
typedef struct DF_WatchViewTextEditState DF_WatchViewTextEditState;
struct DF_WatchViewTextEditState
{
DF_WatchViewTextEditState *pt_hash_next;
DF_WatchViewPoint pt;
TxtPt cursor;
TxtPt mark;
U8 input_buffer[1024];
U64 input_size;
U8 initial_buffer[1024];
U64 initial_size;
};
typedef struct DF_WatchViewState DF_WatchViewState;
struct DF_WatchViewState
{
B32 initialized;
// rjf: fill kind (way that the contents of the watch view are computed)
DF_EvalWatchViewFillKind fill_kind;
DF_WatchViewFillKind fill_kind;
// rjf; table cursor state
DF_EvalWatchViewPoint cursor;
DF_EvalWatchViewPoint mark;
DF_WatchViewPoint cursor;
DF_WatchViewPoint mark;
DF_WatchViewPoint next_cursor;
DF_WatchViewPoint next_mark;
// rjf: text input state
TxtPt input_cursor;
TxtPt input_mark;
U8 input_buffer[1024];
U64 input_size;
B32 input_editing;
Arena *text_edit_arena;
U64 text_edit_state_slots_count;
DF_WatchViewTextEditState dummy_text_edit_state;
DF_WatchViewTextEditState **text_edit_state_slots;
B32 text_editing;
// rjf: table column width state
F32 expr_column_pct;
@@ -454,27 +469,38 @@ internal DF_EntityListerItemArray df_entity_lister_item_array_from_list(Arena *a
internal void df_entity_lister_item_array_sort_by_strength__in_place(DF_EntityListerItemArray array);
////////////////////////////////
//~ rjf: Eval/Watch Views
//~ rjf: Watch Views
//- rjf: eval watch view instance -> eval view key
internal DF_EvalViewKey df_eval_view_key_from_eval_watch_view(DF_EvalWatchViewState *ewv);
internal DF_EvalViewKey df_eval_view_key_from_eval_watch_view(DF_WatchViewState *ewv);
//- rjf: root allocation/deallocation/mutation
internal DF_EvalRoot * df_eval_root_alloc(DF_View *view, DF_EvalWatchViewState *ews);
internal void df_eval_root_release(DF_EvalWatchViewState *ews, DF_EvalRoot *root);
internal DF_EvalRoot * df_eval_root_alloc(DF_View *view, DF_WatchViewState *ews);
internal void df_eval_root_release(DF_WatchViewState *ews, DF_EvalRoot *root);
internal void df_eval_root_equip_string(DF_EvalRoot *root, String8 string);
internal DF_EvalRoot * df_eval_root_from_string(DF_EvalWatchViewState *ews, String8 string);
internal DF_EvalRoot * df_eval_root_from_expand_key(DF_EvalWatchViewState *ews, DF_EvalView *eval_view, DF_ExpandKey expand_key);
internal DF_EvalRoot * df_eval_root_from_string(DF_WatchViewState *ews, String8 string);
internal DF_EvalRoot * df_eval_root_from_expand_key(DF_WatchViewState *ews, DF_EvalView *eval_view, DF_ExpandKey expand_key);
internal String8 df_string_from_eval_root(DF_EvalRoot *root);
internal DF_ExpandKey df_parent_expand_key_from_eval_root(DF_EvalRoot *root);
internal DF_ExpandKey df_expand_key_from_eval_root(DF_EvalRoot *root);
//- rjf: watch view points <-> table coordinates
internal B32 df_watch_view_point_match(DF_WatchViewPoint a, DF_WatchViewPoint b);
internal DF_WatchViewPoint df_watch_view_point_from_tbl(DF_EvalVizBlockList *blocks, Vec2S64 tbl);
internal Vec2S64 df_tbl_from_watch_view_point(DF_EvalVizBlockList *blocks, DF_WatchViewPoint pt);
//- rjf: table coordinates -> strings
internal String8 df_string_from_eval_viz_row_column_kind(Arena *arena, DF_EvalView *ev, TG_Graph *graph, RDI_Parsed *rdi, DF_EvalVizRow *row, DF_WatchViewColumnKind col_kind, B32 editable);
//- rjf: table coordinates -> text edit state
internal DF_WatchViewTextEditState *df_watch_view_text_edit_state_from_pt(DF_WatchViewState *wv, DF_WatchViewPoint pt);
//- rjf: windowed watch tree visualization
internal DF_EvalVizBlockList df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_EvalWatchViewState *ews);
internal DF_EvalVizBlockList df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews);
//- rjf: eval/watch views main hooks
internal void df_eval_watch_view_init(DF_EvalWatchViewState *ewv, DF_View *view, DF_EvalWatchViewFillKind fill_kind);
internal void df_eval_watch_view_cmds(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalWatchViewState *ewv, DF_CmdList *cmds);
internal void df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalWatchViewState *ewv, B32 modifiable, U32 default_radix, Rng2F32 rect);
internal void df_watch_view_init(DF_WatchViewState *ewv, DF_View *view, DF_WatchViewFillKind fill_kind);
internal void df_watch_view_cmds(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewState *ewv, DF_CmdList *cmds);
internal void df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewState *ewv, B32 modifiable, U32 default_radix, Rng2F32 rect);
#endif // DEBUG_FRONTEND_VIEWS_H
+8 -1
View File
@@ -598,7 +598,7 @@ str8_lit_comp("goto_name"),
str8_lit_comp("function_breakpoint"),
};
DF_StringBindingPair df_g_default_binding_table[97] =
DF_StringBindingPair df_g_default_binding_table[104] =
{
{str8_lit_comp("kill_all"), {OS_Key_F5, 0 |OS_EventFlag_Shift }},
{str8_lit_comp("step_into_inst"), {OS_Key_F11, 0 |OS_EventFlag_Alt}},
@@ -644,6 +644,9 @@ DF_StringBindingPair df_g_default_binding_table[97] =
{str8_lit_comp("switch_to_partner_file"), {OS_Key_O, 0 |OS_EventFlag_Alt}},
{str8_lit_comp("load_user"), {OS_Key_O, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}},
{str8_lit_comp("load_profile"), {OS_Key_O, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}},
{str8_lit_comp("edit"), {OS_Key_F2, 0 }},
{str8_lit_comp("accept"), {OS_Key_Return, 0 }},
{str8_lit_comp("cancel"), {OS_Key_Esc, 0 }},
{str8_lit_comp("move_left"), {OS_Key_Left, 0 }},
{str8_lit_comp("move_right"), {OS_Key_Right, 0 }},
{str8_lit_comp("move_up"), {OS_Key_Up, 0 }},
@@ -668,6 +671,8 @@ DF_StringBindingPair df_g_default_binding_table[97] =
{str8_lit_comp("move_down_page_select"), {OS_Key_PageDown, 0 |OS_EventFlag_Shift }},
{str8_lit_comp("move_up_whole_select"), {OS_Key_Home, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }},
{str8_lit_comp("move_down_whole_select"), {OS_Key_End, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }},
{str8_lit_comp("move_up_reorder"), {OS_Key_Up, 0 |OS_EventFlag_Alt}},
{str8_lit_comp("move_down_reorder"), {OS_Key_Down, 0 |OS_EventFlag_Alt}},
{str8_lit_comp("move_home"), {OS_Key_Home, 0 }},
{str8_lit_comp("move_end"), {OS_Key_End, 0 }},
{str8_lit_comp("move_home_select"), {OS_Key_Home, 0 |OS_EventFlag_Shift }},
@@ -678,8 +683,10 @@ DF_StringBindingPair df_g_default_binding_table[97] =
{str8_lit_comp("backspace_single"), {OS_Key_Backspace, 0 }},
{str8_lit_comp("backspace_chunk"), {OS_Key_Backspace, 0 |OS_EventFlag_Ctrl }},
{str8_lit_comp("copy"), {OS_Key_C, 0 |OS_EventFlag_Ctrl }},
{str8_lit_comp("copy"), {OS_Key_Insert, 0 |OS_EventFlag_Ctrl }},
{str8_lit_comp("cut"), {OS_Key_X, 0 |OS_EventFlag_Ctrl }},
{str8_lit_comp("paste"), {OS_Key_V, 0 |OS_EventFlag_Ctrl }},
{str8_lit_comp("paste"), {OS_Key_Insert, 0 |OS_EventFlag_Shift }},
{str8_lit_comp("insert_text"), {OS_Key_Null, 0 }},
{str8_lit_comp("goto_line"), {OS_Key_G, 0 |OS_EventFlag_Ctrl }},
{str8_lit_comp("goto_address"), {OS_Key_G, 0 |OS_EventFlag_Alt}},
+1 -8
View File
@@ -6,13 +6,6 @@
#ifndef DF_GFX_META_H
#define DF_GFX_META_H
typedef enum DF_NameKind
{
DF_NameKind_Null,
DF_NameKind_EntityName,
DF_NameKind_COUNT,
} DF_NameKind;
typedef enum DF_GfxViewKind
{
DF_GfxViewKind_Null,
@@ -303,7 +296,7 @@ extern Vec4F32* df_g_theme_preset_colors_table[9];
extern DF_CmdParamSlot df_g_cmd_param_slot_2_view_spec_src_map[7];
extern String8 df_g_cmd_param_slot_2_view_spec_dst_map[7];
extern String8 df_g_cmd_param_slot_2_view_spec_cmd_map[7];
extern DF_StringBindingPair df_g_default_binding_table[97];
extern DF_StringBindingPair df_g_default_binding_table[104];
extern String8 df_g_binding_version_remap_old_name_table[3];
extern String8 df_g_binding_version_remap_new_name_table[3];
extern DF_ViewSpecInfo df_g_gfx_view_kind_spec_info_table[31];
+3 -3
View File
@@ -1,8 +1,8 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef RDI_MARKUP_H
#define RDI_MARKUP_H
#ifndef RADDBG_MARKUP_H
#define RADDBG_MARKUP_H
////////////////////////////////
//~ Usage Macros
@@ -75,4 +75,4 @@ raddbg_log__impl(char *fmt, ...)
#endif // defined(_WIN32)
#endif // RDI_MARKUP_H
#endif // RADDBG_MARKUP_H
@@ -141,4 +141,14 @@
# error Endianness of this architecture not understood by context cracker
#endif
////////////////////////////////
//~ rjf: Unsupported Errors
#if ARCH_X86
# error You tried to build in x86 (32 bit) mode, but currently, only building in x64 (64 bit) mode is supported.
#endif
#if !ARCH_X64
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
#endif
#endif // BASE_CONTEXT_CRACKING_H
+122 -81
View File
@@ -11,7 +11,9 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
ProfBeginFunction();
Temp scratch = scratch_begin(0, 0);
//////////////////////////////
//- rjf: begin logging
//
if(main_thread_log == 0)
{
main_thread_log = log_alloc();
@@ -24,13 +26,17 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
log_select(main_thread_log);
log_scope_begin();
//////////////////////////////
//- rjf: tick cache layers
//
txt_user_clock_tick();
dasm_user_clock_tick();
geo_user_clock_tick();
tex_user_clock_tick();
//////////////////////////////
//- rjf: pick target hz
//
// TODO(rjf): maximize target, given all windows and their monitors
F32 target_hz = os_default_refresh_rate();
if(frame_time_us_history_idx > 32)
@@ -66,29 +72,41 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
target_hz = best_target_hz;
}
//////////////////////////////
//- rjf: target Hz -> delta time
//
F32 dt = 1.f/target_hz;
//////////////////////////////
//- rjf: last frame before sleep -> disable txti change detection
//
if(df_gfx_state->num_frames_requested == 0)
{
txti_set_external_change_detection_enabled(0);
}
//////////////////////////////
//- rjf: get events from the OS
//
OS_EventList events = {0};
if(os_handle_match(repaint_window_handle, os_handle_zero()))
{
events = os_get_events(scratch.arena, df_gfx_state->num_frames_requested == 0);
}
//////////////////////////////
//- rjf: enable txti change detection
//
txti_set_external_change_detection_enabled(1);
//////////////////////////////
//- rjf: begin measuring actual per-frame work
//
U64 begin_time_us = os_now_microseconds();
//////////////////////////////
//- rjf: bind change
//
if(!df_gfx_state->confirm_active && df_gfx_state->bind_change_active)
{
if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Esc))
@@ -113,6 +131,7 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
event->key != OS_Key_Delete &&
event->key != OS_Key_LeftMouseButton &&
event->key != OS_Key_RightMouseButton &&
event->key != OS_Key_MiddleMouseButton &&
event->key != OS_Key_Ctrl &&
event->key != OS_Key_Alt &&
event->key != OS_Key_Shift)
@@ -136,7 +155,10 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
}
}
//- rjf: take hotkeys
//////////////////////////////
//- rjf: consume events
//
B32 queue_drag_drop = 0;
{
for(OS_Event *event = events.first, *next = 0;
event != 0;
@@ -145,7 +167,63 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
next = event->next;
DF_Window *window = df_window_from_os_handle(event->window);
DF_CmdParams params = window ? df_cmd_params_from_window(window) : df_cmd_params_from_gfx();
if(event->kind == OS_EventKind_Press)
B32 take = 0;
B32 skip = 0;
//- rjf: try drag-drop
if(df_drag_is_active() && event->kind == OS_EventKind_Release && event->key == OS_Key_LeftMouseButton)
{
skip = 1;
queue_drag_drop = 1;
}
//- rjf: try window close
if(!take && event->kind == OS_EventKind_WindowClose && window != 0)
{
take = 1;
DF_CmdParams params = df_cmd_params_from_window(window);
df_push_cmd__root(&params, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseWindow));
}
//- rjf: try menu bar operations
{
if(!take && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
{
take = 1;
df_gfx_request_frame();
window->menu_bar_focused_on_press = window->menu_bar_focused;
window->menu_bar_key_held = 1;
window->menu_bar_focus_press_started = 1;
}
if(!take && event->kind == OS_EventKind_Release && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
{
take = 1;
df_gfx_request_frame();
window->menu_bar_key_held = 0;
}
if(window->menu_bar_focused && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
{
take = 1;
df_gfx_request_frame();
window->menu_bar_focused = 0;
}
else if(window->menu_bar_focus_press_started && !window->menu_bar_focused && event->kind == OS_EventKind_Release && event->flags == 0 && event->key == OS_Key_Alt && event->is_repeat == 0)
{
take = 1;
df_gfx_request_frame();
window->menu_bar_focused = !window->menu_bar_focused_on_press;
window->menu_bar_focus_press_started = 0;
}
else if(event->kind == OS_EventKind_Press && event->key == OS_Key_Esc && window->menu_bar_focused && !ui_any_ctx_menu_is_open())
{
take = 1;
df_gfx_request_frame();
window->menu_bar_focused = 0;
}
}
//- rjf: try hotkey presses
if(!take && event->kind == OS_EventKind_Press)
{
DF_Binding binding = {event->key, event->flags};
DF_CmdSpecList spec_candidates = df_cmd_spec_list_from_binding(scratch.arena, binding);
@@ -159,7 +237,7 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
df_cmd_params_mark_slot(&params, DF_CmdParamSlot_CmdSpec);
}
U32 hit_char = os_codepoint_from_event_flags_and_key(event->flags, event->key);
os_eat_event(&events, event);
take = 1;
df_push_cmd__root(&params, run_spec);
if(event->flags & OS_EventFlag_Alt)
{
@@ -172,7 +250,9 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
}
df_gfx_request_frame();
}
else if(event->kind == OS_EventKind_Text)
//- rjf: try text events
if(!take && event->kind == OS_EventKind_Text)
{
String32 insertion32 = str32(&event->character, 1);
String8 insertion8 = str8_from_32(scratch.arena, insertion32);
@@ -181,87 +261,51 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
df_cmd_params_mark_slot(&params, DF_CmdParamSlot_String);
df_push_cmd__root(&params, spec);
df_gfx_request_frame();
os_eat_event(&events, event);
take = 1;
if(event->flags & OS_EventFlag_Alt)
{
window->menu_bar_focus_press_started = 0;
}
}
}
}
//- rjf: menu bar focus
{
for(OS_Event *event = events.first, *next = 0; event != 0; event = next)
{
next = event->next;
DF_Window *ws = df_window_from_os_handle(event->window);
if(ws == 0)
{
continue;
}
B32 take = 0;
if(event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
//- rjf: do fall-through
if(!take)
{
take = 1;
df_gfx_request_frame();
ws->menu_bar_focused_on_press = ws->menu_bar_focused;
ws->menu_bar_key_held = 1;
ws->menu_bar_focus_press_started = 1;
params.os_event = event;
df_push_cmd__root(&params, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_OSEvent));
}
if(event->kind == OS_EventKind_Release && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
{
take = 1;
df_gfx_request_frame();
ws->menu_bar_key_held = 0;
}
if(ws->menu_bar_focused && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
{
take = 1;
df_gfx_request_frame();
ws->menu_bar_focused = 0;
}
else if(ws->menu_bar_focus_press_started && !ws->menu_bar_focused && event->kind == OS_EventKind_Release && event->flags == 0 && event->key == OS_Key_Alt && event->is_repeat == 0)
{
take = 1;
df_gfx_request_frame();
ws->menu_bar_focused = !ws->menu_bar_focused_on_press;
ws->menu_bar_focus_press_started = 0;
}
else if(event->kind == OS_EventKind_Press && event->key == OS_Key_Esc && ws->menu_bar_focused && !ui_any_ctx_menu_is_open())
{
take = 1;
df_gfx_request_frame();
ws->menu_bar_focused = 0;
}
if(take)
//- rjf: take
if(take && !skip)
{
os_eat_event(&events, event);
}
}
}
//////////////////////////////
//- rjf: gather root-level commands
//
DF_CmdList cmds = df_core_gather_root_cmds(scratch.arena);
//////////////////////////////
//- rjf: begin frame
//
df_core_begin_frame(scratch.arena, &cmds, dt);
df_gfx_begin_frame(scratch.arena, &cmds);
//////////////////////////////
//- rjf: queue drop for drag/drop
if(df_drag_is_active())
//
if(queue_drag_drop)
{
for(OS_Event *event = events.first; event != 0; event = event->next)
{
if(event->kind == OS_EventKind_Release && event->key == OS_Key_LeftMouseButton)
{
df_queue_drag_drop();
break;
}
}
df_queue_drag_drop();
}
//////////////////////////////
//- rjf: auto-focus moused-over windows while dragging
//
if(df_drag_is_active())
{
B32 over_focused_window = 0;
@@ -292,20 +336,26 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
}
}
//////////////////////////////
//- rjf: update & render
//
{
d_begin_frame();
for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next)
{
df_window_update_and_render(scratch.arena, &events, w, &cmds);
df_window_update_and_render(scratch.arena, w, &cmds);
}
}
//////////////////////////////
//- rjf: end frontend frame, send signals, etc.
//
df_gfx_end_frame();
df_core_end_frame();
//////////////////////////////
//- rjf: submit rendering to all windows
//
{
r_begin_frame();
for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next)
@@ -317,35 +367,26 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
r_end_frame();
}
//- rjf: take window closing events
for(OS_Event *e = events.first, *next = 0; e; e = next)
{
next = e->next;
if(e->kind == OS_EventKind_WindowClose)
{
for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next)
{
if(os_handle_match(w->os, e->window))
{
DF_CmdParams params = df_cmd_params_from_window(w);
df_push_cmd__root(&params, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseWindow));
break;
}
}
os_eat_event(&events, e);
}
}
//////////////////////////////
//- rjf: determine frame time, record into history
//
U64 end_time_us = os_now_microseconds();
U64 frame_time_us = end_time_us-begin_time_us;
frame_time_us_history[frame_time_us_history_idx%ArrayCount(frame_time_us_history)] = frame_time_us;
frame_time_us_history_idx += 1;
//////////////////////////////
//- rjf: end logging
//
{
String8 log = log_scope_end(scratch.arena);
os_append_data_to_file_path(main_thread_log_path, log);
LogScopeResult log = log_scope_end(scratch.arena);
os_append_data_to_file_path(main_thread_log_path, log.strings[LogMsgKind_Info]);
if(log.strings[LogMsgKind_UserError].size != 0)
{
DF_CmdParams p = df_cmd_params_from_gfx();
p.string = log.strings[LogMsgKind_UserError];
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error));
}
}
scratch_end(scratch);
+47 -46
View File
@@ -4,19 +4,13 @@
////////////////////////////////
//~ rjf: Frontend/UI Pass Tasks
//
// [ ] editing multiple bindings for commands
// [ ] n-row table selection, in watch window & other UIs, multi-selection
// ctrl+C
// [ ] UI_NavActions, OS_Event -> UI_Event (single event stream)
//
// [ ] better discoverability for view rules - have better help hover tooltip,
// info on arguments, and better autocomplete lister
//
// [ ] source view -> floating margin/line-nums
// [ ] theme colors -> more explicit about e.g. opaque backgrounds vs. floating
// & scrollbars etc.
// [ ] target/breakpoint/watch-pin reordering
// [ ] watch window reordering
// [ ] standard way to filter
// [ ] visualize remapped files (via path map)
// [ ] theme lister -> fonts & font sizes
// [ ] font lister
@@ -32,9 +26,6 @@
// that you use to tag them. Just some way that would make it easier to
// focus on your own threads.
//
// [ ] autocomplete lister should respect position in edited expression,
// tabbing through should autocomplete but not exit, etc.
//
// [ ] it would be nice to have "show in explorer" for right click on source
// file tab (opens explorer & selects the file)
//
@@ -42,8 +33,6 @@
// different color? can I turn it off? And why sometimes digits in number
// start with brighter color, but sometimes with darker - shouldn't it
// always have the same color ordering?
//
// [ ] pipe failure-to-launch errors back to frontend
////////////////////////////////
//~ rjf: Hot, High Priority Tasks (Complete Unusability, Crashes, Fire-Worthy)
@@ -73,6 +62,17 @@
////////////////////////////////
//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup)
//
// [ ] Jeff Notes
// [ ] highlighted text & ctrl+f -> auto-fill search query
// [ ] double-click any part of frame in callstack view -> snap to function
// [ ] sort locals by appearance in source code (or maybe just debug info)
// [ ] sum view rule
// [ ] plot view rule
// [ ] histogram view rule
// [ ] max view rule
// [ ] min view rule
// [ ] double click on procedure in procedures tab to jump to source
//
// [ ] investigate /DEBUG:FASTLINK - can we somehow alert that we do not
// support it?
//
@@ -129,24 +129,11 @@
// have alternating bright/dim letters to show sections of a number. Is
// this in the theme colors somewhere?
//
// [ ] ** I couldn't figure out how to really view threads in the debugger.
// The only place I found a thread list was in "The Scheduler", but it
// only lists threads by ID, which is hard to use. I can hover over them
// to get the stack, which helps, but it would be much nicer if the top
// function was displayed in the window by default next to the thread.
// [ ] ** It would be nice if thread listings displayed the name of the
// thread, instead of just the ID.
//
// [ ] ** Scrollbars are barely visible for me, for some reason. I could not
// find anything in the theme that would fill them with a solid, bright
// color. Instead they are just a thin outline and the same color as the
// scroll bar background.
//
// [ ] Dragging a window tab (like Locals or Registers or whatnot) and
// canceling with ESC should revert the window tab to where it was.
// Currently, it leaves the window tab reordered if you dragged over its
// window and shuffled its position.
//
// [ ] Many of the UI elements, like the menus, would like better if they had
// a little bit of margin. Having the text right next to the edges, and
// with no line spacing, makes it harder to read things quickly.
@@ -205,11 +192,6 @@
// be fine with them, but they would have to be much more light (like
// alpha 0.1 or something)
//
// [ ] It's confusing that ENTER is the way you expand and collapse things in
// the watch window, but then also how you edit them if they are not
// expandable? It seems like this should be consistent (one way to edit,
// one way to expand/collapse, that are distinct)
//
// [ ] The hex format for color values in the config file was a real
// mindbender. It's prefixed with "0x", so I was assuming it was either
// Windows Big Endian (0xAARRGGBB) or Mac Little Endian (0xAABBGGRR). To
@@ -234,16 +216,10 @@
// [ ] can it ignore stepping into _RTC_CheckStackVars generated functions?
// [ ] mouse back button should make view to go back after I double clicked
// on function to open it
// [ ] pressing random keyboard keys in source code advances text cursor like
// you were inputting text, very strange.
// [ ] Alt+8 to switch to disassembly would be nice (regardless on which
// panel was previous, don't want to use ctrl+, multiple times)
// Alt+8 for disasm and Alt+6 for memory view are shortcuts I often use
// in VS
// [ ] in watch window when I enter some new expression and then click mouse
// away from cell, then it should behave the same as if I pressed enter.
// Currently it does the same as if I have pressed esc and I have lost my
// expression
// [ ] default font size is too small for me - not only source code, but
// menus/tab/watch names (which don't resize). Maybe you could query
// Windows for initial font size?
@@ -319,7 +295,6 @@
// variables?
//
// [ ] @feature disasm view improvement features
// [ ] interleaved src/dasm view
// [ ] visualize jump destinations in disasm
//
// [ ] @feature eval ui improvement features
@@ -355,14 +330,6 @@
// [ ] fancy string runs can include "weakness" information for text truncation
// ... can prioritize certain parts of strings to be truncated before
// others. would be good for e.g. the middle of a path
// [ ] ui code maintenance, simplification, design, & robustness pass
// [ ] page-up & page-down correct handling in keyboard nav
// [ ] collapse context menus & command lister into same codepaths. filter by
// context. parameterize by context.
// [ ] collapse text cells & command lister & etc. into same codepath (?)
// [ ] nested context menus
// [ ] unified top-level cursor/typing/lister helper
// [ ] font selection lister
// [ ] font cache eviction (both for font tags, closing fp handles, and
// rasterizations)
// [ ] frontend speedup opportunities
@@ -377,7 +344,41 @@
////////////////////////////////
//~ rjf: Recently Completed Task Log
//
//
// [x] UI_NavActions, OS_Event -> UI_Event (single event stream)
// [x] better discoverability for view rules - have better help hover tooltip,
// info on arguments, and better autocomplete lister
// [x] source view -> floating margin/line-nums
// [x] watch window reordering
// [x] standard way to filter
// [x] autocomplete lister should respect position in edited expression,
// tabbing through should autocomplete but not exit, etc.
// [x] pipe failure-to-launch errors back to frontend
// [x] bit more padding on the tabs
// [x] unified top-level cursor/typing/lister helper
// [x] collapse text cells & command lister & etc. into same codepath (?)
// [x] page-up & page-down correct handling in keyboard nav
// [x] interleaved src/dasm view
// [x] in watch window when I enter some new expression and then click mouse
// away from cell, then it should behave the same as if I pressed enter.
// Currently it does the same as if I have pressed esc and I have lost my
// expression
// [x] pressing random keyboard keys in source code advances text cursor like
// you were inputting text, very strange.
// [x] It's confusing that ENTER is the way you expand and collapse things in
// the watch window, but then also how you edit them if they are not
// expandable? It seems like this should be consistent (one way to edit,
// one way to expand/collapse, that are distinct)
// [x] Dragging a window tab (like Locals or Registers or whatnot) and
// canceling with ESC should revert the window tab to where it was.
// Currently, it leaves the window tab reordered if you dragged over its
// window and shuffled its position.
// [x] ** I couldn't figure out how to really view threads in the debugger.
// The only place I found a thread list was in "The Scheduler", but it
// only lists threads by ID, which is hard to use. I can hover over them
// to get the stack, which helps, but it would be much nicer if the top
// function was displayed in the window by default next to the thread.
// [x] ** It would be nice if thread listings displayed the name of the
// thread, instead of just the ID.
#ifndef RADDBG_H
#define RADDBG_H
+1 -1
View File
@@ -2057,7 +2057,7 @@ internal TS_TASK_FUNCTION_DEF(p2r_symbol_stream_convert_task__entry_point)
// rjf: unpack proc's container type
RDIM_Type *container_type = 0;
U64 container_name_opl = p2r_end_of_cplusplus_container_name(name);
if(container_name_opl > 2)
if(container_name_opl > 2 && in->tpi_hash != 0 && in->tpi_leaf != 0)
{
String8 container_name = str8(name.str, container_name_opl - 2);
CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, container_name, 0);
+33 -23
View File
@@ -193,32 +193,32 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size,
if(is_focus_active)
{
Temp scratch = scratch_begin(0, 0);
UI_NavActionList *nav_actions = ui_nav_actions();
for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next)
UI_EventList *events = ui_events();
for(UI_EventNode *n = events->first, *next = 0; n != 0; n = next)
{
String8 edit_string = str8(edit_buffer, edit_string_size_out[0]);
next = n->next;
// rjf: do not consume anything that doesn't fit a single-line's operations
if(n->v.delta.y != 0)
if((n->v.kind != UI_EventKind_Edit && n->v.kind != UI_EventKind_Navigate && n->v.kind != UI_EventKind_Text) || n->v.delta_2s32.y != 0)
{
continue;
}
// rjf: map this action to an op
UI_NavTxtOp op = ui_nav_single_line_txt_op_from_action(scratch.arena, n->v, edit_string, *cursor, *mark);
UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, &n->v, edit_string, *cursor, *mark);
// rjf: perform replace range
if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0)
{
String8 new_string = ui_nav_push_string_replace_range(scratch.arena, edit_string, r1s64(op.range.min.column, op.range.max.column), op.replace);
String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(op.range.min.column, op.range.max.column), op.replace);
new_string.size = Min(edit_buffer_size, new_string.size);
MemoryCopy(edit_buffer, new_string.str, new_string.size);
edit_string_size_out[0] = new_string.size;
}
// rjf: perform copy
if(op.flags & UI_NavTxtOpFlag_Copy)
if(op.flags & UI_TxtOpFlag_Copy)
{
os_set_clipboard_text(op.copy);
}
@@ -229,7 +229,7 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size,
// rjf: consume event
{
ui_nav_eat_action_node(nav_actions, n);
ui_eat_event(events, n);
changes_made = 1;
}
}
@@ -1335,7 +1335,7 @@ thread_static Vec2F32 ui_scroll_list_dim_px = {0};
thread_static Rng1S64 ui_scroll_list_scroll_idx_rng = {0};
internal void
ui_scroll_list_begin(UI_ScrollListParams *params, UI_ScrollPt *scroll_pt, Vec2S64 *cursor_out, Rng1S64 *visible_row_range_out, UI_ScrollListSignal *signal_out)
ui_scroll_list_begin(UI_ScrollListParams *params, UI_ScrollPt *scroll_pt, Vec2S64 *cursor_out, Vec2S64 *mark_out, Rng1S64 *visible_row_range_out, UI_ScrollListSignal *signal_out)
{
//- rjf: unpack arguments
Rng1S64 scroll_row_idx_range = r1s64(params->item_range.min, ClampBot(params->item_range.min, params->item_range.max-1));
@@ -1345,27 +1345,28 @@ ui_scroll_list_begin(UI_ScrollListParams *params, UI_ScrollPt *scroll_pt, Vec2S6
B32 moved = 0;
if(params->flags & UI_ScrollListFlag_Nav && cursor_out != 0 && ui_is_focus_active())
{
UI_NavActionList *nav_actions = ui_nav_actions();
UI_EventList *events = ui_events();
Vec2S64 cursor = *cursor_out;
for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next)
Vec2S64 mark = mark_out ? *mark_out : cursor;
for(UI_EventNode *n = events->first, *next = 0; n != 0; n = next)
{
next = n->next;
UI_NavAction *action = &n->v;
if((action->delta.x == 0 && action->delta.y == 0) ||
action->flags & (UI_NavActionFlag_KeepMark|UI_NavActionFlag_Delete))
UI_Event *evt = &n->v;
if((evt->delta_2s32.x == 0 && evt->delta_2s32.y == 0) ||
evt->flags & UI_EventFlag_Delete)
{
continue;
}
ui_nav_eat_action_node(nav_actions, n);
ui_eat_event(events, n);
moved = 1;
switch(action->delta_unit)
switch(evt->delta_unit)
{
default:{moved = 0;}break;
case UI_NavDeltaUnit_Element:
case UI_EventDeltaUnit_Char:
{
for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis+1))
{
cursor.v[axis] += action->delta.v[axis];
cursor.v[axis] += evt->delta_2s32.v[axis];
if(cursor.v[axis] < params->cursor_range.min.v[axis])
{
cursor.v[axis] = params->cursor_range.max.v[axis];
@@ -1377,25 +1378,34 @@ ui_scroll_list_begin(UI_ScrollListParams *params, UI_ScrollPt *scroll_pt, Vec2S6
cursor.v[axis] = clamp_1s64(r1s64(params->cursor_range.min.v[axis], params->cursor_range.max.v[axis]), cursor.v[axis]);
}
}break;
case UI_NavDeltaUnit_Chunk:
case UI_NavDeltaUnit_Whole:
case UI_EventDeltaUnit_Word:
case UI_EventDeltaUnit_Line:
case UI_EventDeltaUnit_Page:
{
cursor.x = (action->delta.x>0 ? params->cursor_range.max.x : action->delta.x<0 ? params->cursor_range.min.x + !!params->cursor_min_is_empty_selection[Axis2_X] : cursor.x);
cursor.y += ((action->delta.y>0 ? +(num_possible_visible_rows-3) : action->delta.y<0 ? -(num_possible_visible_rows-3) : 0));
cursor.x = (evt->delta_2s32.x>0 ? params->cursor_range.max.x : evt->delta_2s32.x<0 ? params->cursor_range.min.x + !!params->cursor_min_is_empty_selection[Axis2_X] : cursor.x);
cursor.y += ((evt->delta_2s32.y>0 ? +(num_possible_visible_rows-3) : evt->delta_2s32.y<0 ? -(num_possible_visible_rows-3) : 0));
cursor.y = clamp_1s64(r1s64(params->cursor_range.min.y + !!params->cursor_min_is_empty_selection[Axis2_Y], params->cursor_range.max.y), cursor.y);
}break;
case UI_NavDeltaUnit_EndPoint:
case UI_EventDeltaUnit_Whole:
{
for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis+1))
{
cursor.v[axis] = (action->delta.v[axis]>0 ? params->cursor_range.max.v[axis] : action->delta.v[axis]<0 ? params->cursor_range.min.v[axis] + !!params->cursor_min_is_empty_selection[axis] : cursor.v[axis]);
cursor.v[axis] = (evt->delta_2s32.v[axis]>0 ? params->cursor_range.max.v[axis] : evt->delta_2s32.v[axis]<0 ? params->cursor_range.min.v[axis] + !!params->cursor_min_is_empty_selection[axis] : cursor.v[axis]);
}
}break;
}
if(!(evt->flags & UI_EventFlag_KeepMark))
{
mark = cursor;
}
}
if(moved)
{
*cursor_out = cursor;
if(mark_out)
{
*mark_out = mark;
}
}
}
+2 -2
View File
@@ -157,7 +157,7 @@ internal U64 ui_scroll_list_row_from_item(UI_ScrollListRowBlockArray *blocks, U6
internal U64 ui_scroll_list_item_from_row(UI_ScrollListRowBlockArray *blocks, U64 row);
internal UI_ScrollPt ui_scroll_bar(Axis2 axis, UI_Size off_axis_size, UI_ScrollPt pt, Rng1S64 idx_range, S64 view_num_indices);
internal void ui_scroll_list_begin(UI_ScrollListParams *params, UI_ScrollPt *scroll_pt_out, Vec2S64 *cursor_out, Rng1S64 *visible_row_range_out, UI_ScrollListSignal *signal_out);
internal void ui_scroll_list_begin(UI_ScrollListParams *params, UI_ScrollPt *scroll_pt_out, Vec2S64 *cursor_out, Vec2S64 *mark_out, Rng1S64 *visible_row_range_out, UI_ScrollListSignal *signal_out);
internal void ui_scroll_list_end(void);
////////////////////////////////
@@ -180,6 +180,6 @@ internal void ui_scroll_list_end(void);
#define UI_TableCell DeferLoop(ui_table_cell_begin(), ui_table_cell_end())
#define UI_TableCellSized(size) DeferLoop(ui_table_cell_sized_begin(size), ui_table_cell_end())
#define UI_ScrollList(params, scroll_pt_out, cursor_out, visible_row_range_out, signal_out) DeferLoop(ui_scroll_list_begin((params), (scroll_pt_out), (cursor_out), (visible_row_range_out), (signal_out)), ui_scroll_list_end())
#define UI_ScrollList(params, scroll_pt_out, cursor_out, mark_out, visible_row_range_out, signal_out) DeferLoop(ui_scroll_list_begin((params), (scroll_pt_out), (cursor_out), (mark_out), (visible_row_range_out), (signal_out)), ui_scroll_list_end())
#endif // UI_BASIC_WIDGETS_H
+235 -191
View File
@@ -95,34 +95,37 @@ ui_key_match(UI_Key a, UI_Key b)
}
////////////////////////////////
//~ rjf: Navigation Action List Building & Consumption Functions
//~ rjf: Event Type Functions
internal void
ui_nav_action_list_push(Arena *arena, UI_NavActionList *list, UI_NavAction action)
internal UI_EventNode *
ui_event_list_push(Arena *arena, UI_EventList *list, UI_Event *v)
{
UI_NavActionNode *node = push_array(arena, UI_NavActionNode, 1);
DLLPushBack(list->first, list->last, node);
MemoryCopyStruct(&node->v, &action);
UI_EventNode *n = push_array(arena, UI_EventNode, 1);
MemoryCopyStruct(&n->v, v);
n->v.string = push_str8_copy(arena, n->v.string);
DLLPushBack(list->first, list->last, n);
list->count += 1;
return n;
}
internal void
ui_nav_eat_action_node(UI_NavActionList *list, UI_NavActionNode *node)
ui_eat_event(UI_EventList *list, UI_EventNode *node)
{
DLLRemove(list->first, list->last, node);
list->count -= 1;
}
////////////////////////////////
//~ rjf: High Level Navigation Action => Text Operations
//~ rjf: Text Operation Functions
internal B32
ui_nav_char_is_code_symbol(U8 c)
ui_char_is_scan_boundary(U8 c)
{
return (char_is_alpha(c) || char_is_digit(c, 10) || c == '_');
}
internal S64
ui_nav_scanned_column_from_column(String8 string, S64 start_column, Side side)
ui_scanned_column_from_column(String8 string, S64 start_column, Side side)
{
S64 new_column = start_column;
S64 delta = (!!side)*2 - 1;
@@ -133,86 +136,90 @@ ui_nav_scanned_column_from_column(String8 string, S64 start_column, Side side)
{
U8 byte = (col <= string.size) ? string.str[col-1] : 0;
B32 is_non_space = !char_is_space(byte);
B32 is_name = ui_nav_char_is_code_symbol(byte);
if (((side == Side_Min) && (col == 1)) ||
((side == Side_Max) && (col == string.size+1)) ||
(found_non_space && !is_non_space) ||
(found_text && !is_name))
B32 is_name = ui_char_is_scan_boundary(byte);
if(((side == Side_Min) && (col == 1)) ||
((side == Side_Max) && (col == string.size+1)) ||
(found_non_space && !is_non_space) ||
(found_text && !is_name))
{
new_column = col + (!side && col != 1);
break;
} else if (!found_text && is_name) {
}
else if (!found_text && is_name)
{
found_text = 1;
} else if (!found_non_space && is_non_space ) {
}
else if (!found_non_space && is_non_space)
{
found_non_space = 1;
}
}
return new_column;
}
internal UI_NavTxtOp
ui_nav_single_line_txt_op_from_action(Arena *arena, UI_NavAction action, String8 line, TxtPt cursor, TxtPt mark)
internal UI_TxtOp
ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string, TxtPt cursor, TxtPt mark)
{
TxtPt next_cursor = cursor;
TxtPt next_mark = mark;
TxtRng range = {0};
String8 replace = {0};
String8 copy = {0};
UI_NavTxtOpFlags flags = 0;
Vec2S32 delta = action.delta;
UI_TxtOpFlags flags = 0;
Vec2S32 delta = event->delta_2s32;
Vec2S32 original_delta = delta;
//- rjf: resolve high-level delta into byte delta, based on unit
switch(action.delta_unit)
switch(event->delta_unit)
{
default:{}break;
case UI_NavDeltaUnit_Element:
case UI_EventDeltaUnit_Char:
{
// TODO(rjf): this should account for multi-byte characters in UTF-8... for now, just assume ASCII and
// no-op
}break;
case UI_NavDeltaUnit_Chunk:
case UI_EventDeltaUnit_Word:
{
delta.x = (S32)ui_nav_scanned_column_from_column(line, cursor.column, delta.x > 0 ? Side_Max : Side_Min) - cursor.column;
delta.x = (S32)ui_scanned_column_from_column(string, cursor.column, delta.x > 0 ? Side_Max : Side_Min) - cursor.column;
}break;
case UI_NavDeltaUnit_Whole:
case UI_NavDeltaUnit_EndPoint:
case UI_EventDeltaUnit_Line:
case UI_EventDeltaUnit_Whole:
case UI_EventDeltaUnit_Page:
{
S64 first_nonwhitespace_column = 1;
for(U64 idx = 0; idx < line.size; idx += 1)
for(U64 idx = 0; idx < string.size; idx += 1)
{
if(!char_is_space(line.str[idx]))
if(!char_is_space(string.str[idx]))
{
first_nonwhitespace_column = (S64)idx + 1;
break;
}
}
S64 home_dest_column = (cursor.column == first_nonwhitespace_column) ? 1 : first_nonwhitespace_column;
delta.x = (delta.x > 0) ? ((S64)line.size+1 - cursor.column) : (home_dest_column - cursor.column);
delta.x = (delta.x > 0) ? ((S64)string.size+1 - cursor.column) : (home_dest_column - cursor.column);
}break;
}
//- rjf: zero delta
if(!txt_pt_match(cursor, mark) && action.flags & UI_NavActionFlag_ZeroDeltaOnSelect)
if(!txt_pt_match(cursor, mark) && event->flags & UI_EventFlag_ZeroDeltaOnSelect)
{
delta = v2s32(0, 0);
}
//- rjf: form next cursor
if(txt_pt_match(cursor, mark) || !(action.flags & UI_NavActionFlag_ZeroDeltaOnSelect))
if(txt_pt_match(cursor, mark) || !(event->flags & UI_EventFlag_ZeroDeltaOnSelect))
{
next_cursor.column += delta.x;
}
//- rjf: cap at line
if(action.flags & UI_NavActionFlag_CapAtLine)
if(event->flags & UI_EventFlag_CapAtLine)
{
next_cursor.column = Clamp(1, next_cursor.column, (S64)(line.size+1));
next_cursor.column = Clamp(1, next_cursor.column, (S64)(string.size+1));
}
//- rjf: in some cases, we want to pick a selection side based on the delta
if(!txt_pt_match(cursor, mark) && action.flags & UI_NavActionFlag_PickSelectSide)
if(!txt_pt_match(cursor, mark) && event->flags & UI_EventFlag_PickSelectSide)
{
if(original_delta.x < 0 || original_delta.y < 0)
{
@@ -225,21 +232,21 @@ ui_nav_single_line_txt_op_from_action(Arena *arena, UI_NavAction action, String8
}
//- rjf: copying
if(action.flags & UI_NavActionFlag_Copy)
if(event->flags & UI_EventFlag_Copy)
{
if(cursor.line == mark.line)
{
copy = str8_substr(line, r1u64(cursor.column-1, mark.column-1));
flags |= UI_NavTxtOpFlag_Copy;
copy = str8_substr(string, r1u64(cursor.column-1, mark.column-1));
flags |= UI_TxtOpFlag_Copy;
}
else
{
flags |= UI_NavTxtOpFlag_Invalid;
flags |= UI_TxtOpFlag_Invalid;
}
}
//- rjf: pasting
if(action.flags & UI_NavActionFlag_Paste)
if(event->flags & UI_EventFlag_Paste)
{
range = txt_rng(cursor, mark);
replace = os_get_clipboard_text(arena);
@@ -247,7 +254,7 @@ ui_nav_single_line_txt_op_from_action(Arena *arena, UI_NavAction action, String8
}
//- rjf: deletion
if(action.flags & UI_NavActionFlag_Delete)
if(event->flags & UI_EventFlag_Delete)
{
TxtPt new_pos = txt_pt_min(next_cursor, next_mark);
range = txt_rng(next_cursor, next_mark);
@@ -256,37 +263,39 @@ ui_nav_single_line_txt_op_from_action(Arena *arena, UI_NavAction action, String8
}
//- rjf: stick mark to cursor, when we don't want to keep it in the same spot
if(!(action.flags & UI_NavActionFlag_KeepMark))
if(!(event->flags & UI_EventFlag_KeepMark))
{
next_mark = next_cursor;
}
//- rjf: insertion
if(action.insertion.size != 0)
if(event->string.size != 0)
{
range = txt_rng(cursor, mark);
replace = push_str8_copy(arena, action.insertion);
next_cursor = next_mark = txt_pt(range.min.line, range.min.column + action.insertion.size);
replace = push_str8_copy(arena, event->string);
next_cursor = next_mark = txt_pt(range.min.line, range.min.column + event->string.size);
}
//- rjf: replace & commit -> replace entire range
if(action.flags & UI_NavActionFlag_ReplaceAndCommit)
#if 0
if(event->flags & UI_EventFlag_ReplaceAndCommit)
{
range = txt_rng(txt_pt(cursor.line, 1), txt_pt(cursor.line, line.size+1));
}
#endif
//- rjf: determine if this event should be taken, based on bounds of cursor
{
if(next_cursor.column > line.size+1 || 1 > next_cursor.column || action.delta.y != 0)
if(next_cursor.column > string.size+1 || 1 > next_cursor.column || event->delta_2s32.y != 0)
{
flags |= UI_NavTxtOpFlag_Invalid;
flags |= UI_TxtOpFlag_Invalid;
}
next_cursor.column = Clamp(1, next_cursor.column, line.size+replace.size+1);
next_mark.column = Clamp(1, next_mark.column, line.size+replace.size+1);
next_cursor.column = Clamp(1, next_cursor.column, string.size+replace.size+1);
next_mark.column = Clamp(1, next_mark.column, string.size+replace.size+1);
}
//- rjf: build+fill
UI_NavTxtOp op = {0};
UI_TxtOp op = {0};
{
op.flags = flags;
op.replace = replace;
@@ -298,11 +307,8 @@ ui_nav_single_line_txt_op_from_action(Arena *arena, UI_NavAction action, String8
return op;
}
////////////////////////////////
//~ rjf: Single-Line String Modification
internal String8
ui_nav_push_string_replace_range(Arena *arena, String8 string, Rng1S64 col_range, String8 replace)
ui_push_string_replace_range(Arena *arena, String8 string, Rng1S64 col_range, String8 replace)
{
//- rjf: convert to offset range
Rng1U64 range =
@@ -336,7 +342,8 @@ ui_nav_push_string_replace_range(Arena *arena, String8 string, Rng1S64 col_range
}
}
return str8(push_base, new_size);
String8 result = str8(push_base, new_size);
return result;
}
////////////////////////////////
@@ -489,18 +496,12 @@ ui_window(void)
return ui_state->window;
}
internal OS_EventList *
internal UI_EventList *
ui_events(void)
{
return ui_state->events;
}
internal UI_NavActionList *
ui_nav_actions(void)
{
return ui_state->nav_actions;
}
internal Vec2F32
ui_mouse(void)
{
@@ -525,6 +526,79 @@ ui_dt(void)
return ui_state->animation_dt;
}
//- rjf: event consumption helpers
internal B32
ui_key_press(OS_EventFlags mods, OS_Key key)
{
UI_EventList *list = ui_events();
B32 result = 0;
for(UI_EventNode *n = list->first; n != 0; n = n->next)
{
if(n->v.kind == UI_EventKind_Press && n->v.key == key && n->v.modifiers == mods)
{
result = 1;
ui_eat_event(list, n);
break;
}
}
return result;
}
internal B32
ui_key_release(OS_EventFlags mods, OS_Key key)
{
UI_EventList *list = ui_events();
B32 result = 0;
for(UI_EventNode *n = list->first; n != 0; n = n->next)
{
if(n->v.kind == UI_EventKind_Release && n->v.key == key && n->v.modifiers == mods)
{
result = 1;
ui_eat_event(list, n);
break;
}
}
return result;
}
internal B32
ui_text(U32 character)
{
UI_EventList *list = ui_events();
B32 result = 0;
Temp scratch = scratch_begin(0, 0);
String8 character_text = str8_from_32(scratch.arena, str32(&character, 1));
for(UI_EventNode *n = list->first; n != 0; n = n->next)
{
if(n->v.kind == UI_EventKind_Text && str8_match(character_text, n->v.string, 0))
{
result = 1;
ui_eat_event(list, n);
break;
}
}
scratch_end(scratch);
return result;
}
internal B32
ui_slot_press(UI_EventActionSlot slot)
{
UI_EventList *list = ui_events();
B32 result = 0;
for(UI_EventNode *n = list->first; n != 0; n = n->next)
{
if(n->v.kind == UI_EventKind_Press && n->v.slot == slot)
{
result = 1;
ui_eat_event(list, n);
break;
}
}
return result;
}
//- rjf: drag data
internal Vec2F32
@@ -646,7 +720,7 @@ ui_box_from_key(UI_Key key)
//~ rjf: Top-Level Building API
internal void
ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_actions, UI_IconInfo *icon_info, F32 real_dt, F32 animation_dt)
ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, F32 real_dt, F32 animation_dt)
{
//- rjf: reset per-build ui state
{
@@ -662,9 +736,9 @@ ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_act
}
//- rjf: detect mouse-moves
for(OS_Event *e = events->first; e != 0; e = e->next)
for(UI_EventNode *n = events->first; n != 0; n = n->next)
{
if(e->kind == OS_EventKind_MouseMove && os_handle_match(e->window, window))
if(n->v.kind == UI_EventKind_MouseMove)
{
ui_state->last_time_mousemoved_us = os_now_microseconds();
}
@@ -674,7 +748,6 @@ ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_act
{
ui_state->events = events;
ui_state->window = window;
ui_state->nav_actions = nav_actions;
ui_state->mouse = (os_window_is_focused(window) || ui_state->last_time_mousemoved_us+500000 >= os_now_microseconds()) ? os_mouse_from_window(window) : v2f32(-100, -100);
ui_state->animation_dt = animation_dt;
MemoryZeroStruct(&ui_state->icon_info);
@@ -708,43 +781,41 @@ ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_act
B32 nav_next = 0;
B32 nav_prev = 0;
Axis2 axis_lock = Axis2_Invalid;
if(os_key_press(events, window, 0, OS_Key_Tab))
if(ui_key_press(0, OS_Key_Tab))
{
nav_next = 1;
}
if(os_key_press(events, window, OS_EventFlag_Shift, OS_Key_Tab))
if(ui_key_press(OS_EventFlag_Shift, OS_Key_Tab))
{
nav_prev = 1;
}
for(UI_NavActionNode *node = nav_actions->first, *next = 0;
node != 0;
node = next)
for(UI_EventNode *node = events->first, *next = 0; node != 0; node = next)
{
next = node->next;
B32 taken = 0;
if(node->v.delta.x == 0 && node->v.delta.y == 0)
if(node->v.delta_2s32.x == 0 && node->v.delta_2s32.y == 0)
{
continue;
}
if(((node->v.delta.x > 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavX) || node->v.delta.x == 0) &&
((node->v.delta.y > 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavY) || node->v.delta.y == 0))
if(((node->v.delta_2s32.x > 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavX) || node->v.delta_2s32.x == 0) &&
((node->v.delta_2s32.y > 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavY) || node->v.delta_2s32.y == 0))
{
taken = 1;
nav_next = 1;
}
if(((node->v.delta.x < 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavX) || node->v.delta.x == 0) &&
((node->v.delta.y < 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavY) || node->v.delta.y == 0))
if(((node->v.delta_2s32.x < 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavX) || node->v.delta_2s32.x == 0) &&
((node->v.delta_2s32.y < 0 && nav_root->flags & UI_BoxFlag_DefaultFocusNavY) || node->v.delta_2s32.y == 0))
{
taken = 1;
nav_prev = 1;
}
if(node->v.flags & UI_NavActionFlag_ExplicitDirectional)
if(node->v.flags & UI_EventFlag_ExplicitDirectional)
{
axis_lock = node->v.delta.x != 0 ? Axis2_X : Axis2_Y;
axis_lock = node->v.delta_2s32.x != 0 ? Axis2_X : Axis2_Y;
}
if(taken)
{
ui_nav_eat_action_node(nav_actions, node);
ui_eat_event(events, node);
}
}
@@ -872,7 +943,7 @@ ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_act
//- rjf: some child has the active focus -> accept escape keys to pop from the active key stack
if(!ui_key_match(ui_key_zero(), nav_root->default_nav_focus_active_key))
{
for(;os_key_press(events, window, 0, OS_Key_Esc);)
for(;ui_slot_press(UI_EventActionSlot_Cancel);)
{
UI_Box *prev_focus_root = nav_root;
for(UI_Box *focus_root = ui_box_from_key(nav_root->default_nav_focus_active_key);
@@ -900,13 +971,10 @@ ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_act
UI_Box *active_box = ui_box_from_key(nav_root->default_nav_focus_active_key);
if(!ui_box_is_nil(active_box))
{
for(OS_Event *event = events->first; event != 0; event = event->next)
for(UI_EventNode *n = events->first; n != 0; n = n->next)
{
if(!os_handle_match(event->window, window))
{
continue;
}
if(event->kind == OS_EventKind_Press &&
UI_Event *event = &n->v;
if(event->kind == UI_EventKind_Press &&
event->key == OS_Key_LeftMouseButton &&
!contains_2f32(active_box->rect, ui_mouse()))
{
@@ -1015,20 +1083,6 @@ ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_act
ui_state->active_box_key[k] = ui_key_zero();
}
}
//- rjf: reset active keys if there is clicking activity on other windows
for(OS_Event *event = events->first; event != 0; event = event->next)
{
if((event->kind == OS_EventKind_Press || event->kind == OS_EventKind_Release) &&
!os_handle_match(event->window, window))
{
for(EachEnumVal(UI_MouseButtonKind, k))
{
ui_state->active_box_key[k] = ui_key_zero();
}
break;
}
}
}
internal void
@@ -1037,7 +1091,7 @@ ui_end_build(void)
ProfBeginFunction();
//- rjf: escape -> close context menu
if(ui_state->ctx_menu_open != 0 && os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc))
if(ui_state->ctx_menu_open != 0 && ui_slot_press(UI_EventActionSlot_Cancel))
{
ui_ctx_menu_close();
}
@@ -1287,12 +1341,16 @@ ui_end_build(void)
}
//- rjf: close ctx menu if unconsumed clicks
for(OS_Event *event = ui_events()->first; event != 0; event = event->next)
{
if(event->kind == OS_EventKind_Press && os_handle_match(event->window, ui_window()) &&
(event->key == OS_Key_LeftMouseButton || event->key == OS_Key_RightMouseButton))
UI_EventList *events = ui_events();
for(UI_EventNode *n = events->first; n != 0; n = n->next)
{
ui_ctx_menu_close();
UI_Event *event = &n->v;
if(event->kind == UI_EventKind_Press &&
(event->key == OS_Key_LeftMouseButton || event->key == OS_Key_RightMouseButton))
{
ui_ctx_menu_close();
}
}
}
@@ -1314,10 +1372,11 @@ ui_end_build(void)
//- rjf: clipboard commits
{
Temp scratch = scratch_begin(0, 0);
UI_Box *box = ui_box_from_key(ui_state->clipboard_copy_key);
String8List strs = {0};
if(!ui_box_is_nil(box))
{
Temp scratch = scratch_begin(0, 0);
String8List strs = {0};
UI_BoxRec rec = {0};
for(UI_Box *b = box; !ui_box_is_nil(b); rec = ui_box_rec_df_pre(b, box), b = rec.next)
{
@@ -1334,8 +1393,8 @@ ui_end_build(void)
String8 string = str8_list_join(scratch.arena, &strs, &join);
os_set_clipboard_text(string);
}
scratch_end(scratch);
}
scratch_end(scratch);
}
//- rjf: hovering possibly-truncated drawn text -> store text
@@ -2336,33 +2395,33 @@ ui_do_single_line_string_edits(TxtPt *cursor, TxtPt *mark, U64 string_max, Strin
{
B32 change = 0;
Temp scratch = scratch_begin(0, 0);
UI_NavActionList *nav_actions = ui_nav_actions();
for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next)
UI_EventList *events = ui_events();
for(UI_EventNode *n = events->first, *next = 0; n != 0; n = next)
{
next = n->next;
// rjf: do not consume anything that doesn't fit a single-line's operations
if(n->v.delta.y != 0)
if((n->v.kind != UI_EventKind_Edit && n->v.kind != UI_EventKind_Navigate && n->v.kind != UI_EventKind_Text) || n->v.delta_2s32.y != 0)
{
continue;
}
// rjf: map this action to an op
B32 taken = 0;
UI_NavTxtOp op = ui_nav_single_line_txt_op_from_action(scratch.arena, n->v, *out_string, *cursor, *mark);
UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, &n->v, *out_string, *cursor, *mark);
// rjf: perform replace range
if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0)
{
taken = 1;
String8 new_string = ui_nav_push_string_replace_range(scratch.arena, *out_string, r1s64(op.range.min.column, op.range.max.column), op.replace);
String8 new_string = ui_push_string_replace_range(scratch.arena, *out_string, r1s64(op.range.min.column, op.range.max.column), op.replace);
new_string.size = Min(string_max, new_string.size);
MemoryCopy(out_string->str, new_string.str, new_string.size);
out_string->size = new_string.size;
}
// rjf: perform copy
if(op.flags & UI_NavTxtOpFlag_Copy)
if(op.flags & UI_TxtOpFlag_Copy)
{
taken = 1;
os_set_clipboard_text(op.copy);
@@ -2376,7 +2435,7 @@ ui_do_single_line_string_edits(TxtPt *cursor, TxtPt *mark, U64 string_max, Strin
// rjf: consume event
if(taken)
{
ui_nav_eat_action_node(nav_actions, n);
ui_eat_event(events, n);
change = 1;
}
}
@@ -2435,15 +2494,13 @@ ui_signal_from_box(UI_Box *box)
//- rjf: process events related to this box
//
B32 view_scrolled = 0;
for(OS_Event *evt = ui_state->events->first, *next = 0;
evt != 0;
evt = next)
for(UI_EventNode *n = ui_state->events->first, *next = 0;
n != 0;
n = next)
{
B32 taken = 0;
next = evt->next;
//- rjf: skip disqualified events
if(!os_handle_match(evt->window, ui_state->window)) {continue;}
next = n->next;
UI_Event *evt = &n->v;
//- rjf: unpack event
Vec2F32 evt_mouse = evt->pos;
@@ -2455,11 +2512,11 @@ ui_signal_from_box(UI_Box *box)
B32 evt_key_is_mouse = (evt->key == OS_Key_LeftMouseButton ||
evt->key == OS_Key_MiddleMouseButton ||
evt->key == OS_Key_RightMouseButton);
sig.event_flags |= evt->flags;
sig.event_flags |= evt->modifiers;
//- rjf: mouse presses in box -> set hot/active; mark signal accordingly
if(box->flags & UI_BoxFlag_MouseClickable &&
evt->kind == OS_EventKind_Press &&
evt->kind == UI_EventKind_Press &&
evt_mouse_in_bounds &&
evt_key_is_mouse)
{
@@ -2493,7 +2550,7 @@ ui_signal_from_box(UI_Box *box)
//- rjf: mouse releases in active box -> unset active; mark signal accordingly
if(box->flags & UI_BoxFlag_MouseClickable &&
evt->kind == OS_EventKind_Release &&
evt->kind == UI_EventKind_Release &&
ui_key_match(ui_state->active_box_key[evt_mouse_button_kind], box->key) &&
evt_mouse_in_bounds &&
evt_key_is_mouse)
@@ -2506,7 +2563,7 @@ ui_signal_from_box(UI_Box *box)
//- rjf: mouse releases outside active box -> unset hot/active
if(box->flags & UI_BoxFlag_MouseClickable &&
evt->kind == OS_EventKind_Release &&
evt->kind == UI_EventKind_Release &&
ui_key_match(ui_state->active_box_key[evt_mouse_button_kind], box->key) &&
!evt_mouse_in_bounds &&
evt_key_is_mouse)
@@ -2520,21 +2577,60 @@ ui_signal_from_box(UI_Box *box)
//- rjf: focus is hot & keyboard click -> mark signal
if(box->flags & UI_BoxFlag_KeyboardClickable &&
is_focus_hot &&
evt->kind == OS_EventKind_Press &&
evt->key == OS_Key_Return)
evt->kind == UI_EventKind_Press &&
evt->slot == UI_EventActionSlot_Accept)
{
sig.f |= UI_SignalFlag_KeyboardPressed;
taken = 1;
}
//- rjf: focus is hot & copy event -> remember to copy this box tree's text content
if(is_focus_hot &&
evt->flags & UI_EventFlag_Copy &&
!ui_key_match(ui_key_zero(), box->key))
{
ui_state->clipboard_copy_key = box->key;
taken = 1;
}
//- rjf: ancestor is focused & fastpath codepoint pressed -> press
if(box->flags & UI_BoxFlag_Clickable && box->fastpath_codepoint != 0 && evt->string.size != 0)
{
B32 ancestor_is_focused = 0;
for(UI_Box *parent = box->parent; !ui_box_is_nil(parent); parent = parent->parent)
{
if(parent->flags & UI_BoxFlag_FocusActive)
{
ancestor_is_focused = 1;
if(parent->flags & UI_BoxFlag_FocusActiveDisabled ||
!ui_key_match(parent->default_nav_focus_active_key, ui_key_zero()))
{
ancestor_is_focused = 0;
break;
}
}
}
if(ancestor_is_focused)
{
Temp scratch = scratch_begin(0, 0);
String32 insertion32 = str32_from_8(scratch.arena, evt->string);
if(insertion32.size == 1 && insertion32.str[0] == box->fastpath_codepoint)
{
taken = 1;
sig.f |= UI_SignalFlag_Clicked|UI_SignalFlag_Pressed;
}
scratch_end(scratch);
}
}
//- rjf: scrolling
if(box->flags & UI_BoxFlag_Scroll &&
evt->kind == OS_EventKind_Scroll &&
evt->flags != OS_EventFlag_Ctrl &&
evt->kind == UI_EventKind_Scroll &&
evt->modifiers != OS_EventFlag_Ctrl &&
evt_mouse_in_bounds)
{
Vec2F32 delta = evt->delta;
if(evt->flags & OS_EventFlag_Shift)
Vec2F32 delta = evt->delta_2f32;
if(evt->modifiers & OS_EventFlag_Shift)
{
Swap(F32, delta.x, delta.y);
}
@@ -2550,12 +2646,12 @@ ui_signal_from_box(UI_Box *box)
//- rjf: view scrolling
if(box->flags & UI_BoxFlag_ViewScroll && box->first_touched_build_index != box->last_touched_build_index &&
evt->kind == OS_EventKind_Scroll &&
evt->flags != OS_EventFlag_Ctrl &&
evt->kind == UI_EventKind_Scroll &&
evt->modifiers != OS_EventFlag_Ctrl &&
evt_mouse_in_bounds)
{
Vec2F32 delta = evt->delta;
if(evt->flags & OS_EventFlag_Shift)
Vec2F32 delta = evt->delta_2f32;
if(evt->modifiers & OS_EventFlag_Shift)
{
Swap(F32, delta.x, delta.y);
}
@@ -2575,7 +2671,6 @@ ui_signal_from_box(UI_Box *box)
}
delta.y = 0;
}
os_eat_event(ui_state->events, evt);
box->view_off_target.x += delta.x;
box->view_off_target.y += delta.y;
view_scrolled = 1;
@@ -2585,58 +2680,7 @@ ui_signal_from_box(UI_Box *box)
//- rjf: taken -> eat event
if(taken)
{
os_eat_event(ui_state->events, evt);
}
}
//////////////////////////////
//- rjf: process nav actions related to this box
//
{
for(UI_NavActionNode *n = ui_state->nav_actions->first, *next = 0;
n != 0;
n = next)
{
next = n->next;
UI_NavAction *action = &n->v;
B32 taken = 0;
if(is_focus_hot && box->flags & UI_BoxFlag_KeyboardClickable && action->flags & UI_NavActionFlag_Copy)
{
ui_state->clipboard_copy_key = box->key;
taken = 1;
}
if(box->flags & UI_BoxFlag_Clickable && box->fastpath_codepoint != 0)
{
B32 ancestor_is_focused = 0;
for(UI_Box *parent = box->parent; !ui_box_is_nil(parent); parent = parent->parent)
{
if(parent->flags & UI_BoxFlag_FocusActive)
{
ancestor_is_focused = 1;
if(parent->flags & UI_BoxFlag_FocusActiveDisabled ||
!ui_key_match(parent->default_nav_focus_active_key, ui_key_zero()))
{
ancestor_is_focused = 0;
break;
}
}
}
if(ancestor_is_focused && action->insertion.size != 0)
{
Temp scratch = scratch_begin(0, 0);
String32 insertion32 = str32_from_8(scratch.arena, action->insertion);
if(insertion32.size == 1 && insertion32.str[0] == box->fastpath_codepoint)
{
taken = 1;
sig.f |= UI_SignalFlag_Clicked|UI_SignalFlag_Pressed;
}
scratch_end(scratch);
}
}
if(taken)
{
ui_nav_eat_action_node(ui_nav_actions(), n);
}
ui_eat_event(ui_state->events, n);
}
}
+95 -56
View File
@@ -57,68 +57,107 @@ typedef enum UI_FocusKind
UI_FocusKind;
////////////////////////////////
//~ rjf: Navigation Types
//~ rjf: Events
typedef enum UI_NavDeltaUnit
// TODO(rjf): clean all this up
typedef enum UI_EventKind
{
UI_NavDeltaUnit_Element,
UI_NavDeltaUnit_Chunk,
UI_NavDeltaUnit_Whole,
UI_NavDeltaUnit_EndPoint,
UI_NavDeltaUnit_COUNT,
UI_EventKind_Null,
UI_EventKind_Press,
UI_EventKind_Release,
UI_EventKind_Text,
UI_EventKind_Navigate,
UI_EventKind_Edit,
UI_EventKind_MouseMove,
UI_EventKind_Scroll,
UI_EventKind_AutocompleteHint,
UI_EventKind_COUNT
}
UI_NavDeltaUnit;
UI_EventKind;
typedef U32 UI_NavActionFlags;
typedef enum UI_EventActionSlot
{
UI_EventActionSlot_Null,
UI_EventActionSlot_Accept,
UI_EventActionSlot_Cancel,
UI_EventActionSlot_Edit,
UI_EventActionSlot_COUNT
}
UI_EventActionSlot;
typedef U32 UI_EventFlags;
enum
{
UI_NavActionFlag_KeepMark = (1<<0),
UI_NavActionFlag_Delete = (1<<1),
UI_NavActionFlag_Copy = (1<<2),
UI_NavActionFlag_Paste = (1<<3),
UI_NavActionFlag_ZeroDeltaOnSelect = (1<<4),
UI_NavActionFlag_PickSelectSide = (1<<5),
UI_NavActionFlag_CapAtLine = (1<<6),
UI_NavActionFlag_ExplicitDirectional = (1<<7),
UI_NavActionFlag_ReplaceAndCommit = (1<<8),
UI_EventFlag_KeepMark = (1<<0),
UI_EventFlag_Delete = (1<<1),
UI_EventFlag_Copy = (1<<2),
UI_EventFlag_Paste = (1<<3),
UI_EventFlag_ZeroDeltaOnSelect = (1<<4),
UI_EventFlag_PickSelectSide = (1<<5),
UI_EventFlag_CapAtLine = (1<<6),
UI_EventFlag_ExplicitDirectional = (1<<7),
UI_EventFlag_Reorder = (1<<8),
};
typedef struct UI_NavAction UI_NavAction;
struct UI_NavAction
typedef enum UI_EventDeltaUnit
{
UI_NavActionFlags flags;
Vec2S32 delta;
UI_NavDeltaUnit delta_unit;
String8 insertion;
UI_EventDeltaUnit_Null,
UI_EventDeltaUnit_Char,
UI_EventDeltaUnit_Word,
UI_EventDeltaUnit_Line,
UI_EventDeltaUnit_Page,
UI_EventDeltaUnit_Whole,
UI_EventDeltaUnit_COUNT
}
UI_EventDeltaUnit;
typedef struct UI_Event UI_Event;
struct UI_Event
{
UI_EventKind kind;
UI_EventActionSlot slot;
UI_EventFlags flags;
UI_EventDeltaUnit delta_unit;
OS_Key key;
OS_EventFlags modifiers;
String8 string;
Vec2F32 pos;
Vec2F32 delta_2f32;
Vec2S32 delta_2s32;
U64 timestamp_us;
};
typedef struct UI_NavActionNode UI_NavActionNode;
struct UI_NavActionNode
typedef struct UI_EventNode UI_EventNode;
struct UI_EventNode
{
UI_NavActionNode *next;
UI_NavActionNode *prev;
UI_NavAction v;
UI_EventNode *next;
UI_EventNode *prev;
UI_Event v;
};
typedef struct UI_NavActionList UI_NavActionList;
struct UI_NavActionList
typedef struct UI_EventList UI_EventList;
struct UI_EventList
{
UI_NavActionNode *first;
UI_NavActionNode *last;
UI_EventNode *first;
UI_EventNode *last;
U64 count;
};
typedef U32 UI_NavTxtOpFlags;
////////////////////////////////
//~ rjf: Textual Operations
typedef U32 UI_TxtOpFlags;
enum
{
UI_NavTxtOpFlag_Invalid = (1<<0),
UI_NavTxtOpFlag_Copy = (1<<1),
UI_TxtOpFlag_Invalid = (1<<0),
UI_TxtOpFlag_Copy = (1<<1),
};
typedef struct UI_NavTxtOp UI_NavTxtOp;
struct UI_NavTxtOp
typedef struct UI_TxtOp UI_TxtOp;
struct UI_TxtOp
{
UI_NavTxtOpFlags flags;
UI_TxtOpFlags flags;
String8 replace;
String8 copy;
TxtRng range;
@@ -485,8 +524,7 @@ struct UI_State
//- rjf: build parameters
UI_IconInfo icon_info;
OS_Handle window;
OS_EventList *events;
UI_NavActionList *nav_actions;
UI_EventList *events;
Vec2F32 mouse;
F32 animation_dt;
B32 external_focus_commit;
@@ -542,22 +580,18 @@ internal UI_Key ui_key_from_stringf(UI_Key seed_key, char *fmt, ...);
internal B32 ui_key_match(UI_Key a, UI_Key b);
////////////////////////////////
//~ rjf: Navigation Action List Building & Consumption Functions
//~ rjf: Event Type Functions
internal void ui_nav_action_list_push(Arena *arena, UI_NavActionList *list, UI_NavAction action);
internal void ui_nav_eat_action_node(UI_NavActionList *list, UI_NavActionNode *node);
internal UI_EventNode *ui_event_list_push(Arena *arena, UI_EventList *list, UI_Event *v);
internal void ui_eat_event(UI_EventList *list, UI_EventNode *node);
////////////////////////////////
//~ rjf: High Level Navigation Action => Text Operations
//~ rjf: Text Operation Functions
internal B32 ui_nav_char_is_scan_boundary(U8 c);
internal S64 ui_nav_scanned_column_from_column(String8 string, S64 start_column, Side side);
internal UI_NavTxtOp ui_nav_single_line_txt_op_from_action(Arena *arena, UI_NavAction action, String8 line, TxtPt cursor, TxtPt mark);
////////////////////////////////
//~ rjf: Single-Line String Modification
internal String8 ui_nav_push_string_replace_range(Arena *arena, String8 string, Rng1S64 col_range, String8 replace);
internal B32 ui_char_is_scan_boundary(U8 c);
internal S64 ui_scanned_column_from_column(String8 string, S64 start_column, Side side);
internal UI_TxtOp ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string, TxtPt cursor, TxtPt mark);
internal String8 ui_push_string_replace_range(Arena *arena, String8 string, Rng1S64 range, String8 replace);
////////////////////////////////
//~ rjf: Size Type Functions
@@ -611,13 +645,18 @@ internal UI_State *ui_get_selected_state(void);
//- rjf: per-frame info
internal Arena * ui_build_arena(void);
internal OS_Handle ui_window(void);
internal OS_EventList * ui_events(void);
internal UI_NavActionList *ui_nav_actions(void);
internal UI_EventList * ui_events(void);
internal Vec2F32 ui_mouse(void);
internal F_Tag ui_icon_font(void);
internal String8 ui_icon_string_from_kind(UI_IconKind icon_kind);
internal F32 ui_dt(void);
//- rjf: event consumption helpers
internal B32 ui_key_press(OS_EventFlags mods, OS_Key key);
internal B32 ui_key_release(OS_EventFlags mods, OS_Key key);
internal B32 ui_text(U32 character);
internal B32 ui_slot_press(UI_EventActionSlot slot);
//- rjf: drag data
internal Vec2F32 ui_drag_start_mouse(void);
internal Vec2F32 ui_drag_delta(void);
@@ -644,7 +683,7 @@ internal UI_Box * ui_box_from_key(UI_Key key);
////////////////////////////////
//~ rjf: Top-Level Building API
internal void ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_actions, UI_IconInfo *icon_info, F32 real_dt, F32 animation_dt);
internal void ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, F32 real_dt, F32 animation_dt);
internal void ui_end_build(void);
internal void ui_calc_sizes_standalone__in_place_rec(UI_Box *root, Axis2 axis);
internal void ui_calc_sizes_upwards_dependent__in_place_rec(UI_Box *root, Axis2 axis);