diff --git a/src/base/base_context_cracking.h b/src/base/base_context_cracking.h index f9f1a782..9df1dc5e 100644 --- a/src/base/base_context_cracking.h +++ b/src/base/base_context_cracking.h @@ -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 diff --git a/src/base/base_log.c b/src/base/base_log.c index af7b25ec..b04a041e 100644 --- a/src/base/base_log.c +++ b/src/base/base_log.c @@ -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); } diff --git a/src/base/base_log.h b/src/base/base_log.h index ff4ac6e4..b5054b40 100644 --- a/src/base/base_log.h +++ b/src/base/base_log.h @@ -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 diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index daa2e619..625b6485 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -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; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 2c078221..0666e237 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -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); diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index 75b694c9..b150acd7 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -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) { diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index 578edffa..da0984ae 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -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); diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 908b4991..26f5bbfd 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -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(""); + 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; diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 485cc0b9..302d030c 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -354,6 +354,7 @@ struct DF_CoreViewRuleSpecInfo { String8 string; String8 display_string; + String8 schema; String8 description; DF_CoreViewRuleSpecInfoFlags flags; DF_CoreViewRuleEvalResolutionHookFunctionType *eval_resolution; diff --git a/src/df/core/df_core.mdesk b/src/df/core/df_core.mdesk index a5ac4af8..58ad9ba2 100644 --- a/src/df/core/df_core.mdesk +++ b/src/df/core/df_core.mdesk @@ -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 diff --git a/src/df/core/generated/df_core.meta.h b/src/df/core/generated/df_core.meta.h index 9eca62e3..5d52eec8 100644 --- a/src/df/core/generated/df_core.meta.h +++ b/src/df/core/generated/df_core.meta.h @@ -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]; diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 184190e1..eb993471 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -968,6 +968,7 @@ df_window_open(Vec2F32 size, OS_Handle preferred_monitor, DF_CfgSrc cfg_src) window->entity_ctx_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_entity_ctx_menu_")); window->tab_ctx_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_tab_ctx_menu_")); window->hover_eval_arena = arena_alloc(); + window->autocomp_lister_params_arena = arena_alloc(); window->free_panel = &df_g_nil_panel; window->root_panel = df_panel_alloc(window); window->focused_panel = window->root_panel; @@ -1030,7 +1031,7 @@ df_window_from_os_handle(OS_Handle os) #endif internal void -df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, DF_CmdList *cmds) +df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) { ProfBeginFunction(); @@ -1073,8 +1074,8 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D ////////////////////////////// //- rjf: do core-layer commands & batch up commands to be dispatched to views // + UI_EventList events = {0}; B32 panel_reset_done = 0; - UI_NavActionList nav_actions = {0}; ProfScope("do commands") { Temp scratch = scratch_begin(&arena, 1); @@ -1119,6 +1120,36 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } }break; + //- rjf: OS events + case DF_CoreCmdKind_OSEvent: + { + OS_Event *os_event = params.os_event; + if(os_event != 0 && os_handle_match(os_event->window, ws->os)) + { + UI_Event ui_event = zero_struct; + UI_EventKind kind = UI_EventKind_Null; + { + switch(os_event->kind) + { + default:{}break; + case OS_EventKind_Press: {kind = UI_EventKind_Press;}break; + case OS_EventKind_Release: {kind = UI_EventKind_Release;}break; + case OS_EventKind_MouseMove: {kind = UI_EventKind_MouseMove;}break; + case OS_EventKind_Text: {kind = UI_EventKind_Text;}break; + case OS_EventKind_Scroll: {kind = UI_EventKind_Scroll;}break; + } + } + ui_event.kind = kind; + ui_event.key = os_event->key; + ui_event.modifiers = os_event->flags; + ui_event.string = os_event->character ? str8_from_32(ui_build_arena(), str32(&os_event->character, 1)) : str8_zero(); + ui_event.pos = os_event->pos; + ui_event.delta_2f32 = os_event->delta; + ui_event.timestamp_us = os_event->timestamp_us; + ui_event_list_push(ui_build_arena(), &events, &ui_event); + } + }break; + //- rjf: command fast path case DF_CoreCmdKind_RunCommand: { @@ -2076,6 +2107,29 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } }break; + //- rjf: meta controls + case DF_CoreCmdKind_Edit: + { + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Press; + evt.slot = UI_EventActionSlot_Edit; + ui_event_list_push(ui_build_arena(), &events, &evt); + }break; + case DF_CoreCmdKind_Accept: + { + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Press; + evt.slot = UI_EventActionSlot_Accept; + ui_event_list_push(ui_build_arena(), &events, &evt); + }break; + case DF_CoreCmdKind_Cancel: + { + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Press; + evt.slot = UI_EventActionSlot_Cancel; + ui_event_list_push(ui_build_arena(), &events, &evt); + }break; + //- rjf: directional movement & text controls // // NOTE(rjf): These all get funneled into a separate intermediate that @@ -2084,191 +2138,345 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D // case DF_CoreCmdKind_MoveLeft: { - UI_NavAction action = {UI_NavActionFlag_PickSelectSide|UI_NavActionFlag_ZeroDeltaOnSelect|UI_NavActionFlag_ExplicitDirectional, {-1, +0}}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_PickSelectSide|UI_EventFlag_ZeroDeltaOnSelect|UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(-1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveRight: { - UI_NavAction action = {UI_NavActionFlag_PickSelectSide|UI_NavActionFlag_ZeroDeltaOnSelect|UI_NavActionFlag_ExplicitDirectional, {+1, +0}}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_PickSelectSide|UI_EventFlag_ZeroDeltaOnSelect|UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveUp: { - UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {+0, -1}}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+0, -1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveDown: { - UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {+0, +1}}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+0, +1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveLeftSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {-1, +0}}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(-1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveRightSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+1, +0}}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveUpSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, -1}}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+0, -1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveDownSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, +1}}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+0, +1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveLeftChunk: { - UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {-1, +0}, UI_NavDeltaUnit_Chunk}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Word; + evt.delta_2s32 = v2s32(-1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveRightChunk: { - UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {+1, +0}, UI_NavDeltaUnit_Chunk}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Word; + evt.delta_2s32 = v2s32(+1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveUpChunk: { - UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {+0, -1}, UI_NavDeltaUnit_Chunk}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Word; + evt.delta_2s32 = v2s32(+0, -1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveDownChunk: { - UI_NavAction action = {UI_NavActionFlag_ExplicitDirectional, {+0, +1}, UI_NavDeltaUnit_Chunk}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Word; + evt.delta_2s32 = v2s32(+0, +1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveUpPage: { - UI_NavAction action = {0, {+0, -1}, UI_NavDeltaUnit_Whole}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.delta_unit = UI_EventDeltaUnit_Page; + evt.delta_2s32 = v2s32(+0, -1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveDownPage: { - UI_NavAction action = {0, {+0, +1}, UI_NavDeltaUnit_Whole}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.delta_unit = UI_EventDeltaUnit_Page; + evt.delta_2s32 = v2s32(+0, +1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveUpWhole: { - UI_NavAction action = {0, {+0, -1}, UI_NavDeltaUnit_EndPoint}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.delta_unit = UI_EventDeltaUnit_Whole; + evt.delta_2s32 = v2s32(+0, -1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveDownWhole: { - UI_NavAction action = {0, {+0, +1}, UI_NavDeltaUnit_EndPoint}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.delta_unit = UI_EventDeltaUnit_Whole; + evt.delta_2s32 = v2s32(+0, +1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveLeftChunkSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {-1, +0}, UI_NavDeltaUnit_Chunk}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Word; + evt.delta_2s32 = v2s32(-1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveRightChunkSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+1, +0}, UI_NavDeltaUnit_Chunk}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Word; + evt.delta_2s32 = v2s32(+1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveUpChunkSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, -1}, UI_NavDeltaUnit_Chunk}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Word; + evt.delta_2s32 = v2s32(+0, -1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveDownChunkSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, +1}, UI_NavDeltaUnit_Chunk}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; + evt.delta_unit = UI_EventDeltaUnit_Word; + evt.delta_2s32 = v2s32(+0, +1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveUpPageSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, -1}, UI_NavDeltaUnit_Whole}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark; + evt.delta_unit = UI_EventDeltaUnit_Page; + evt.delta_2s32 = v2s32(+0, -1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveDownPageSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark|UI_NavActionFlag_ExplicitDirectional, {+0, +1}, UI_NavDeltaUnit_Whole}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark; + evt.delta_unit = UI_EventDeltaUnit_Page; + evt.delta_2s32 = v2s32(+0, +1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveUpWholeSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark, {+0, -1}, UI_NavDeltaUnit_EndPoint}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark; + evt.delta_unit = UI_EventDeltaUnit_Whole; + evt.delta_2s32 = v2s32(+0, -1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveDownWholeSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark, {+0, +1}, UI_NavDeltaUnit_EndPoint}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark; + evt.delta_unit = UI_EventDeltaUnit_Whole; + evt.delta_2s32 = v2s32(+0, +1); + ui_event_list_push(ui_build_arena(), &events, &evt); + }break; + case DF_CoreCmdKind_MoveUpReorder: + { + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_Reorder; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+0, -1); + ui_event_list_push(ui_build_arena(), &events, &evt); + }break; + case DF_CoreCmdKind_MoveDownReorder: + { + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_Reorder; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+0, +1); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveHome: { - UI_NavAction action = {0, {-1, +0}, UI_NavDeltaUnit_Whole}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.delta_unit = UI_EventDeltaUnit_Line; + evt.delta_2s32 = v2s32(-1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveEnd: { - UI_NavAction action = {0, {+1, +0}, UI_NavDeltaUnit_Whole}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.delta_unit = UI_EventDeltaUnit_Line; + evt.delta_2s32 = v2s32(+1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveHomeSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark, {-1, +0}, UI_NavDeltaUnit_Whole}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark; + evt.delta_unit = UI_EventDeltaUnit_Line; + evt.delta_2s32 = v2s32(-1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_MoveEndSelect: { - UI_NavAction action = {UI_NavActionFlag_KeepMark, {+1, +0}, UI_NavDeltaUnit_Whole}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_KeepMark; + evt.delta_unit = UI_EventDeltaUnit_Line; + evt.delta_2s32 = v2s32(+1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_SelectAll: { - UI_NavAction action1 = {0, {-1, +0}, UI_NavDeltaUnit_EndPoint}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action1); - UI_NavAction action2 = {UI_NavActionFlag_KeepMark, {+1, +0}, UI_NavDeltaUnit_EndPoint}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action2); + UI_Event evt1 = zero_struct; + evt1.kind = UI_EventKind_Navigate; + evt1.delta_unit = UI_EventDeltaUnit_Whole; + evt1.delta_2s32 = v2s32(-1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt1); + UI_Event evt2 = zero_struct; + evt2.kind = UI_EventKind_Navigate; + evt2.flags = UI_EventFlag_KeepMark; + evt2.delta_unit = UI_EventDeltaUnit_Whole; + evt2.delta_2s32 = v2s32(+1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt2); }break; case DF_CoreCmdKind_DeleteSingle: { - UI_NavAction action = {UI_NavActionFlag_Delete, {+1, +0}, UI_NavDeltaUnit_Element}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Edit; + evt.flags = UI_EventFlag_Delete; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_DeleteChunk: { - UI_NavAction action = {UI_NavActionFlag_Delete, {+1, +0}, UI_NavDeltaUnit_Chunk}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Edit; + evt.flags = UI_EventFlag_Delete; + evt.delta_unit = UI_EventDeltaUnit_Word; + evt.delta_2s32 = v2s32(+1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_BackspaceSingle: { - UI_NavAction action = {UI_NavActionFlag_Delete|UI_NavActionFlag_ZeroDeltaOnSelect, {-1, +0}, UI_NavDeltaUnit_Element}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Edit; + evt.flags = UI_EventFlag_Delete|UI_EventFlag_ZeroDeltaOnSelect; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(-1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_BackspaceChunk: { - UI_NavAction action = {UI_NavActionFlag_Delete|UI_NavActionFlag_ZeroDeltaOnSelect, {-1, +0}, UI_NavDeltaUnit_Chunk}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Edit; + evt.flags = UI_EventFlag_Delete; + evt.delta_unit = UI_EventDeltaUnit_Word; + evt.delta_2s32 = v2s32(-1, +0); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_Copy: { - UI_NavAction action = {UI_NavActionFlag_Copy|UI_NavActionFlag_KeepMark}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Edit; + evt.flags = UI_EventFlag_Copy|UI_EventFlag_KeepMark; + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_Cut: { - UI_NavAction action = {UI_NavActionFlag_Copy|UI_NavActionFlag_Delete}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Edit; + evt.flags = UI_EventFlag_Copy|UI_EventFlag_Delete; + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_Paste: { - UI_NavAction action = {UI_NavActionFlag_Paste}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Text; + evt.string = os_get_clipboard_text(ui_build_arena()); + ui_event_list_push(ui_build_arena(), &events, &evt); }break; case DF_CoreCmdKind_InsertText: { - String8 insertion = params.string; - UI_NavAction action = {0, {0}, (UI_NavDeltaUnit)0, push_str8_copy(ui_build_arena(), insertion)}; - ui_nav_action_list_push(ui_build_arena(), &nav_actions, action); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Text; + evt.string = params.string; + ui_event_list_push(ui_build_arena(), &events, &evt); }break; //- rjf: address finding @@ -3073,7 +3281,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } // rjf: begin & push initial stack values - ui_begin_build(events, ws->os, &nav_actions, &icon_info, df_dt(), df_dt()); + ui_begin_build(ws->os, &events, &icon_info, df_dt(), df_dt()); ui_push_font(main_font); ui_push_font_size(main_font_size); ui_push_pref_width(ui_em(20.f, 1)); @@ -4008,14 +4216,14 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBackground)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_ActionText)) UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBorder)) - if(ui_clicked(ui_buttonf("OK")) || (ui_key_match(bg_box->default_nav_focus_hot_key, ui_key_zero()) && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return))) + if(ui_clicked(ui_buttonf("OK")) || (ui_key_match(bg_box->default_nav_focus_hot_key, ui_key_zero()) && ui_slot_press(UI_EventActionSlot_Accept))) { DF_CmdParams p = df_cmd_params_zero(); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ConfirmAccept)); } UI_CornerRadius10(ui_top_font_size()*0.25f) UI_CornerRadius11(ui_top_font_size()*0.25f) - if(ui_clicked(ui_buttonf("Cancel")) || os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + if(ui_clicked(ui_buttonf("Cancel")) || ui_slot_press(UI_EventActionSlot_Cancel)) { DF_CmdParams p = df_cmd_params_zero(); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ConfirmCancel)); @@ -4052,7 +4260,8 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D //- rjf: gather lister items DF_AutoCompListerItemChunkList item_list = {0}; { - if(ws->autocomp_lister_flags & DF_AutoCompListerFlag_Locals) + //- rjf: gather locals + if(ws->autocomp_lister_params.flags & DF_AutoCompListerFlag_Locals) { EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_binary_voff(binary, thread_rip_voff); for(EVAL_String2NumMapNode *n = locals_map->first; n != 0; n = n->order_next) @@ -4069,7 +4278,9 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } } } - if(ws->autocomp_lister_flags & DF_AutoCompListerFlag_Registers) + + //- rjf: gather registers + if(ws->autocomp_lister_params.flags & DF_AutoCompListerFlag_Registers) { Architecture arch = df_architecture_from_entity(thread); U64 reg_names_count = regs_reg_code_count_from_architecture(arch); @@ -4109,7 +4320,9 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } } } - if(ws->autocomp_lister_flags & DF_AutoCompListerFlag_ViewRules) + + //- rjf: gather view rules + if(ws->autocomp_lister_params.flags & DF_AutoCompListerFlag_ViewRules) { for(U64 slot_idx = 0; slot_idx < df_state->view_rule_spec_table_size; slot_idx += 1) { @@ -4128,6 +4341,79 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } } } + + //- rjf: gather languages + if(ws->autocomp_lister_params.flags & DF_AutoCompListerFlag_Languages) + { + for(EachNonZeroEnumVal(TXT_LangKind, lang)) + { + DF_AutoCompListerItem item = {0}; + { + item.string = txt_extension_from_lang_kind(lang); + item.kind_string = str8_lit("Language"); + item.matches = fuzzy_match_find(scratch.arena, query, item.string); + } + if(query.size == 0 || item.matches.count != 0) + { + df_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); + } + } + } + + //- rjf: gather architectures + if(ws->autocomp_lister_params.flags & DF_AutoCompListerFlag_Architectures) + { + for(EachNonZeroEnumVal(Architecture, arch)) + { + DF_AutoCompListerItem item = {0}; + { + item.string = string_from_architecture(arch); + item.kind_string = str8_lit("Architecture"); + item.matches = fuzzy_match_find(scratch.arena, query, item.string); + } + if(query.size == 0 || item.matches.count != 0) + { + df_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); + } + } + } + + //- rjf: gather tex2dformats + if(ws->autocomp_lister_params.flags & DF_AutoCompListerFlag_Tex2DFormats) + { + for(EachNonZeroEnumVal(R_Tex2DFormat, fmt)) + { + DF_AutoCompListerItem item = {0}; + { + item.string = lower_from_str8(scratch.arena, r_tex2d_format_display_string_table[fmt]); + item.kind_string = str8_lit("Format"); + item.matches = fuzzy_match_find(scratch.arena, query, item.string); + } + if(query.size == 0 || item.matches.count != 0) + { + df_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); + } + } + } + + //- rjf: gather view rule params + if(ws->autocomp_lister_params.flags & DF_AutoCompListerFlag_ViewRuleParams) + { + for(String8Node *n = ws->autocomp_lister_params.strings.first; n != 0; n = n->next) + { + String8 string = n->string; + DF_AutoCompListerItem item = {0}; + { + item.string = string; + item.kind_string = str8_lit("Parameter"); + item.matches = fuzzy_match_find(scratch.arena, query, item.string); + } + if(query.size == 0 || item.matches.count != 0) + { + df_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); + } + } + } } //- rjf: lister item list -> sorted array @@ -4139,7 +4425,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D // rjf: animate target # of rows { F32 rate = 1 - pow_f32(2, (-60.f * df_dt())); - F32 target = Min((F32)item_array.count, 8.f); + F32 target = Min((F32)item_array.count, 16.f); if(abs_f32(target - ws->autocomp_num_visible_rows_t) > 0.01f) { df_gfx_request_frame(); @@ -4183,7 +4469,12 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_Squish(0.25f-0.25f*ws->autocomp_open_t) UI_Transparency(1.f-ws->autocomp_open_t) { - autocomp_box = ui_build_box_from_stringf(UI_BoxFlag_DefaultFocusNavY|UI_BoxFlag_Clip|UI_BoxFlag_RoundChildrenByParent|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBackground, "autocomp_box"); + autocomp_box = ui_build_box_from_stringf(UI_BoxFlag_DefaultFocusNavY|UI_BoxFlag_Clickable|UI_BoxFlag_Clip|UI_BoxFlag_RoundChildrenByParent|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBackground, "autocomp_box"); + if(ws->autocomp_query_dirty) + { + ws->autocomp_query_dirty = 0; + autocomp_box->default_nav_focus_hot_key = autocomp_box->default_nav_focus_active_key = autocomp_box->default_nav_focus_next_hot_key = autocomp_box->default_nav_focus_next_active_key = ui_key_zero(); + } } UI_Parent(autocomp_box) UI_WidthFill UI_PrefHeight(ui_px(row_height_px, 1.f)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_HoverCursor(OS_Cursor_HandPoint) UI_Focus(UI_FocusKind_Null) @@ -4191,10 +4482,14 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D for(U64 idx = 0; idx < item_array.count; idx += 1) { DF_AutoCompListerItem *item = &item_array.v[idx]; - UI_Box *item_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawActiveEffects|UI_BoxFlag_Clickable, "autocomp_%I64x", idx); + UI_Box *item_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawActiveEffects|UI_BoxFlag_MouseClickable, "autocomp_%I64x", idx); UI_Parent(item_box) { - UI_WidthFill ui_label(item->string); + UI_WidthFill + { + UI_Box *box = ui_label(item->string).box; + ui_box_equip_fuzzy_match_ranges(box, &item->matches); + } UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_PrefWidth(ui_text_dim(10, 1)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) @@ -4203,8 +4498,23 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_Signal item_sig = ui_signal_from_box(item_box); if(ui_clicked(item_sig)) { - UI_NavAction autocomp_action = {UI_NavActionFlag_ReplaceAndCommit, {0}, (UI_NavDeltaUnit)0, push_str8_copy(ui_build_arena(), item->string)}; - ui_nav_action_list_push(ui_build_arena(), ui_nav_actions(), autocomp_action); + UI_Event move_back_evt = zero_struct; + move_back_evt.kind = UI_EventKind_Navigate; + move_back_evt.flags = UI_EventFlag_KeepMark; + move_back_evt.delta_2s32.x = -(S32)query.size; + ui_event_list_push(ui_build_arena(), &events, &move_back_evt); + UI_Event paste_evt = zero_struct; + paste_evt.kind = UI_EventKind_Text; + paste_evt.string = item->string; + ui_event_list_push(ui_build_arena(), &events, &paste_evt); + autocomp_box->default_nav_focus_hot_key = autocomp_box->default_nav_focus_active_key = autocomp_box->default_nav_focus_next_hot_key = autocomp_box->default_nav_focus_next_active_key = ui_key_zero(); + } + else if(item_box->flags & UI_BoxFlag_FocusHot && !(item_box->flags & UI_BoxFlag_FocusHotDisabled)) + { + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_AutocompleteHint; + evt.string = item->string; + ui_event_list_push(ui_build_arena(), &events, &evt); } } } @@ -4544,28 +4854,28 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D U64 open_menu_idx_prime = open_menu_idx; if(menu_open && ws->menu_bar_focused && window_is_focused) { - UI_NavActionList *nav_actions = ui_nav_actions(); - for(UI_NavActionNode *n = nav_actions->first, *next = 0; + UI_EventList *events = ui_events(); + for(UI_EventNode *n = events->first, *next = 0; n != 0; n = next) { next = n->next; - UI_NavAction *action = &n->v; + UI_Event *evt = &n->v; B32 taken = 0; - if(action->delta.x > 0) + if(evt->delta_2s32.x > 0) { taken = 1; open_menu_idx_prime += 1; open_menu_idx_prime = open_menu_idx_prime%ArrayCount(items); } - if(action->delta.x < 0) + if(evt->delta_2s32.x < 0) { taken = 1; open_menu_idx_prime = open_menu_idx_prime > 0 ? open_menu_idx_prime-1 : (ArrayCount(items)-1); } if(taken) { - ui_nav_eat_action_node(nav_actions, n); + ui_eat_event(events, n); } } } @@ -4575,7 +4885,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D { ui_set_next_fastpath_codepoint(items[idx].codepoint); B32 alt_fastpath_key = 0; - if(os_key_press(ui_events(), ui_window(), OS_EventFlag_Alt, items[idx].key)) + if(ui_key_press(OS_EventFlag_Alt, items[idx].key)) { alt_fastpath_key = 1; } @@ -5310,14 +5620,14 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D //- rjf: query submission if((ui_is_focus_active() || (window_is_focused && !ui_any_ctx_menu_is_open() && !ws->menu_bar_focused && !ws->query_view_selected)) && - os_key_press(events, ws->os, 0, OS_Key_Esc)) + ui_slot_press(UI_EventActionSlot_Cancel)) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CancelQuery)); } if(ui_is_focus_active()) { - if(os_key_press(events, ws->os, 0, OS_Key_Return)) + if(ui_slot_press(UI_EventActionSlot_Accept)) { Temp scratch = scratch_begin(&arena, 1); DF_View *view = ws->query_view_stack_top; @@ -5352,6 +5662,10 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); } } + else + { + ws->query_view_selected = 0; + } //////////////////////////// //- rjf: build hover eval @@ -6238,7 +6552,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D DF_View *view = df_view_from_handle(panel->selected_tab_view); UI_Focus(UI_FocusKind_On) { - if(view->is_filtering && ui_is_focus_active() && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(view->is_filtering && ui_is_focus_active() && ui_slot_press(UI_EventActionSlot_Accept)) { DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ApplyFilter)); @@ -6457,25 +6771,26 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(ui_is_focus_active() && view->spec->info.flags & DF_ViewSpecFlag_TypingAutomaticallyFilters && !view->is_filtering) { DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); - for(UI_NavActionNode *n = ui_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; - if(n->v.flags & UI_NavActionFlag_Paste) + if(n->v.flags & UI_EventFlag_Paste) { - ui_nav_eat_action_node(ui_nav_actions(), n); + ui_eat_event(events, n); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Filter)); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Paste)); } - else if(n->v.insertion.size != 0) + else if(n->v.string.size != 0 && n->v.kind == UI_EventKind_Text) { - ui_nav_eat_action_node(ui_nav_actions(), n); + ui_eat_event(events, n); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Filter)); - p.string = n->v.insertion; + p.string = n->v.string; df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_InsertText)); } } } - if((view->query_string_size != 0 || view->is_filtering) && ui_is_focus_active() && os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + if((view->query_string_size != 0 || view->is_filtering) && ui_is_focus_active() && ui_slot_press(UI_EventActionSlot_Cancel)) { DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ClearFilter)); @@ -6786,7 +7101,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D // rjf: space for next tab { - ui_spacer(ui_em(0.15f, 1.f)); + ui_spacer(ui_em(0.3f, 1.f)); } // rjf: store off drop-site @@ -6885,7 +7200,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D // rjf: drop DF_DragDropPayload payload = df_g_drag_drop_payload; - if(catchall_drop_site_hovered && (active_drop_site != 0 && df_drag_drop(&payload)) || (df_panel_from_handle(payload.panel) == panel && 0)) + if(catchall_drop_site_hovered && (active_drop_site != 0 && df_drag_drop(&payload))) { DF_View *view = df_view_from_handle(payload.view); DF_Panel *src_panel = df_panel_from_handle(payload.panel); @@ -7046,7 +7361,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D //////////////////////////// //- rjf: drag/drop cancelling // - if(df_drag_is_active() && os_key_press(events, ws->os, 0, OS_Key_Esc)) + if(df_drag_is_active() && ui_slot_press(UI_EventActionSlot_Cancel)) { df_drag_kill(); ui_kill_action(); @@ -7055,17 +7370,19 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D //////////////////////////// //- rjf: font size changing // - for(OS_Event *event = events->first; event != 0; event = event->next) + for(UI_EventNode *n = events.first, *next = 0; n != 0; n = next) { - if(os_handle_match(event->window, ws->os) && event->kind == OS_EventKind_Scroll && event->flags & OS_EventFlag_Ctrl) + next = n->next; + UI_Event *event = &n->v; + if(event->kind == UI_EventKind_Scroll && event->modifiers & OS_EventFlag_Ctrl) { - os_eat_event(ui_events(), event); - if(event->delta.y < 0) + ui_eat_event(&events, n); + if(event->delta_2f32.y < 0) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_IncUIFontScale)); } - else if(event->delta.y > 0) + else if(event->delta_2f32.y > 0) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_DecUIFontScale)); @@ -7127,7 +7444,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D ////////////////////////////// //- rjf: hover eval cancelling // - if(ws->hover_eval_string.size != 0 && os_key_press(events, ws->os, 0, OS_Key_Esc)) + if(ws->hover_eval_string.size != 0 && ui_slot_press(UI_EventActionSlot_Cancel)) { MemoryZeroStruct(&ws->hover_eval_string); arena_clear(ws->hover_eval_arena); @@ -8508,10 +8825,173 @@ df_autocomp_lister_item_array_sort__in_place(DF_AutoCompListerItemArray *array) qsort(array->v, array->count, sizeof(array->v[0]), (int (*)(const void*, const void*))df_autocomp_lister_item_qsort_compare); } -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) { + U64 word_start_off = 0; + for(U64 off = 0; off < input.size && off < cursor_off; off += 1) + { + if(!char_is_alpha(input.str[off]) && !char_is_digit(input.str[off], 10) && input.str[off] != '_') + { + word_start_off = off+1; + } + } + String8 query = str8_skip(str8_prefix(input, cursor_off), word_start_off); + return query; +} + +internal DF_AutoCompListerParams +df_view_rule_autocomp_lister_params_from_input_cursor(Arena *arena, String8 string, U64 cursor_off) +{ + DF_AutoCompListerParams params = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: do partial parse of input + MD_TokenizeResult input_tokenize = md_tokenize_from_text(scratch.arena, string); + + //- rjf: find descension steps to cursor + typedef struct DescendStep DescendStep; + struct DescendStep + { + DescendStep *next; + DescendStep *prev; + String8 string; + }; + DescendStep *first_step = 0; + DescendStep *last_step = 0; + DescendStep *free_step = 0; + S32 paren_nest = 0; + S32 colon_nest = 0; + String8 last_step_string = {0}; + for(U64 idx = 0; idx < input_tokenize.tokens.count; idx += 1) + { + MD_Token *token = &input_tokenize.tokens.v[idx]; + if(token->range.min >= cursor_off) + { + break; + } + String8 token_string = str8_substr(string, token->range); + if(token->flags & (MD_TokenFlag_Identifier|MD_TokenFlag_StringLiteral)) + { + last_step_string = token_string; + } + if(str8_match(token_string, str8_lit("("), 0) || str8_match(token_string, str8_lit("["), 0) || str8_match(token_string, str8_lit("{"), 0)) + { + paren_nest += 1; + } + if(str8_match(token_string, str8_lit(")"), 0) || str8_match(token_string, str8_lit("]"), 0) || str8_match(token_string, str8_lit("}"), 0)) + { + paren_nest -= 1; + for(;colon_nest > paren_nest; colon_nest -= 1) + { + if(last_step != 0) + { + DescendStep *step = last_step; + DLLRemove(first_step, last_step, step); + SLLStackPush(free_step, step); + } + } + if(paren_nest == 0 && last_step != 0) + { + DescendStep *step = last_step; + DLLRemove(first_step, last_step, step); + SLLStackPush(free_step, step); + } + } + if(str8_match(token_string, str8_lit(":"), 0)) + { + colon_nest += 1; + if(last_step_string.size != 0) + { + DescendStep *step = free_step; + if(step != 0) + { + SLLStackPop(free_step); + MemoryZeroStruct(step); + } + else + { + step = push_array(scratch.arena, DescendStep, 1); + } + step->string = last_step_string; + DLLPushBack(first_step, last_step, step); + } + } + if(str8_match(token_string, str8_lit(";"), 0) || str8_match(token_string, str8_lit(","), 0)) + { + for(;colon_nest > paren_nest; colon_nest -= 1) + { + if(last_step != 0) + { + DescendStep *step = last_step; + DLLRemove(first_step, last_step, step); + SLLStackPush(free_step, step); + } + } + } + } + + //- rjf: map view rule root to spec + DF_CoreViewRuleSpec *spec = df_core_view_rule_spec_from_string(first_step ? first_step->string : str8_zero()); + + //- rjf: do parse of schema + MD_TokenizeResult schema_tokenize = md_tokenize_from_text(scratch.arena, spec->info.schema); + MD_ParseResult schema_parse = md_parse_from_text_tokens(scratch.arena, str8_zero(), spec->info.schema, schema_tokenize.tokens); + MD_Node *schema_rule_root = md_child_from_string(schema_parse.root, str8_lit("x"), 0); + + //- rjf: follow schema according to descend steps, gather flags from schema node matching cursor descension steps + if(first_step != 0) + { + MD_Node *schema_node = schema_rule_root; + for(DescendStep *step = first_step->next;;) + { + if(step == 0) + { + for(MD_EachNode(child, schema_node->first)) + { + if(0){} + else if(str8_match(child->string, str8_lit("expr"), StringMatchFlag_CaseInsensitive)) {params.flags |= DF_AutoCompListerFlag_Locals;} + else if(str8_match(child->string, str8_lit("member"), StringMatchFlag_CaseInsensitive)) {params.flags |= DF_AutoCompListerFlag_Members;} + else if(str8_match(child->string, str8_lit("lang"), StringMatchFlag_CaseInsensitive)) {params.flags |= DF_AutoCompListerFlag_Languages;} + else if(str8_match(child->string, str8_lit("arch"), StringMatchFlag_CaseInsensitive)) {params.flags |= DF_AutoCompListerFlag_Architectures;} + else if(str8_match(child->string, str8_lit("tex2dformat"), StringMatchFlag_CaseInsensitive)) {params.flags |= DF_AutoCompListerFlag_Tex2DFormats;} + else if(child->flags & (MD_NodeFlag_StringSingleQuote|MD_NodeFlag_StringDoubleQuote|MD_NodeFlag_StringTick)) + { + str8_list_push(arena, ¶ms.strings, child->string); + params.flags |= DF_AutoCompListerFlag_ViewRuleParams; + } + } + break; + } + if(step != 0) + { + MD_Node *next_node = md_child_from_string(schema_node, step->string, StringMatchFlag_CaseInsensitive); + schema_node = next_node; + step = step->next; + } + else + { + schema_node = schema_node->first; + } + } + } + + scratch_end(scratch); + } + return params; +} + +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) +{ + String8 query = df_autocomp_query_word_from_input_string_off(input, cursor_off); String8 current_query = str8(ws->autocomp_lister_query_buffer, ws->autocomp_lister_query_size); + if(cursor_off != ws->autocomp_cursor_off) + { + ws->autocomp_query_dirty = 1; + ws->autocomp_cursor_off = cursor_off; + } if(!str8_match(query, current_query, 0)) { ws->autocomp_force_closed = 0; @@ -8530,7 +9010,9 @@ df_set_autocomp_lister_query(DF_Window *ws, UI_Key root_key, DF_CtrlCtx ctrl_ctx } ws->autocomp_ctrl_ctx = ctrl_ctx; ws->autocomp_root_key = root_key; - ws->autocomp_lister_flags = flags; + arena_clear(ws->autocomp_lister_params_arena); + MemoryCopyStruct(&ws->autocomp_lister_params, params); + ws->autocomp_lister_params.strings = str8_list_copy(ws->autocomp_lister_params_arena, &ws->autocomp_lister_params.strings); ws->autocomp_lister_query_size = Min(query.size, sizeof(ws->autocomp_lister_query_buffer)); MemoryCopy(ws->autocomp_lister_query_buffer, query.str, ws->autocomp_lister_query_size); ws->autocomp_last_frame_idx = df_frame_index(); @@ -10064,6 +10546,14 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ UI_Box *margin_container_box = &ui_g_nil_box; if(params->flags & DF_CodeSliceFlag_Margin) UI_Focus(UI_FocusKind_Off) UI_Parent(top_container_box) ProfScope("build margins") { + if(params->margin_float_off_px != 0) + { + ui_set_next_pref_width(ui_px(params->margin_width_px, 1)); + ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); + ui_build_box_from_key(0, ui_key_zero()); + ui_set_next_fixed_x(params->margin_float_off_px); + ui_set_next_flags(UI_BoxFlag_DrawBackground); + } ui_set_next_pref_width(ui_px(params->margin_width_px, 1)); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); ui_set_next_child_layout_axis(Axis2_Y); @@ -10673,17 +11163,20 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ //- rjf: hovering text container & ctrl+scroll -> change font size if(ui_hovering(text_container_sig)) { - for(OS_Event *event = ui_events()->first; event != 0; event = event->next) + UI_EventList *events = ui_events(); + for(UI_EventNode *n = events->first, *next = 0; n != 0; n = next) { - if(os_handle_match(event->window, ui_window()) && event->kind == OS_EventKind_Scroll && event->flags & OS_EventFlag_Ctrl) + next = n->next; + UI_Event *event = &n->v; + if(event->kind == UI_EventKind_Scroll && event->modifiers & OS_EventFlag_Ctrl) { - os_eat_event(ui_events(), event); - if(event->delta.y < 0) + ui_eat_event(events, n); + if(event->delta_2f32.y < 0) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_IncCodeFontScale)); } - else if(event->delta.y > 0) + else if(event->delta_2f32.y > 0) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_DecCodeFontScale)); @@ -10851,9 +11344,20 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ TxtRng select_rng = txt_rng(*cursor, *mark); Vec4F32 inactive_color = df_rgba_from_theme_color(DF_ThemeColor_WeakText); Vec4F32 active_color = df_rgba_from_theme_color(DF_ThemeColor_PlainText); + if(params->margin_float_off_px != 0) + { + ui_set_next_pref_width(ui_px(params->line_num_width_px, 1.f)); + ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); + ui_build_box_from_key(0, ui_key_zero()); + ui_set_next_fixed_x(params->margin_float_off_px); + ui_set_next_flags(UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawSideRight|UI_BoxFlag_DrawSideLeft); + } + else + { + ui_set_next_flags(UI_BoxFlag_DrawSideRight|UI_BoxFlag_DrawSideLeft); + } ui_set_next_pref_width(ui_px(params->line_num_width_px, 1.f)); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); - ui_set_next_flags(UI_BoxFlag_DrawSideRight|UI_BoxFlag_DrawSideLeft); UI_Column UI_PrefHeight(ui_px(params->line_height_px, 1.f)) UI_Font(params->font) @@ -11275,25 +11779,28 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx { Temp scratch = scratch_begin(0, 0); B32 change = 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; + if(n->v.kind != UI_EventKind_Navigate && n->v.kind != UI_EventKind_Edit) + { + continue; + } B32 taken = 0; - String8 line = txt_string_from_info_data_line_num(info, data, cursor->line); - UI_NavTxtOp single_line_op = ui_nav_single_line_txt_op_from_action(scratch.arena, n->v, line, *cursor, *mark); + UI_TxtOp single_line_op = ui_single_line_txt_op_from_event(scratch.arena, &n->v, line, *cursor, *mark); //- rjf: invalid single-line op or endpoint units => try multiline - if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint || single_line_op.flags & UI_NavTxtOpFlag_Invalid) + if(n->v.delta_unit == UI_EventDeltaUnit_Whole || single_line_op.flags & UI_TxtOpFlag_Invalid) { U64 line_count = info->lines_count; String8 prev_line = txt_string_from_info_data_line_num(info, data, cursor->line-1); String8 next_line = txt_string_from_info_data_line_num(info, data, cursor->line+1); - Vec2S32 delta = n->v.delta; + Vec2S32 delta = n->v.delta_2s32; //- rjf: wrap lines right - if(n->v.delta_unit != UI_NavDeltaUnit_EndPoint && delta.x > 0 && cursor->column == line.size+1 && cursor->line+1 <= line_count) + if(n->v.delta_unit != UI_EventDeltaUnit_Whole && delta.x > 0 && cursor->column == line.size+1 && cursor->line+1 <= line_count) { cursor->line += 1; cursor->column = 1; @@ -11303,7 +11810,7 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: wrap lines left - if(n->v.delta_unit != UI_NavDeltaUnit_EndPoint && delta.x < 0 && cursor->column == 1 && cursor->line-1 >= 1) + if(n->v.delta_unit != UI_EventDeltaUnit_Whole && delta.x < 0 && cursor->column == 1 && cursor->line-1 >= 1) { cursor->line -= 1; cursor->column = prev_line.size+1; @@ -11313,7 +11820,7 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: movement down (plain) - if(n->v.delta_unit == UI_NavDeltaUnit_Element && delta.y > 0 && cursor->line+1 <= line_count) + if(n->v.delta_unit == UI_EventDeltaUnit_Char && delta.y > 0 && cursor->line+1 <= line_count) { cursor->line += 1; cursor->column = Min(*preferred_column, next_line.size+1); @@ -11322,7 +11829,7 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: movement up (plain) - if(n->v.delta_unit == UI_NavDeltaUnit_Element && delta.y < 0 && cursor->line-1 >= 1) + if(n->v.delta_unit == UI_EventDeltaUnit_Char && delta.y < 0 && cursor->line-1 >= 1) { cursor->line -= 1; cursor->column = Min(*preferred_column, prev_line.size+1); @@ -11331,7 +11838,7 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: movement down (chunk) - if(n->v.delta_unit == UI_NavDeltaUnit_Chunk && delta.y > 0 && cursor->line+1 <= line_count) + if(n->v.delta_unit == UI_EventDeltaUnit_Word && delta.y > 0 && cursor->line+1 <= line_count) { for(S64 line_num = cursor->line+1; line_num <= line_count; line_num += 1) { @@ -11354,7 +11861,7 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: movement up (chunk) - if(n->v.delta_unit == UI_NavDeltaUnit_Chunk && delta.y < 0 && cursor->line-1 >= 1) + if(n->v.delta_unit == UI_EventDeltaUnit_Word && delta.y < 0 && cursor->line-1 >= 1) { for(S64 line_num = cursor->line-1; line_num > 0; line_num -= 1) { @@ -11377,7 +11884,7 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: movement down (page) - if(n->v.delta_unit == UI_NavDeltaUnit_Whole && delta.y > 0) + if(n->v.delta_unit == UI_EventDeltaUnit_Page && delta.y > 0) { cursor->line += line_count_per_page; cursor->column = 1; @@ -11387,7 +11894,7 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: movement up (page) - if(n->v.delta_unit == UI_NavDeltaUnit_Whole && delta.y < 0) + if(n->v.delta_unit == UI_EventDeltaUnit_Page && delta.y < 0) { cursor->line -= line_count_per_page; cursor->column = 1; @@ -11397,7 +11904,7 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: movement to endpoint (+) - if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint && (delta.y > 0 || delta.x > 0)) + if(n->v.delta_unit == UI_EventDeltaUnit_Whole && (delta.y > 0 || delta.x > 0)) { *cursor = txt_pt(line_count, info->lines_count ? dim_1u64(info->lines_ranges[info->lines_count-1])+1 : 1); change = 1; @@ -11405,7 +11912,7 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: movement to endpoint (-) - if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint && (delta.y < 0 || delta.x < 0)) + if(n->v.delta_unit == UI_EventDeltaUnit_Whole && (delta.y < 0 || delta.x < 0)) { *cursor = txt_pt(1, 1); change = 1; @@ -11413,7 +11920,7 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: stick mark to cursor, when we don't want to keep it in the same spot - if(!(n->v.flags & UI_NavActionFlag_KeepMark)) + if(!(n->v.flags & UI_EventFlag_KeepMark)) { *mark = *cursor; } @@ -11430,16 +11937,17 @@ df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx } //- rjf: copy - if(n->v.flags & UI_NavActionFlag_Copy) + if(n->v.flags & UI_EventFlag_Copy) { String8 text = txt_string_from_info_data_txt_rng(info, data, txt_rng(*cursor, *mark)); os_set_clipboard_text(text); + taken = 1; } //- rjf: consume if(taken) { - ui_nav_eat_action_node(nav_actions, n); + ui_eat_event(events, n); } } @@ -11452,26 +11960,29 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, { Temp scratch = scratch_begin(0, 0); B32 change = 0; - UI_NavActionList *nav_actions = ui_nav_actions(); + UI_EventList *events = ui_events(); TXTI_BufferInfo buffer_info = txti_buffer_info_from_handle(scratch.arena, handle); - for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next) + for(UI_EventNode *n = events->first, *next = 0; n != 0; n = next) { next = n->next; B32 taken = 0; - + if(n->v.kind != UI_EventKind_Navigate && n->v.kind != UI_EventKind_Edit) + { + continue; + } String8 line = txti_string_from_handle_line_num(scratch.arena, handle, cursor->line); - UI_NavTxtOp single_line_op = ui_nav_single_line_txt_op_from_action(scratch.arena, n->v, line, *cursor, *mark); + UI_TxtOp single_line_op = ui_single_line_txt_op_from_event(scratch.arena, &n->v, line, *cursor, *mark); //- rjf: invalid single-line op or endpoint units => try multiline - if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint || single_line_op.flags & UI_NavTxtOpFlag_Invalid) + if(n->v.delta_unit == UI_EventDeltaUnit_Whole || single_line_op.flags & UI_TxtOpFlag_Invalid) { U64 line_count = buffer_info.total_line_count; String8 prev_line = txti_string_from_handle_line_num(scratch.arena, handle, cursor->line-1); String8 next_line = txti_string_from_handle_line_num(scratch.arena, handle, cursor->line+1); - Vec2S32 delta = n->v.delta; + Vec2S32 delta = n->v.delta_2s32; //- rjf: wrap lines right - if(n->v.delta_unit != UI_NavDeltaUnit_EndPoint && delta.x > 0 && cursor->column == line.size+1 && cursor->line+1 <= line_count) + if(n->v.delta_unit != UI_EventDeltaUnit_Whole && delta.x > 0 && cursor->column == line.size+1 && cursor->line+1 <= line_count) { cursor->line += 1; cursor->column = 1; @@ -11481,7 +11992,7 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: wrap lines left - if(n->v.delta_unit != UI_NavDeltaUnit_EndPoint && delta.x < 0 && cursor->column == 1 && cursor->line-1 >= 1) + if(n->v.delta_unit != UI_EventDeltaUnit_Whole && delta.x < 0 && cursor->column == 1 && cursor->line-1 >= 1) { cursor->line -= 1; cursor->column = prev_line.size+1; @@ -11491,7 +12002,7 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: movement down (plain) - if(n->v.delta_unit == UI_NavDeltaUnit_Element && delta.y > 0 && cursor->line+1 <= line_count) + if(n->v.delta_unit == UI_EventDeltaUnit_Char && delta.y > 0 && cursor->line+1 <= line_count) { cursor->line += 1; cursor->column = Min(*preferred_column, next_line.size+1); @@ -11500,7 +12011,7 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: movement up (plain) - if(n->v.delta_unit == UI_NavDeltaUnit_Element && delta.y < 0 && cursor->line-1 >= 1) + if(n->v.delta_unit == UI_EventDeltaUnit_Char && delta.y < 0 && cursor->line-1 >= 1) { cursor->line -= 1; cursor->column = Min(*preferred_column, prev_line.size+1); @@ -11509,7 +12020,7 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: movement down (chunk) - if(n->v.delta_unit == UI_NavDeltaUnit_Chunk && delta.y > 0 && cursor->line+1 <= line_count) + if(n->v.delta_unit == UI_EventDeltaUnit_Word && delta.y > 0 && cursor->line+1 <= line_count) { for(S64 line_num = cursor->line+1; line_num <= line_count; line_num += 1) { @@ -11532,7 +12043,7 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: movement up (chunk) - if(n->v.delta_unit == UI_NavDeltaUnit_Chunk && delta.y < 0 && cursor->line-1 >= 1) + if(n->v.delta_unit == UI_EventDeltaUnit_Word && delta.y < 0 && cursor->line-1 >= 1) { for(S64 line_num = cursor->line-1; line_num > 0; line_num -= 1) { @@ -11555,7 +12066,7 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: movement down (page) - if(n->v.delta_unit == UI_NavDeltaUnit_Whole && delta.y > 0) + if(n->v.delta_unit == UI_EventDeltaUnit_Page && delta.y > 0) { cursor->line += line_count_per_page; cursor->column = 1; @@ -11565,7 +12076,7 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: movement up (page) - if(n->v.delta_unit == UI_NavDeltaUnit_Whole && delta.y < 0) + if(n->v.delta_unit == UI_EventDeltaUnit_Page && delta.y < 0) { cursor->line -= line_count_per_page; cursor->column = 1; @@ -11575,7 +12086,7 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: movement to endpoint (+) - if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint && (delta.y > 0 || delta.x > 0)) + if(n->v.delta_unit == UI_EventDeltaUnit_Whole && (delta.y > 0 || delta.x > 0)) { *cursor = txt_pt(line_count, buffer_info.last_line_size); change = 1; @@ -11583,7 +12094,7 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: movement to endpoint (-) - if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint && (delta.y < 0 || delta.x < 0)) + if(n->v.delta_unit == UI_EventDeltaUnit_Whole && (delta.y < 0 || delta.x < 0)) { *cursor = txt_pt(1, 1); change = 1; @@ -11591,7 +12102,7 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: stick mark to cursor, when we don't want to keep it in the same spot - if(!(n->v.flags & UI_NavActionFlag_KeepMark)) + if(!(n->v.flags & UI_EventFlag_KeepMark)) { *mark = *cursor; } @@ -11608,16 +12119,17 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, } //- rjf: copy - if(n->v.flags & UI_NavActionFlag_Copy) + if(n->v.flags & UI_EventFlag_Copy) { String8 text = txti_string_from_handle_txt_rng(scratch.arena, handle, txt_rng(*cursor, *mark)); os_set_clipboard_text(text); + taken = 1; } //- rjf: consume if(taken) { - ui_nav_eat_action_node(nav_actions, n); + ui_eat_event(events, n); } } @@ -11914,16 +12426,16 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx B32 commit = 0; if(!is_focus_active && is_focus_hot) { - 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; - UI_NavAction *action = &n->v; - if(action->flags & UI_NavActionFlag_Copy) + UI_Event *evt = &n->v; + if(evt->flags & UI_EventFlag_Copy) { os_set_clipboard_text(pre_edit_value); } - if(action->flags & UI_NavActionFlag_Delete) + if(evt->flags & UI_EventFlag_Delete) { commit = 1; edit_string_size_out[0] = 0; @@ -11946,17 +12458,17 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx B32 start_editing_via_typing = 0; if(is_focus_hot) { - UI_NavActionList *nav_actions = ui_nav_actions(); - for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + UI_EventList *events = ui_events(); + for(UI_EventNode *n = events->first; n != 0; n = n->next) { - if(n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste) + if(n->v.string.size != 0 || n->v.flags & UI_EventFlag_Paste) { start_editing_via_typing = 1; break; } } } - if(is_focus_hot && os_key_press(ui_events(), ui_window(), 0, OS_Key_F2)) + if(is_focus_hot && ui_slot_press(UI_EventActionSlot_Edit)) { start_editing_via_typing = 1; } @@ -11979,37 +12491,65 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx sig.f |= UI_SignalFlag_Commit; } + //- rjf: determine autocompletion string + String8 autocomplete_hint_string = {0}; + { + UI_EventList *events = ui_events(); + for(UI_EventNode *n = events->first; n != 0; n = n->next) + { + if(n->v.kind == UI_EventKind_AutocompleteHint) + { + autocomplete_hint_string = n->v.string; + } + } + } + //- rjf: take navigation actions for editing B32 changes_made = 0; if(!(flags & DF_LineEditFlag_DisableEdit) && (is_focus_active || focus_started)) { 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: any valid op & autocomplete hint? -> perform autocomplete first, then re-compute op + if(autocomplete_hint_string.size != 0) + { + String8 word_query = df_autocomp_query_word_from_input_string_off(edit_string, cursor->column-1); + U64 word_off = (U64)(word_query.str - edit_string.str); + String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(word_off+1, word_off+1+word_query.size), autocomplete_hint_string); + 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; + *cursor = *mark = txt_pt(1, word_off+1+autocomplete_hint_string.size); + edit_string = str8(edit_buffer, edit_string_size_out[0]); + op = ui_single_line_txt_op_from_event(scratch.arena, &n->v, edit_string, *cursor, *mark); + MemoryZeroStruct(&autocomplete_hint_string); + } // 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); } @@ -12020,7 +12560,7 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx // rjf: consume event { - ui_nav_eat_action_node(nav_actions, n); + ui_eat_event(events, n); changes_made = 1; } } @@ -12088,6 +12628,70 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx ui_set_next_pref_width(ui_px(total_editstr_width+ui_top_font_size()*2, 0.f)); UI_Box *editstr_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTextTrunc, "###editstr"); D_FancyStringList code_fancy_strings = df_fancy_string_list_from_code_string(scratch.arena, 1.f, 0, ui_top_text_color(), edit_string); + if(autocomplete_hint_string.size != 0) + { + String8 query_word = df_autocomp_query_word_from_input_string_off(edit_string, cursor->column-1); + String8 autocomplete_append_string = str8_skip(autocomplete_hint_string, query_word.size); + U64 off = 0; + U64 cursor_off = cursor->column-1; + D_FancyStringNode *prev_n = 0; + for(D_FancyStringNode *n = code_fancy_strings.first; n != 0; n = n->next) + { + if(off <= cursor_off && cursor_off <= off+n->v.string.size) + { + prev_n = n; + break; + } + off += n->v.string.size; + } + { + D_FancyStringNode *autocomp_fstr_n = push_array(scratch.arena, D_FancyStringNode, 1); + D_FancyString *fstr = &autocomp_fstr_n->v; + fstr->font = ui_top_font(); + fstr->string = autocomplete_append_string; + fstr->color = ui_top_text_color(); + fstr->color.w *= 0.5f; + fstr->size = ui_top_font_size(); + autocomp_fstr_n->next = prev_n ? prev_n->next : 0; + if(prev_n != 0) + { + prev_n->next = autocomp_fstr_n; + } + if(prev_n == 0) + { + code_fancy_strings.first = code_fancy_strings.last = autocomp_fstr_n; + } + if(prev_n != 0 && prev_n->next == 0) + { + code_fancy_strings.last = autocomp_fstr_n; + } + code_fancy_strings.node_count += 1; + code_fancy_strings.total_size += autocomplete_hint_string.size; + if(prev_n != 0 && cursor_off - off < prev_n->v.string.size) + { + String8 full_string = prev_n->v.string; + U64 chop_amt = full_string.size - (cursor_off - off); + prev_n->v.string = str8_chop(full_string, chop_amt); + code_fancy_strings.total_size -= chop_amt; + if(chop_amt != 0) + { + String8 post_cursor = str8_skip(full_string, cursor_off - off); + D_FancyStringNode *post_fstr_n = push_array(scratch.arena, D_FancyStringNode, 1); + D_FancyString *post_fstr = &post_fstr_n->v; + MemoryCopyStruct(post_fstr, &prev_n->v); + post_fstr->string = post_cursor; + if(autocomp_fstr_n->next == 0) + { + code_fancy_strings.last = post_fstr_n; + } + post_fstr_n->next = autocomp_fstr_n->next; + autocomp_fstr_n->next = post_fstr_n; + code_fancy_strings.node_count += 1; + code_fancy_strings.total_size += post_cursor.size; + } + } + } + } ui_box_equip_display_fancy_strings(editstr_box, &code_fancy_strings); UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1); draw_data->edited_string = push_str8_copy(ui_build_arena(), edit_string); @@ -12465,6 +13069,7 @@ df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds) os_window_close(ws->os); arena_release(ws->query_cmd_arena); arena_release(ws->hover_eval_arena); + arena_release(ws->autocomp_lister_params_arena); arena_release(ws->arena); SLLStackPush(df_gfx_state->free_window, ws); ws->gen += 1; @@ -13076,6 +13681,31 @@ df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds) df_bind_spec(cmd_spec, pair->binding); } } + + //- rjf: always ensure that the meta controls have bindings + if(src == DF_CfgSrc_User) + { + struct + { + DF_CmdSpec *spec; + OS_Key fallback_key; + } + meta_ctrls[] = + { + { df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Edit), OS_Key_F2 }, + { df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Accept), OS_Key_Return }, + { df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Cancel), OS_Key_Esc }, + }; + for(U64 idx = 0; idx < ArrayCount(meta_ctrls); idx += 1) + { + DF_BindingList bindings = df_bindings_from_spec(scratch.arena, meta_ctrls[idx].spec); + if(bindings.count == 0) + { + DF_Binding binding = {meta_ctrls[idx].fallback_key, 0}; + df_bind_spec(meta_ctrls[idx].spec, binding); + } + } + } }break; //- rjf: writing config changes diff --git a/src/df/gfx/df_gfx.h b/src/df/gfx/df_gfx.h index 425ea56b..a7c1b964 100644 --- a/src/df/gfx/df_gfx.h +++ b/src/df/gfx/df_gfx.h @@ -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 diff --git a/src/df/gfx/df_gfx.mdesk b/src/df/gfx/df_gfx.mdesk index ce18cbd4..c6ef1183 100644 --- a/src/df/gfx/df_gfx.mdesk +++ b/src/df/gfx/df_gfx.mdesk @@ -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)`, diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index 2c438b71..59fee683 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -370,12 +370,12 @@ df_entity_lister_item_array_sort_by_strength__in_place(DF_EntityListerItemArray } //////////////////////////////// -//~ 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) +df_eval_view_key_from_eval_watch_view(DF_WatchViewState *ewv) { DF_EvalViewKey key = df_eval_view_key_make((U64)ewv, df_hash_from_string(str8_struct(&ewv))); return key; @@ -384,7 +384,7 @@ df_eval_view_key_from_eval_watch_view(DF_EvalWatchViewState *ewv) //- rjf: root allocation/deallocation/mutation internal DF_EvalRoot * -df_eval_root_alloc(DF_View *view, DF_EvalWatchViewState *ews) +df_eval_root_alloc(DF_View *view, DF_WatchViewState *ews) { DF_EvalRoot *result = ews->first_free_root; if(result != 0) @@ -404,7 +404,7 @@ df_eval_root_alloc(DF_View *view, DF_EvalWatchViewState *ews) } internal void -df_eval_root_release(DF_EvalWatchViewState *ews, DF_EvalRoot *root) +df_eval_root_release(DF_WatchViewState *ews, DF_EvalRoot *root) { DLLRemove(ews->first_root, ews->last_root, root); SLLStackPush(ews->first_free_root, root); @@ -419,7 +419,7 @@ df_eval_root_equip_string(DF_EvalRoot *root, String8 string) } internal DF_EvalRoot * -df_eval_root_from_string(DF_EvalWatchViewState *ews, String8 string) +df_eval_root_from_string(DF_WatchViewState *ews, String8 string) { DF_EvalRoot *root = 0; for(DF_EvalRoot *r = ews->first_root; r != 0; r = r->next) @@ -435,7 +435,7 @@ 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) +df_eval_root_from_expand_key(DF_WatchViewState *ews, DF_EvalView *eval_view, DF_ExpandKey expand_key) { DF_EvalRoot *root = 0; for(DF_EvalRoot *r = ews->first_root; r != 0; r = r->next) @@ -472,10 +472,78 @@ df_expand_key_from_eval_root(DF_EvalRoot *root) return key; } +//- rjf: watch view points <-> table coordinates + +internal B32 +df_watch_view_point_match(DF_WatchViewPoint a, DF_WatchViewPoint b) +{ + return (a.column_kind == b.column_kind && + df_expand_key_match(a.parent_key, b.parent_key) && + df_expand_key_match(a.key, b.key)); +} + +internal DF_WatchViewPoint +df_watch_view_point_from_tbl(DF_EvalVizBlockList *blocks, Vec2S64 tbl) +{ + DF_WatchViewPoint pt = zero_struct; + pt.column_kind = (DF_WatchViewColumnKind)(tbl.x%DF_WatchViewColumnKind_COUNT); + pt.key = df_key_from_viz_block_list_row_num(blocks, tbl.y); + pt.parent_key = df_parent_key_from_viz_block_list_row_num(blocks, tbl.y); + return pt; +} + +internal Vec2S64 +df_tbl_from_watch_view_point(DF_EvalVizBlockList *blocks, DF_WatchViewPoint pt) +{ + Vec2S64 tbl = {0}; + tbl.x = (S64)pt.column_kind; + tbl.y = df_row_num_from_viz_block_list_key(blocks, pt.key); + return tbl; +} + +//- 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) +{ + String8 result = {0}; + switch(col_kind) + { + default:{}break; + case DF_WatchViewColumnKind_Expr: {result = editable ? row->edit_expr : row->display_expr;}break; + case DF_WatchViewColumnKind_Value: {result = editable ? row->edit_value : row->display_value;}break; + case DF_WatchViewColumnKind_Type: {result = !tg_key_match(row->eval.type_key, tg_key_zero()) ? tg_string_from_key(arena, graph, rdi, row->eval.type_key) : str8_zero();}break; + case DF_WatchViewColumnKind_ViewRule:{result = df_eval_view_rule_from_key(ev, row->key);}break; + } + return result; +} + +//- rjf: table coordinates -> text edit state + +internal DF_WatchViewTextEditState * +df_watch_view_text_edit_state_from_pt(DF_WatchViewState *wv, DF_WatchViewPoint pt) +{ + DF_WatchViewTextEditState *result = &wv->dummy_text_edit_state; + if(wv->text_edit_state_slots_count != 0 && wv->text_editing != 0) + { + U64 hash = df_hash_from_expand_key(pt.key); + U64 slot_idx = hash%wv->text_edit_state_slots_count; + for(DF_WatchViewTextEditState *s = wv->text_edit_state_slots[slot_idx]; s != 0; s = s->pt_hash_next) + { + if(df_watch_view_point_match(pt, s->pt)) + { + result = s; + break; + } + } + } + return result; +} + //- rjf: windowed watch tree visualization (both single-line and multi-line) 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) +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) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -490,7 +558,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF //- rjf: mutable watch fill -> build blocks from top-level mutable root expressions // default: - case DF_EvalWatchViewFillKind_Mutable: + case DF_WatchViewFillKind_Mutable: { for(DF_EvalRoot *root = ews->first_root; root != 0; root = root->next) { @@ -509,7 +577,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF //////////////////////////// //- rjf: registers fill -> build blocks via iterating all registers/aliases as root-level expressions // - case DF_EvalWatchViewFillKind_Registers: + case DF_WatchViewFillKind_Registers: { DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); Architecture arch = df_architecture_from_entity(thread); @@ -547,7 +615,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF //////////////////////////// //- rjf: locals fill -> build blocks via iterating all locals as root-level expressions // - case DF_EvalWatchViewFillKind_Locals: + case DF_WatchViewFillKind_Locals: { U64 num = 1; for(EVAL_String2NumMapNode *n = parse_ctx->locals_map->first; n != 0; n = n->order_next, num += 1) @@ -567,10 +635,10 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF //////////////////////////// //- rjf: debug info table fill -> build split debug info table blocks // - case DF_EvalWatchViewFillKind_Globals: dbgi_target = DBGI_FuzzySearchTarget_GlobalVariables; goto dbgi_table; - case DF_EvalWatchViewFillKind_ThreadLocals: dbgi_target = DBGI_FuzzySearchTarget_ThreadVariables; goto dbgi_table; - case DF_EvalWatchViewFillKind_Types: dbgi_target = DBGI_FuzzySearchTarget_UDTs; goto dbgi_table; - case DF_EvalWatchViewFillKind_Procedures: dbgi_target = DBGI_FuzzySearchTarget_Procedures; goto dbgi_table; + case DF_WatchViewFillKind_Globals: dbgi_target = DBGI_FuzzySearchTarget_GlobalVariables; goto dbgi_table; + case DF_WatchViewFillKind_ThreadLocals: dbgi_target = DBGI_FuzzySearchTarget_ThreadVariables; goto dbgi_table; + case DF_WatchViewFillKind_Types: dbgi_target = DBGI_FuzzySearchTarget_UDTs; goto dbgi_table; + case DF_WatchViewFillKind_Procedures: dbgi_target = DBGI_FuzzySearchTarget_Procedures; goto dbgi_table; dbgi_table:; { //- rjf: unpack context @@ -699,7 +767,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF //- rjf: eval/watch views main hooks internal void -df_eval_watch_view_init(DF_EvalWatchViewState *ewv, DF_View *view, DF_EvalWatchViewFillKind fill_kind) +df_watch_view_init(DF_WatchViewState *ewv, DF_View *view, DF_WatchViewFillKind fill_kind) { if(ewv->initialized == 0) { @@ -709,11 +777,12 @@ df_eval_watch_view_init(DF_EvalWatchViewState *ewv, DF_View *view, DF_EvalWatchV ewv->type_column_pct = 0.15f; ewv->view_rule_column_pct = 0.30f; ewv->fill_kind = fill_kind; + ewv->text_edit_arena = df_view_push_arena_ext(view); } } internal void -df_eval_watch_view_cmds(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalWatchViewState *ewv, DF_CmdList *cmds) +df_watch_view_cmds(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewState *ewv, DF_CmdList *cmds) { for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) { @@ -745,7 +814,7 @@ df_eval_watch_view_cmds(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalWa } 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) +df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewState *ewv, B32 modifiable, U32 default_radix, Rng2F32 rect) { ProfBeginFunction(); DBGI_Scope *scope = dbgi_scope_open(); @@ -755,7 +824,6 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW //- rjf: unpack arguments // F_Tag code_font = df_font_from_slot(DF_FontSlot_Code); - F32 code_font_size = df_font_size_from_slot(ws, DF_FontSlot_Code); DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); @@ -763,6 +831,8 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW DF_EvalViewKey eval_view_key = df_eval_view_key_from_eval_watch_view(ewv); DF_EvalView *eval_view = df_eval_view_from_key(eval_view_key); String8 filter = str8(view->query_buffer, view->query_string_size); + F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); + S64 num_possible_visible_rows = (S64)(dim_2f32(rect).y/row_height_px); ////////////////////////////// //- rjf: process * thread info -> parse_ctx @@ -770,126 +840,636 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(scope, process, thread_ip_vaddr); ////////////////////////////// - //- rjf: state -> macro map + //- rjf: determine autocompletion string // - EVAL_String2ExprMap macro_map = eval_string2expr_map_make(scratch.arena, 256); - for(DF_EvalRoot *root = ewv->first_root; root != 0; root = root->next) + String8 autocomplete_hint_string = {0}; { - String8 root_expr = str8(root->expr_buffer, root->expr_buffer_string_size); - - //- rjf: unpack arguments - DF_Entity *process = thread->parent; - U64 unwind_count = ctrl_ctx.unwind_count; - CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - Architecture arch = df_architecture_from_entity(thread); - U64 reg_size = regs_block_size_from_architecture(arch); - U64 thread_unwind_ip_vaddr = 0; - void *thread_unwind_regs_block = push_array(scratch.arena, U8, reg_size); + UI_EventList *events = ui_events(); + for(UI_EventNode *n = events->first; n != 0; n = n->next) { - U64 idx = 0; - for(CTRL_UnwindFrame *f = unwind.first; f != 0; f = f->next, idx += 1) + if(n->v.kind == UI_EventKind_AutocompleteHint) { - if(idx == unwind_count) - { - thread_unwind_ip_vaddr = f->rip; - thread_unwind_regs_block = f->regs; - break; - } + autocomplete_hint_string = n->v.string; + break; } } - - //- rjf: lex & parse - EVAL_TokenArray tokens = eval_token_array_from_text(scratch.arena, root_expr); - EVAL_ParseResult parse = eval_parse_expr_from_text_tokens(scratch.arena, &parse_ctx, root_expr, &tokens); - EVAL_ErrorList errors = parse.errors; - if(errors.count == 0) - { - eval_push_leaf_ident_exprs_from_expr__in_place(scratch.arena, ¯o_map, parse.expr, &errors); - } } ////////////////////////////// - //- rjf: state -> viz blocks - // - DF_EvalVizBlockList blocks = df_eval_viz_block_list_from_watch_view_state(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, view, ewv); - - ////////////////////////////// - //- rjf: does this eval watch view allow mutation? -> add extra block for editable empty row - // - DF_ExpandKey empty_row_parent_key = df_expand_key_make(max_U64, max_U64); - DF_ExpandKey empty_row_key = df_expand_key_make(df_hash_from_expand_key(empty_row_parent_key), 0); - if(modifiable) - { - DF_EvalVizBlock *b = df_eval_viz_block_begin(scratch.arena, DF_EvalVizBlockKind_Null, empty_row_parent_key, empty_row_key, 0); - b->visual_idx_range = b->semantic_idx_range = r1u64(0, 1); - df_eval_viz_block_end(&blocks, b); - } - - ////////////////////////////// - //- rjf: selection state * blocks -> 2D table coordinates + //- rjf: consume events & perform navigations/edits - calculate state // + EVAL_String2ExprMap macro_map = {0}; + DF_EvalVizBlockList blocks = {0}; + UI_ScrollListRowBlockArray row_blocks = {0}; Vec2S64 cursor_tbl = {0}; Vec2S64 mark_tbl = {0}; - { - cursor_tbl.x = ewv->cursor.column_kind; - cursor_tbl.y = df_row_num_from_viz_block_list_key(&blocks, ewv->cursor.key); - mark_tbl.x = ewv->mark.column_kind; - mark_tbl.y = df_row_num_from_viz_block_list_key(&blocks, ewv->mark.key); - } - - ////////////////////////////// - //- rjf: do start/end editing interaction - // - B32 edit_begin = 0; - B32 edit_begin_or_expand = 0; - B32 edit_commit = 0; - B32 edit_end = 0; - B32 edit_submit = 0; - String8 edit_autocomplete_string = {0}; + Rng2S64 selection_tbl = {0}; UI_Focus(UI_FocusKind_On) { - if(!ewv->input_editing && ui_is_focus_active()) + UI_EventList *events = ui_events(); + B32 state_dirty = 1; + B32 cursor_dirty__tbl = 0; + B32 take_autocomplete = 0; + for(UI_EventNode *event_n = events->first, *next = 0;; event_n = next) { - UI_NavActionList *nav_actions = ui_nav_actions(); - for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + ////////////////////////// + //- rjf: state -> macro map + // + if(state_dirty) { - if(!str8_match(n->v.insertion, str8_lit(" "), 0) && (n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste)) + macro_map = eval_string2expr_map_make(scratch.arena, 256); + for(DF_EvalRoot *root = ewv->first_root; root != 0; root = root->next) { - edit_begin = 1; - break; + String8 root_expr = str8(root->expr_buffer, root->expr_buffer_string_size); + + //- rjf: unpack arguments + DF_Entity *process = thread->parent; + U64 unwind_count = ctrl_ctx.unwind_count; + CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); + Architecture arch = df_architecture_from_entity(thread); + U64 reg_size = regs_block_size_from_architecture(arch); + U64 thread_unwind_ip_vaddr = 0; + void *thread_unwind_regs_block = push_array(scratch.arena, U8, reg_size); + { + U64 idx = 0; + for(CTRL_UnwindFrame *f = unwind.first; f != 0; f = f->next, idx += 1) + { + if(idx == unwind_count) + { + thread_unwind_ip_vaddr = f->rip; + thread_unwind_regs_block = f->regs; + break; + } + } + } + + //- rjf: lex & parse + EVAL_TokenArray tokens = eval_token_array_from_text(scratch.arena, root_expr); + EVAL_ParseResult parse = eval_parse_expr_from_text_tokens(scratch.arena, &parse_ctx, root_expr, &tokens); + EVAL_ErrorList errors = parse.errors; + if(errors.count == 0) + { + eval_push_leaf_ident_exprs_from_expr__in_place(scratch.arena, ¯o_map, parse.expr, &errors); + } } } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_F2)) + + ////////////////////////// + //- rjf: state -> viz blocks + // + if(state_dirty) { - edit_begin = 1; + blocks = df_eval_viz_block_list_from_watch_view_state(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, view, ewv); } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + + ////////////////////////// + //- rjf: does this eval watch view allow mutation? -> add extra block for editable empty row + // + DF_ExpandKey empty_row_parent_key = df_expand_key_make(max_U64, max_U64); + DF_ExpandKey empty_row_key = df_expand_key_make(df_hash_from_expand_key(empty_row_parent_key), 1); + if(state_dirty && modifiable) { - edit_begin_or_expand = 1; + DF_EvalVizBlock *b = df_eval_viz_block_begin(scratch.arena, DF_EvalVizBlockKind_Null, empty_row_parent_key, empty_row_key, 0); + b->visual_idx_range = b->semantic_idx_range = r1u64(0, 1); + df_eval_viz_block_end(&blocks, b); + } + + ////////////////////////// + //- rjf: viz blocks -> ui row blocks + // + { + UI_ScrollListRowBlockChunkList row_block_chunks = {0}; + for(DF_EvalVizBlockNode *n = blocks.first; n != 0; n = n->next) + { + DF_EvalVizBlock *vb = &n->v; + UI_ScrollListRowBlock block = {0}; + block.row_count = dim_1u64(vb->visual_idx_range); + block.item_count = dim_1u64(vb->semantic_idx_range); + ui_scroll_list_row_block_chunk_list_push(scratch.arena, &row_block_chunks, 256, &block); + } + row_blocks = ui_scroll_list_row_block_array_from_chunk_list(scratch.arena, &row_block_chunks); + } + + ////////////////////////// + //- rjf: conclude state update + // + if(state_dirty) + { + state_dirty = 0; + } + + ////////////////////////////// + //- rjf: 2D table coordinates * blocks -> stable cursor state + // + if(cursor_dirty__tbl) + { + cursor_dirty__tbl = 0; + struct + { + DF_WatchViewPoint *pt_state; + Vec2S64 pt_tbl; + } + points[] = + { + {&ewv->cursor, cursor_tbl}, + {&ewv->mark, mark_tbl}, + }; + for(U64 point_idx = 0; point_idx < ArrayCount(points); point_idx += 1) + { + DF_ExpandKey last_key = points[point_idx].pt_state->key; + DF_ExpandKey last_parent_key = points[point_idx].pt_state->parent_key; + points[point_idx].pt_state[0] = df_watch_view_point_from_tbl(&blocks, points[point_idx].pt_tbl); + if(df_expand_key_match(df_expand_key_zero(), points[point_idx].pt_state->key)) + { + points[point_idx].pt_state->key = last_parent_key; + DF_ExpandNode *node = df_expand_node_from_key(&eval_view->expand_tree_table, last_parent_key); + for(DF_ExpandNode *n = node; n != 0; n = n->parent) + { + points[point_idx].pt_state->key = n->key; + if(n->expanded == 0) + { + break; + } + } + } + if(point_idx == 0 && + (!df_expand_key_match(ewv->cursor.key, last_key) || + !df_expand_key_match(ewv->cursor.parent_key, last_parent_key))) + { + ewv->text_editing = 0; + } + } + ewv->next_cursor = ewv->cursor; + ewv->next_mark = ewv->mark; + } + + ////////////////////////// + //- rjf: stable cursor state * blocks -> 2D table coordinates + // + { + cursor_tbl = df_tbl_from_watch_view_point(&blocks, ewv->cursor); + mark_tbl = df_tbl_from_watch_view_point(&blocks, ewv->mark); + selection_tbl = r2s64p(Min(cursor_tbl.x, mark_tbl.x), Min(cursor_tbl.y, mark_tbl.y), + Max(cursor_tbl.x, mark_tbl.x), Max(cursor_tbl.y, mark_tbl.y)); + } + + ////////////////////////////// + //- rjf: apply cursor/mark rugpull change + // + B32 cursor_rugpull = 0; + if(!df_watch_view_point_match(ewv->cursor, ewv->next_cursor)) + { + cursor_rugpull = 1; + ewv->cursor = ewv->next_cursor; + ewv->mark = ewv->next_mark; + } + + ////////////////////////// + //- rjf: grab next event, if any - otherwise exit the loop, as we now have + // the most up-to-date state + // + if(!cursor_rugpull && (event_n == 0 || !ui_is_focus_active())) + { + break; + } + UI_Event dummy_evt = zero_struct; + UI_Event *evt = &dummy_evt; + if(event_n != 0) + { + evt = &event_n->v; + next = event_n->next; + } + B32 taken = 0; + + ////////////////////////// + //- rjf: begin editing on some operations + // + if(!ewv->text_editing && + (evt->kind == UI_EventKind_Text || + evt->flags & UI_EventFlag_Paste || + (evt->kind == UI_EventKind_Press && evt->slot == UI_EventActionSlot_Edit)) && + selection_tbl.min.x == selection_tbl.max.x && + (selection_tbl.min.x != 0 || modifiable)) + { + Vec2S64 selection_dim = dim_2s64(selection_tbl); + ewv->text_editing = 1; + arena_clear(ewv->text_edit_arena); + ewv->text_edit_state_slots_count = u64_up_to_pow2(selection_dim.y+1); + ewv->text_edit_state_slots_count = Max(ewv->text_edit_state_slots_count, 64); + ewv->text_edit_state_slots = push_array(ewv->text_edit_arena, DF_WatchViewTextEditState*, ewv->text_edit_state_slots_count); + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + r1s64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y-1), + ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y-1)+1), &blocks); + DF_EvalVizRow *row = rows.first; + for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y; y += 1, row = row->next) + { + for(S64 x = selection_tbl.min.x; x <= selection_tbl.max.x; x += 1) + { + String8 string = df_string_from_eval_viz_row_column_kind(scratch.arena, eval_view, parse_ctx.type_graph, parse_ctx.rdi, row, (DF_WatchViewColumnKind)x, 1); + string.size = Min(string.size, sizeof(ewv->dummy_text_edit_state.input_buffer)); + DF_WatchViewPoint pt = {(DF_WatchViewColumnKind)x, row->parent_key, row->key}; + U64 hash = df_hash_from_expand_key(pt.key); + U64 slot_idx = hash%ewv->text_edit_state_slots_count; + DF_WatchViewTextEditState *edit_state = push_array(ewv->text_edit_arena, DF_WatchViewTextEditState, 1); + SLLStackPush_N(ewv->text_edit_state_slots[slot_idx], edit_state, pt_hash_next); + edit_state->pt = pt; + edit_state->cursor = txt_pt(1, string.size+1); + edit_state->mark = txt_pt(1, 1); + edit_state->input_size = string.size; + MemoryCopy(edit_state->input_buffer, string.str, string.size); + edit_state->initial_size = string.size; + MemoryCopy(edit_state->initial_buffer, string.str, string.size); + } + } + } + + ////////////////////////// + //- rjf: [table] do cell-granularity expansions + // + if(!ewv->text_editing && evt->slot == UI_EventActionSlot_Accept && selection_tbl.min.x <= 0) + { + taken = 1; + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + r1s64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y-1), + ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y-1)+1), &blocks); + DF_EvalVizRow *row = rows.first; + for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y && row != 0; y += 1, row = row->next) + { + if(row->flags & DF_EvalVizRowFlag_CanExpand) + { + B32 is_expanded = df_expand_key_is_set(&eval_view->expand_tree_table, row->key); + df_expand_set_expansion(eval_view->arena, &eval_view->expand_tree_table, row->parent_key, row->key, !is_expanded); + } + } + } + + ////////////////////////// + //- rjf: [text] apply textual edits + // + if(ewv->text_editing) + { + B32 editing_complete = ((evt->kind == UI_EventKind_Press && (evt->slot == UI_EventActionSlot_Cancel || evt->slot == UI_EventActionSlot_Accept)) || + (evt->kind == UI_EventKind_Navigate && evt->delta_2s32.y != 0) || + cursor_rugpull); + if(editing_complete || + ((evt->kind == UI_EventKind_Edit || + evt->kind == UI_EventKind_Navigate || + evt->kind == UI_EventKind_Text) && + evt->delta_2s32.y == 0)) + { + taken = 1; + for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y; y += 1) + { + for(S64 x = selection_tbl.min.x; x <= selection_tbl.max.x; x += 1) + { + DF_WatchViewPoint pt = df_watch_view_point_from_tbl(&blocks, v2s64(x, y)); + DF_WatchViewTextEditState *edit_state = df_watch_view_text_edit_state_from_pt(ewv, pt); + String8 string = str8(edit_state->input_buffer, edit_state->input_size); + UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); + + // rjf: any valid op & autocomplete hint? -> perform autocomplete first, then re-compute op + if(autocomplete_hint_string.size != 0) + { + take_autocomplete = 1; + String8 word_query = df_autocomp_query_word_from_input_string_off(string, edit_state->cursor.column-1); + U64 word_off = (U64)(word_query.str - string.str); + String8 new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(word_off+1, word_off+1+word_query.size), autocomplete_hint_string); + new_string.size = Min(sizeof(edit_state->input_buffer), new_string.size); + MemoryCopy(edit_state->input_buffer, new_string.str, new_string.size); + edit_state->input_size = new_string.size; + edit_state->cursor = edit_state->mark = txt_pt(1, word_off+1+autocomplete_hint_string.size); + string = str8(edit_state->input_buffer, edit_state->input_size); + op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); + } + + // rjf: cancel? -> revert to initial string + if(editing_complete && evt->slot == UI_EventActionSlot_Cancel) + { + string = str8(edit_state->initial_buffer, edit_state->initial_size); + } + + // rjf: obtain edited string + String8 new_string = string; + if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0) + { + new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(op.range.min.column, op.range.max.column), op.replace); + } + + // rjf: commit to edit state + new_string.size = Min(new_string.size, sizeof(edit_state->input_buffer)); + MemoryCopy(edit_state->input_buffer, new_string.str, new_string.size); + edit_state->input_size = new_string.size; + edit_state->cursor = op.cursor; + edit_state->mark = op.mark; + + // rjf: commit edited cell string + Vec2S64 tbl = v2s64(x, y); + switch((DF_WatchViewColumnKind)x) + { + default:{}break; + case DF_WatchViewColumnKind_Expr: + { + DF_WatchViewPoint pt = df_watch_view_point_from_tbl(&blocks, tbl); + DF_EvalRoot *root = df_eval_root_from_expand_key(ewv, eval_view, pt.key); + if(root != 0) + { + df_eval_root_equip_string(root, new_string); + state_dirty = 1; + } + else if(editing_complete && new_string.size != 0 && df_expand_key_match(pt.key, empty_row_key)) + { + root = df_eval_root_alloc(view, ewv); + df_eval_root_equip_string(root, new_string); + DF_ExpandKey key = df_expand_key_from_eval_root(root); + df_eval_view_set_key_rule(eval_view, key, str8_zero()); + state_dirty = 1; + } + }break; + case DF_WatchViewColumnKind_Value: + if(editing_complete && evt->slot != UI_EventActionSlot_Cancel) + { + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + r1s64(ui_scroll_list_row_from_item(&row_blocks, y-1), + ui_scroll_list_row_from_item(&row_blocks, y-1)+1), &blocks); + B32 success = 0; + if(rows.first != 0) + { + DF_Eval write_eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, new_string); + success = df_commit_eval_value(parse_ctx.type_graph, parse_ctx.rdi, &ctrl_ctx, rows.first->eval, write_eval); + } + if(!success) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.string = str8_lit("Could not commit value successfully."); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + }break; + case DF_WatchViewColumnKind_Type:{}break; + case DF_WatchViewColumnKind_ViewRule: + if(editing_complete) + { + DF_WatchViewPoint pt = df_watch_view_point_from_tbl(&blocks, tbl); + df_eval_view_set_key_rule(eval_view, pt.key, new_string); + state_dirty = 1; + }break; + } + } + } + } + if(editing_complete) + { + ewv->text_editing = 0; + } + } + + ////////////////////////// + //- rjf: [table] do cell-granularity copies + // + if(!ewv->text_editing && evt->flags & UI_EventFlag_Copy) + { + taken = 1; + String8List strs = {0}; + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + r1s64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y-1), + ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y-1)+1), &blocks); + DF_EvalVizRow *row = rows.first; + for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y && row != 0; y += 1, row = row->next) + { + for(S64 x = selection_tbl.min.x; x <= selection_tbl.max.x; x += 1) + { + String8 cell_string = df_string_from_eval_viz_row_column_kind(scratch.arena, eval_view, parse_ctx.type_graph, parse_ctx.rdi, row, (DF_WatchViewColumnKind)x, 0); + cell_string = str8_skip_chop_whitespace(cell_string); + U64 comma_pos = str8_find_needle(cell_string, 0, str8_lit(","), 0); + str8_list_pushf(scratch.arena, &strs, "%s%S%s%s", + comma_pos < cell_string.size ? "\"" : "", + cell_string, + comma_pos < cell_string.size ? "\"" : "", + x+1 <= selection_tbl.max.x ? "," : ""); + } + if(y+1 <= selection_tbl.max.y) + { + str8_list_push(scratch.arena, &strs, str8_lit("\n")); + } + } + String8 string = str8_list_join(scratch.arena, &strs, 0); + os_set_clipboard_text(string); + } + + ////////////////////////// + //- rjf: [table] do cell-granularity deletions + // + if(!ewv->text_editing && evt->flags & UI_EventFlag_Delete) + { + taken = 1; + state_dirty = 1; + for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y; y += 1) + { + DF_WatchViewPoint pt = df_watch_view_point_from_tbl(&blocks, v2s64(0, y)); + + // rjf: row deletions + if(selection_tbl.min.x <= 0) + { + DF_EvalRoot *root = df_eval_root_from_expand_key(ewv, eval_view, pt.key); + if(root != 0) + { + DF_ExpandKey new_cursor_key = empty_row_key; + DF_ExpandKey new_cursor_parent_key = empty_row_parent_key; + if((evt->delta_2s32.x < 0 || evt->delta_2s32.y < 0) && root->prev != 0) + { + new_cursor_key = df_expand_key_from_eval_root(root->prev); + new_cursor_parent_key = df_parent_expand_key_from_eval_root(root->prev); + } + else if(root->next != 0) + { + new_cursor_key = df_expand_key_from_eval_root(root->next); + new_cursor_parent_key = df_parent_expand_key_from_eval_root(root->next); + } + DF_WatchViewPoint new_cursor_pt = {DF_WatchViewColumnKind_Expr, new_cursor_parent_key, new_cursor_key}; + df_eval_root_release(ewv, root); + ewv->cursor = ewv->mark = ewv->next_cursor = ewv->next_mark = new_cursor_pt; + } + } + + // rjf: view rule deletions + else if(selection_tbl.min.x <= DF_WatchViewColumnKind_ViewRule && DF_WatchViewColumnKind_ViewRule <= selection_tbl.max.x) + { + df_eval_view_set_key_rule(eval_view, pt.key, str8_zero()); + } + } + } + + ////////////////////////// + //- rjf: [table] apply deltas to cursor & mark + // + if(!ewv->text_editing && !(evt->flags & UI_EventFlag_Delete) && !(evt->flags & UI_EventFlag_Reorder)) + { + B32 cursor_tbl_min_is_empty_selection[Axis2_COUNT] = {0, 1}; + Rng2S64 cursor_tbl_range = r2s64(v2s64(0, 0), v2s64(3, blocks.total_semantic_row_count)); + Rng1S64 item_range = r1s64(0, 1 + blocks.total_visual_row_count); + Vec2S32 delta = evt->delta_2s32; + if(evt->flags & UI_EventFlag_PickSelectSide && !MemoryMatchStruct(&selection_tbl.min, &selection_tbl.max)) + { + if(delta.x > 0 || delta.y > 0) + { + cursor_tbl.x = selection_tbl.max.x; + cursor_tbl.y = selection_tbl.max.y; + } + else if(delta.x < 0 || delta.y < 0) + { + cursor_tbl.x = selection_tbl.min.x; + cursor_tbl.y = selection_tbl.min.y; + } + } + if(evt->flags & UI_EventFlag_ZeroDeltaOnSelect && !MemoryMatchStruct(&selection_tbl.min, &selection_tbl.max)) + { + MemoryZeroStruct(&delta); + } + B32 moved = 1; + switch(evt->delta_unit) + { + default:{moved = 0;}break; + case UI_EventDeltaUnit_Char: + { + for(EachEnumVal(Axis2, axis)) + { + cursor_tbl.v[axis] += delta.v[axis]; + if(cursor_tbl.v[axis] < cursor_tbl_range.min.v[axis]) + { + cursor_tbl.v[axis] = cursor_tbl_range.max.v[axis]; + } + if(cursor_tbl.v[axis] > cursor_tbl_range.max.v[axis]) + { + cursor_tbl.v[axis] = cursor_tbl_range.min.v[axis]; + } + cursor_tbl.v[axis] = clamp_1s64(r1s64(cursor_tbl_range.min.v[axis], cursor_tbl_range.max.v[axis]), cursor_tbl.v[axis]); + } + }break; + case UI_EventDeltaUnit_Word: + case UI_EventDeltaUnit_Line: + case UI_EventDeltaUnit_Page: + { + cursor_tbl.x = (delta.x>0 ? (cursor_tbl_range.max.x) : + delta.x<0 ? (cursor_tbl_range.min.x + !!cursor_tbl_min_is_empty_selection[Axis2_X]) : + cursor_tbl.x); + cursor_tbl.y += ((delta.y>0 ? +(num_possible_visible_rows-3) : + delta.y<0 ? -(num_possible_visible_rows-3) : + 0)); + cursor_tbl.y = clamp_1s64(r1s64(cursor_tbl_range.min.y + !!cursor_tbl_min_is_empty_selection[Axis2_Y], + cursor_tbl_range.max.y), + cursor_tbl.y); + }break; + case UI_EventDeltaUnit_Whole: + { + for(EachEnumVal(Axis2, axis)) + { + cursor_tbl.v[axis] = (delta.v[axis]>0 ? cursor_tbl_range.max.v[axis] : delta.v[axis]<0 ? cursor_tbl_range.min.v[axis] + !!cursor_tbl_min_is_empty_selection[axis] : cursor_tbl.v[axis]); + } + }break; + } + if(moved) + { + taken = 1; + cursor_dirty__tbl = 1; + { + Rng1S64 scroll_row_idx_range = r1s64(item_range.min, ClampBot(item_range.min, item_range.max-1)); + S64 cursor_item_idx = cursor_tbl.y-1; + if(item_range.min <= cursor_item_idx && cursor_item_idx <= item_range.max) + { + UI_ScrollPt *scroll_pt = &view->scroll_pos.y; + + //- rjf: compute visible row range + Rng1S64 visible_row_range = r1s64(scroll_pt->idx + 0 - !!(scroll_pt->off < 0), + scroll_pt->idx + 0 + num_possible_visible_rows + 1); + + //- rjf: compute cursor row range from cursor item + Rng1S64 cursor_visibility_row_range = {0}; + if(row_blocks.count == 0) + { + cursor_visibility_row_range = r1s64(cursor_item_idx-1, cursor_item_idx+3); + } + else + { + cursor_visibility_row_range.min = (S64)ui_scroll_list_row_from_item(&row_blocks, (U64)cursor_item_idx); + cursor_visibility_row_range.max = cursor_visibility_row_range.min + 4; + } + + //- rjf: compute deltas & apply + S64 min_delta = Min(0, cursor_visibility_row_range.min-visible_row_range.min); + S64 max_delta = Max(0, cursor_visibility_row_range.max-visible_row_range.max); + S64 new_idx = scroll_pt->idx+min_delta+max_delta; + new_idx = clamp_1s64(scroll_row_idx_range, new_idx); + ui_scroll_pt_target_idx(scroll_pt, new_idx); + } + } + + } + } + + ////////////////////////// + //- rjf: [table] stick table mark to cursor if needed + // + if(!ewv->text_editing) + { + if(taken && !(evt->flags & UI_EventFlag_KeepMark)) + { + mark_tbl = cursor_tbl; + } + } + + ////////////////////////// + //- rjf: [table] do cell-granularity reorders + // + if(!ewv->text_editing && evt->flags & UI_EventFlag_Reorder) + { + taken = 1; + DF_ExpandKey first_root_key = df_key_from_viz_block_list_row_num(&blocks, selection_tbl.min.y); + DF_EvalRoot *first_root = df_eval_root_from_expand_key(ewv, eval_view, first_root_key); + DF_EvalRoot *last_root = first_root; + if(first_root != 0) + { + for(S64 y = selection_tbl.min.y+1; y <= selection_tbl.max.y; y += 1) + { + DF_ExpandKey key = df_key_from_viz_block_list_row_num(&blocks, y); + DF_EvalRoot *new_root = df_eval_root_from_expand_key(ewv, eval_view, key); + if(new_root != 0) + { + last_root = new_root; + } + } + } + if(evt->delta_2s32.y < 0 && first_root != 0 && first_root->prev != 0) + { + state_dirty = 1; + DF_EvalRoot *reordered = first_root->prev; + DLLRemove(ewv->first_root, ewv->last_root, reordered); + DLLInsert(ewv->first_root, ewv->last_root, last_root, reordered); + } + if(evt->delta_2s32.y > 0 && last_root != 0 && last_root->next != 0) + { + state_dirty = 1; + DF_EvalRoot *prev_child = first_root->prev; + DF_EvalRoot *reordered = last_root->next; + DLLRemove(ewv->first_root, ewv->last_root, reordered); + DLLInsert(ewv->first_root, ewv->last_root, prev_child, reordered); + } + } + + ////////////////////////// + //- rjf: consume event, if taken + // + if(taken && evt != &dummy_evt) + { + ui_eat_event(events, event_n); } } - if(ewv->input_editing && ui_is_focus_active()) + if(take_autocomplete) { - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + for(UI_EventNode *n = events->first; n != 0; n = n->next) { - edit_end = 1; - edit_commit = 0; - } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) - { - edit_end = 1; - edit_commit = 1; - edit_submit = 1; - } - UI_NavActionList *nav_actions = ui_nav_actions(); - for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) - { - if(n->v.flags & UI_NavActionFlag_ReplaceAndCommit) + if(n->v.kind == UI_EventKind_AutocompleteHint) { - edit_commit = 1; - edit_end = 1; - edit_autocomplete_string = n->v.insertion; - ui_nav_eat_action_node(nav_actions, n); + ui_eat_event(events, n); break; } } @@ -907,8 +1487,6 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW &ewv->view_rule_column_pct, }; B32 pressed = 0; - DF_EvalVizRow *commit_row = 0; - Vec2S64 next_cursor_tbl = cursor_tbl; Rng1S64 visible_row_rng = {0}; UI_ScrollListParams scroll_list_params = {0}; { @@ -936,12 +1514,14 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, ewv->input_editing ? 0 : &cursor_tbl, &visible_row_rng, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, + 0, + 0, + &visible_row_rng, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) UI_TableF(ArrayCount(col_pcts), col_pcts, "table_header") { - next_cursor_tbl = cursor_tbl; - //- rjf: build table header if(visible_row_rng.min == 0) UI_TableVector UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) { @@ -951,7 +1531,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW UI_TableCell if(df_help_label(str8_lit("View Rule"))) UI_Tooltip { F32 max_width = ui_top_font_size()*35; - ui_label_multiline(max_width, str8_lit("View rules are used to tweak the way evaluated expressions are visualized. Multiple rules can be specified on each row. They are specified in a key:(value) form.")); + ui_label_multiline(max_width, str8_lit("View rules are used to tweak the way evaluated expressions are visualized. Multiple rules can be specified on each row. They are specified in a key:(value) form. Some examples follow:")); ui_spacer(ui_em(1.5f, 1)); UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_PlainText)) ui_labelf("array:(N)"); ui_label_multiline(max_width, str8_lit("Specifies that a pointer points to N elements, rather than only 1.")); @@ -986,7 +1566,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW //- rjf: viz blocks -> rows DF_EvalVizWindowedRowList rows = {0}; { - rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, code_font_size, r1s64(visible_row_rng.min-1, visible_row_rng.max), &blocks); + rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(visible_row_rng.min-1, visible_row_rng.max), &blocks); } //- rjf: build table @@ -996,10 +1576,11 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW U64 semantic_idx = rows.count_before_semantic; for(DF_EvalVizRow *row = rows.first; row != 0; row = row->next, semantic_idx += 1) { + //- rjf: unpack row info U64 row_hash = df_hash_from_expand_key(row->key); U64 expr_hash = df_hash_from_string(row->display_expr); df_expand_tree_table_animate(&eval_view->expand_tree_table, df_dt()); - B32 row_selected = ((semantic_idx+1) == cursor_tbl.y); + B32 row_selected = (selection_tbl.min.y <= (semantic_idx+1) && (semantic_idx+1) <= selection_tbl.max.y); B32 row_expanded = df_expand_key_is_set(&eval_view->expand_tree_table, row->key); //- rjf: determine if row's data is fresh and/or bad @@ -1028,15 +1609,11 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW }break; } - //- rjf: store root edit commit info - if(row_selected) - { - commit_row = row; - } - //- rjf: build canvas row if(row->flags & DF_EvalVizRowFlag_Canvas) UI_FocusHot(row_selected ? UI_FocusKind_On : UI_FocusKind_Off) ProfScope("canvas row") { + DF_WatchViewPoint pt = {DF_WatchViewColumnKind_Expr, row->parent_key, row->key}; + //- rjf: build ui_set_next_flags(disabled_flags); ui_set_next_pref_width(ui_pct(1, 0)); @@ -1065,13 +1642,12 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW //- rjf: press -> focus if(ui_pressed(sig)) { - edit_commit = edit_commit || (!row_selected && ewv->input_editing); - next_cursor_tbl = v2s64(DF_EvalWatchViewColumnKind_Expr, (semantic_idx+1)); + ewv->next_cursor = ewv->next_mark = pt; pressed = 1; } - //- rjf: double clicked or keyboard clicked -> open dedicated tab - if(ui_double_clicked(sig) || sig.f & UI_SignalFlag_KeyboardPressed) + //- rjf: double clicked -> open dedicated tab + if(ui_double_clicked(sig)) { DF_CfgNode *cfg = df_cfg_tree_copy(scratch.arena, row->expand_ui_rule_node); DF_CfgNode *cfg_root = push_array(scratch.arena, DF_CfgNode, 1); @@ -1104,7 +1680,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW { ui_set_next_flags(disabled_flags); } - UI_NamedTableVectorF("row_%I64x_%I64x_%I64x", row_hash, expr_hash, ewv->root_count) + UI_NamedTableVectorF("row_%I64x_%I64x", row_hash, ewv->root_count) { //- rjf: draw start of cache lines in expansions if((row->eval.mode == EVAL_EvalMode_Addr || row->eval.mode == EVAL_EvalMode_NULL) && @@ -1142,19 +1718,11 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW //- rjf: expression ProfScope("expr") { - B32 cell_selected = (row_selected && cursor_tbl.x == DF_EvalWatchViewColumnKind_Expr); + DF_WatchViewPoint pt = {DF_WatchViewColumnKind_Expr, row->parent_key, row->key}; + DF_WatchViewTextEditState *edit_state = df_watch_view_text_edit_state_from_pt(ewv, pt); + B32 cell_selected = (row_selected && selection_tbl.min.x <= pt.column_kind && pt.column_kind <= selection_tbl.max.x); B32 can_edit_expr = !(row->depth > 0 || modifiable == 0); - // rjf: begin editing - if(cell_selected && (edit_begin || (edit_begin_or_expand && !(row->flags & DF_EvalVizRowFlag_CanExpand))) && can_edit_expr) - { - ewv->input_editing = 1; - ewv->input_size = Min(sizeof(ewv->input_buffer), row->display_expr.size); - MemoryCopy(ewv->input_buffer, row->display_expr.str, ewv->input_size); - ewv->input_cursor = txt_pt(1, 1+ewv->input_size); - ewv->input_mark = txt_pt(1, 1); - } - // rjf: build UI_Signal sig = {0}; B32 next_expanded = row_expanded; @@ -1165,7 +1733,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW } UI_TableCell UI_FocusHot(cell_selected ? UI_FocusKind_On : UI_FocusKind_Off) - UI_FocusActive((cell_selected && ewv->input_editing) ? UI_FocusKind_On : UI_FocusKind_Off) + UI_FocusActive((cell_selected && ewv->text_editing) ? UI_FocusKind_On : UI_FocusKind_Off) { B32 expr_editing_active = ui_is_focus_active(); B32 is_inherited = (row->inherited_type_key_chain.count != 0); @@ -1192,11 +1760,10 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW DF_LineEditFlag_ExpanderSpace*(row->depth!=0)), row->depth, filter.size ? &matches : 0, - &ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, &next_expanded, + &edit_state->cursor, &edit_state->mark, edit_state->input_buffer, sizeof(edit_state->input_buffer), &edit_state->input_size, &next_expanded, row->display_expr, "###row_%I64x", row_hash); } - edit_commit = edit_commit || ui_committed(sig); if(is_inherited && ui_hovering(sig)) UI_Tooltip { String8List inheritance_chain_type_names = {0}; @@ -1264,35 +1831,31 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW scratch_end(scratch); } - if(expr_editing_active && !edit_end) + + // rjf: autocomplete lister + if(expr_editing_active && + selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y && + txt_pt_match(edit_state->cursor, edit_state->mark)) { - df_set_autocomp_lister_query(ws, sig.box->key, ctrl_ctx, DF_AutoCompListerFlag_Locals, str8(ewv->input_buffer, ewv->input_size)); + String8 input = str8(edit_state->input_buffer, edit_state->input_size); + DF_AutoCompListerParams params = {DF_AutoCompListerFlag_Locals}; + df_set_autocomp_lister_query(ws, sig.box->key, ctrl_ctx, ¶ms, input, edit_state->cursor.column-1); } } // rjf: press -> commit if editing & select if(ui_pressed(sig)) { - edit_commit = edit_commit || (!cell_selected && ewv->input_editing); - next_cursor_tbl = v2s64(DF_EvalWatchViewColumnKind_Expr, (semantic_idx+1)); + ewv->next_cursor = ewv->next_mark = pt; pressed = 1; } - // rjf: keyboard-click & expandable -> expand - if(cell_selected && edit_begin_or_expand && row->flags & DF_EvalVizRowFlag_CanExpand) - { - next_expanded ^= 1; - } - // rjf: double-click -> start editing - if(ui_double_clicked(sig) && !ewv->input_editing && can_edit_expr) + if(ui_double_clicked(sig) && can_edit_expr) { ui_kill_action(); - ewv->input_editing = 1; - ewv->input_size = Min(sizeof(ewv->input_buffer), row->display_expr.size); - MemoryCopy(ewv->input_buffer, row->display_expr.str, ewv->input_size); - ewv->input_cursor = txt_pt(1, 1+ewv->input_size); - ewv->input_mark = txt_pt(1, 1); + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Edit)); } // rjf: commit expansion state @@ -1305,22 +1868,14 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW //- rjf: value ProfScope("value") { - B32 cell_selected = (row_selected && cursor_tbl.x == DF_EvalWatchViewColumnKind_Value); + DF_WatchViewPoint pt = {DF_WatchViewColumnKind_Value, row->parent_key, row->key}; + DF_WatchViewTextEditState *edit_state = df_watch_view_text_edit_state_from_pt(ewv, pt); + B32 cell_selected = (row_selected && selection_tbl.min.x <= pt.column_kind && pt.column_kind <= selection_tbl.max.x); B32 value_is_error = (row->eval.errors.count != 0); B32 value_is_hook = (!value_is_error && row->value_ui_rule_spec != &df_g_nil_gfx_view_rule_spec && row->value_ui_rule_spec != 0); B32 value_is_complex = (!value_is_error && !value_is_hook && !(row->flags & DF_EvalVizRowFlag_CanEditValue)); B32 value_is_simple = (!value_is_error && !value_is_hook && (row->flags & DF_EvalVizRowFlag_CanEditValue)); - // rjf: begin editing - if(cell_selected && (edit_begin || edit_begin_or_expand) && value_is_simple) - { - ewv->input_editing = 1; - ewv->input_size = Min(sizeof(ewv->input_buffer), row->edit_value.size); - MemoryCopy(ewv->input_buffer, row->edit_value.str, ewv->input_size); - ewv->input_cursor = txt_pt(1, 1+ewv->input_size); - ewv->input_mark = txt_pt(1, 1); - } - // rjf: build UI_Signal sig = {0}; if(row_is_bad) @@ -1330,7 +1885,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW } UI_TableCell UI_Font(code_font) UI_FocusHot(cell_selected ? UI_FocusKind_On : UI_FocusKind_Off) - UI_FocusActive((cell_selected && ewv->input_editing) ? UI_FocusKind_On : UI_FocusKind_Off) + UI_FocusActive((cell_selected && ewv->text_editing) ? UI_FocusKind_On : UI_FocusKind_Off) { // rjf: errors? -> show errors if(value_is_error) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) UI_Font(df_font_from_slot(DF_FontSlot_Main)) @@ -1370,8 +1925,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW // rjf: simple values (editable) if(value_is_simple) { - sig = df_line_editf(DF_LineEditFlag_CodeContents|DF_LineEditFlag_NoBackground, 0, 0, &ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, 0, row->display_value, "%S###val_%I64x", row->display_value, row_hash); - edit_commit = (edit_commit || ui_committed(sig)); + sig = df_line_editf(DF_LineEditFlag_CodeContents|DF_LineEditFlag_NoBackground, 0, 0, &edit_state->cursor, &edit_state->mark, edit_state->input_buffer, sizeof(edit_state->input_buffer), &edit_state->input_size, 0, row->display_value, "%S###val_%I64x", row->display_value, row_hash); } } @@ -1384,30 +1938,28 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW // rjf: press -> focus & commit if editing & not selected if(ui_pressed(sig)) { + ewv->next_cursor = ewv->next_mark = pt; pressed = 1; - edit_commit = edit_commit || (ewv->input_editing && !cell_selected); - next_cursor_tbl = v2s64(DF_EvalWatchViewColumnKind_Value, (semantic_idx+1)); } // rjf: double-click -> start editing if(ui_double_clicked(sig) && value_is_simple) { ui_kill_action(); - ewv->input_editing = 1; - ewv->input_size = Min(sizeof(ewv->input_buffer), row->edit_value.size); - MemoryCopy(ewv->input_buffer, row->edit_value.str, ewv->input_size); - ewv->input_cursor = txt_pt(1, 1+ewv->input_size); - ewv->input_mark = txt_pt(1, 1); + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Edit)); } } //- rjf: type ProfScope("type") { - B32 cell_selected = (row_selected && cursor_tbl.x == DF_EvalWatchViewColumnKind_Type); + DF_WatchViewPoint pt = {DF_WatchViewColumnKind_Type, row->parent_key, row->key}; + DF_WatchViewTextEditState *edit_state = df_watch_view_text_edit_state_from_pt(ewv, pt); + B32 cell_selected = (row_selected && selection_tbl.min.x <= pt.column_kind && pt.column_kind <= selection_tbl.max.x); UI_TableCell UI_Font(code_font) UI_FocusHot(cell_selected ? UI_FocusKind_On : UI_FocusKind_Off) - UI_FocusActive((cell_selected && ewv->input_editing) ? UI_FocusKind_On : UI_FocusKind_Off) + UI_FocusActive((cell_selected && ewv->text_editing) ? UI_FocusKind_On : UI_FocusKind_Off) { TG_Key key = row->eval.type_key; String8 string = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdi, key); @@ -1420,9 +1972,8 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW UI_Signal sig = ui_signal_from_box(box); if(ui_pressed(sig)) { + ewv->next_cursor = ewv->next_mark = pt; pressed = 1; - edit_commit = edit_commit || (ewv->input_editing && !cell_selected); - next_cursor_tbl = v2s64(DF_EvalWatchViewColumnKind_Type, (semantic_idx+1)); } } } @@ -1430,54 +1981,49 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW //- rjf: view rule ProfScope("view rule") { - B32 cell_selected = (row_selected && cursor_tbl.x == DF_EvalWatchViewColumnKind_ViewRule); + DF_WatchViewPoint pt = {DF_WatchViewColumnKind_ViewRule, row->parent_key, row->key}; + DF_WatchViewTextEditState *edit_state = df_watch_view_text_edit_state_from_pt(ewv, pt); + B32 cell_selected = (row_selected && selection_tbl.min.x <= pt.column_kind && pt.column_kind <= selection_tbl.max.x); String8 view_rule = df_eval_view_rule_from_key(eval_view, row->key); - // rjf: begin editing - if(cell_selected && (edit_begin || edit_begin_or_expand)) - { - ewv->input_editing = 1; - ewv->input_size = Min(sizeof(ewv->input_buffer), view_rule.size); - MemoryCopy(ewv->input_buffer, view_rule.str, ewv->input_size); - ewv->input_cursor = txt_pt(1, 1+ewv->input_size); - ewv->input_mark = txt_pt(1, 1); - } - // rjf: build UI_Signal sig = {0}; B32 rule_editing_active = 0; UI_TableCell UI_Font(code_font) UI_FocusHot(cell_selected ? UI_FocusKind_On : UI_FocusKind_Off) - UI_FocusActive((cell_selected && ewv->input_editing) ? UI_FocusKind_On : UI_FocusKind_Off) + UI_FocusActive((cell_selected && ewv->text_editing) ? UI_FocusKind_On : UI_FocusKind_Off) { rule_editing_active = ui_is_focus_active(); - sig = df_line_editf(DF_LineEditFlag_CodeContents|DF_LineEditFlag_NoBackground, 0, 0, &ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, 0, view_rule, "###view_rule_%I64x", row_hash); - edit_commit = edit_commit || ui_committed(sig); + sig = df_line_editf(DF_LineEditFlag_CodeContents|DF_LineEditFlag_NoBackground, 0, 0, &edit_state->cursor, &edit_state->mark, edit_state->input_buffer, sizeof(edit_state->input_buffer), &edit_state->input_size, 0, view_rule, "###view_rule_%I64x", row_hash); } // rjf: press -> commit if not selected, select this cell if(ui_pressed(sig)) { + ewv->next_cursor = ewv->next_mark = pt; pressed = 1; - edit_commit = edit_commit || (ewv->input_editing && !cell_selected); - next_cursor_tbl = v2s64(DF_EvalWatchViewColumnKind_ViewRule, (semantic_idx+1)); - } - - // rjf: double-click -> begin editing - if(ui_double_clicked(sig) && !ewv->input_editing) - { - ui_kill_action(); - ewv->input_editing = 1; - ewv->input_size = Min(sizeof(ewv->input_buffer), view_rule.size); - MemoryCopy(ewv->input_buffer, view_rule.str, ewv->input_size); - ewv->input_cursor = txt_pt(1, 1+ewv->input_size); - ewv->input_mark = txt_pt(1, 1); } // rjf: autocomplete lister - if(rule_editing_active && !edit_end) + if(rule_editing_active && + selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y && + txt_pt_match(edit_state->cursor, edit_state->mark)) { - df_set_autocomp_lister_query(ws, sig.box->key, ctrl_ctx, DF_AutoCompListerFlag_ViewRules, str8(ewv->input_buffer, ewv->input_size)); + String8 input = str8(edit_state->input_buffer, edit_state->input_size); + DF_AutoCompListerParams params = df_view_rule_autocomp_lister_params_from_input_cursor(scratch.arena, input, edit_state->cursor.column-1); + if(params.flags == 0) + { + params.flags = DF_AutoCompListerFlag_ViewRules; + } + df_set_autocomp_lister_query(ws, sig.box->key, ctrl_ctx, ¶ms, input, edit_state->cursor.column-1); + } + + // rjf: double-click -> begin editing + if(ui_double_clicked(sig) && !ewv->text_editing) + { + ui_kill_action(); + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Edit)); } } } @@ -1495,150 +2041,6 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } - ////////////////////////////// - //- rjf: commit edits - // - { - DF_EvalWatchViewColumnKind commit_column = (DF_EvalWatchViewColumnKind)cursor_tbl.x; - cursor_tbl = next_cursor_tbl; - if(commit_row != 0 && edit_commit) - { - ewv->input_editing = 0; - String8 commit_string = str8(ewv->input_buffer, ewv->input_size); - if(edit_autocomplete_string.size != 0) - { - commit_string = edit_autocomplete_string; - } - switch(commit_column) - { - default:break; - - //- rjf: expression commits - case DF_EvalWatchViewColumnKind_Expr: if(modifiable) - { - if(commit_string.size == 0) - { - DF_EvalRoot *root = df_eval_root_from_expand_key(ewv, eval_view, commit_row->key); - if(root != 0) - { - df_eval_root_release(ewv, root); - } - } - else - { - DF_EvalRoot *root = df_eval_root_from_expand_key(ewv, eval_view, commit_row->key); - if(!root && df_expand_key_match(commit_row->key, empty_row_key)) - { - root = df_eval_root_alloc(view, ewv); - DF_ExpandKey parent_key = df_parent_expand_key_from_eval_root(root); - DF_ExpandKey key = df_expand_key_from_eval_root(root); - df_expand_set_expansion(eval_view->arena, &eval_view->expand_tree_table, parent_key, key, 0); - df_eval_view_set_key_rule(eval_view, key, str8_lit("")); - } - if(root != 0) - { - df_eval_root_equip_string(root, commit_string); - } - } - }break; - - //- rjf: value commits - case DF_EvalWatchViewColumnKind_Value: - { - Temp scratch = scratch_begin(0, 0); - DF_Eval write_eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, commit_string); - B32 success = df_commit_eval_value(parse_ctx.type_graph, parse_ctx.rdi, &ctrl_ctx, commit_row->eval, write_eval); - if(success == 0) - { - DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); - params.string = str8_lit("Could not commit value successfully."); - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); - } - scratch_end(scratch); - }break; - - //- rjf: type commits - case DF_EvalWatchViewColumnKind_Type: - { - }break; - - //- rjf: view rule commits - case DF_EvalWatchViewColumnKind_ViewRule: - { - df_eval_view_set_key_rule(eval_view, commit_row->key, commit_string); - }break; - } - if(edit_submit && commit_string.size != 0) - { - cursor_tbl.y += 1; - } - } - } - - ////////////////////////////// - //- rjf: end edits - // - if(edit_end) - { - ewv->input_editing = 0; - } - - ////////////////////////////// - //- rjf: commits occurred -> re-compute blocks to adjust to new state - // - if(edit_commit) - { - blocks = df_eval_viz_block_list_from_watch_view_state(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, view, ewv); - if(modifiable) - { - DF_EvalVizBlock *b = df_eval_viz_block_begin(scratch.arena, DF_EvalVizBlockKind_Null, empty_row_parent_key, empty_row_key, 0); - b->visual_idx_range = b->semantic_idx_range = r1u64(0, 1); - df_eval_viz_block_end(&blocks, b); - } - } - - ////////////////////////////// - //- rjf: convert new table coordinates back to selection state - // - struct - { - DF_EvalWatchViewPoint *pt_state; - Vec2S64 pt_tbl; - } - points[] = - { - {&ewv->cursor, cursor_tbl}, - {&ewv->mark, mark_tbl}, - }; - for(U64 point_idx = 0; point_idx < ArrayCount(points); point_idx += 1) - { - DF_ExpandKey last_key = points[point_idx].pt_state->key; - DF_ExpandKey last_parent_key = points[point_idx].pt_state->parent_key; - points[point_idx].pt_state->column_kind= (DF_EvalWatchViewColumnKind)points[point_idx].pt_tbl.x; - points[point_idx].pt_state->key = df_key_from_viz_block_list_row_num(&blocks, points[point_idx].pt_tbl.y); - points[point_idx].pt_state->parent_key = df_parent_key_from_viz_block_list_row_num(&blocks, points[point_idx].pt_tbl.y); - if(df_expand_key_match(df_expand_key_zero(), points[point_idx].pt_state->key)) - { - points[point_idx].pt_state->key = last_parent_key; - DF_ExpandNode *node = df_expand_node_from_key(&eval_view->expand_tree_table, last_parent_key); - for(DF_ExpandNode *n = node; n != 0; n = n->parent) - { - points[point_idx].pt_state->key = n->key; - if(n->expanded == 0) - { - break; - } - } - } - if(point_idx == 0 && - (!df_expand_key_match(ewv->cursor.key, last_key) || - !df_expand_key_match(ewv->cursor.parent_key, last_parent_key))) - { - ewv->input_editing = 0; - } - } - scratch_end(scratch); dbgi_scope_close(scope); ProfEnd(); @@ -1855,7 +2257,7 @@ DF_VIEW_UI_FUNCTION_DEF(Commands) df_cmd_lister_item_array_sort_by_strength__in_place(cmd_array); //- rjf: submit best match when hitting enter w/ no selection - if(cv->selected_cmd_spec == &df_g_nil_cmd_spec && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(cv->selected_cmd_spec == &df_g_nil_cmd_spec && ui_slot_press(UI_EventActionSlot_Accept)) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); if(cmd_array.count > 0) @@ -1892,7 +2294,13 @@ DF_VIEW_UI_FUNCTION_DEF(Commands) scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; } UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + UI_Focus(UI_FocusKind_On) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) { //- rjf: build buttons @@ -2194,7 +2602,7 @@ DF_VIEW_UI_FUNCTION_DEF(FileSystem) } //- rjf: submit best match when hitting enter w/ no selection - if(ps->cursor.y == 0 && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(ps->cursor.y == 0 && ui_slot_press(UI_EventActionSlot_Accept)) { FileProperties query_normalized_with_opt_slash_props = os_properties_from_file_path(query_normalized_with_opt_slash); FileProperties path_query_path_props = os_properties_from_file_path(path_query.path); @@ -2336,7 +2744,13 @@ DF_VIEW_UI_FUNCTION_DEF(FileSystem) scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; } UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &ps->cursor, &visible_row_range, &scroll_list_sig) + UI_Focus(UI_FocusKind_On) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &ps->cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) { // rjf: up-one-directory button (at idx 0) @@ -2533,7 +2947,7 @@ DF_VIEW_UI_FUNCTION_DEF(SystemProcesses) } //- rjf: submit best match when hitting enter w/ no selection - if(sp->selected_pid == 0 && process_info_array.count > 0 && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(sp->selected_pid == 0 && process_info_array.count > 0 && ui_slot_press(UI_EventActionSlot_Accept)) { DF_ProcessInfo *info = &process_info_array.v[0]; DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); @@ -2569,7 +2983,12 @@ DF_VIEW_UI_FUNCTION_DEF(SystemProcesses) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) { //- rjf: build rows @@ -2690,7 +3109,7 @@ DF_VIEW_UI_FUNCTION_DEF(EntityLister) df_entity_lister_item_array_sort_by_strength__in_place(ent_arr); //- rjf: submit best match when hitting enter w/ no selection - if(df_entity_is_nil(df_entity_from_handle(fev->selected_entity_handle)) && ent_arr.count != 0 && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(df_entity_is_nil(df_entity_from_handle(fev->selected_entity_handle)) && ent_arr.count != 0 && ui_slot_press(UI_EventActionSlot_Accept)) { DF_Entity *ent = ent_arr.v[0].entity; DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); @@ -2728,7 +3147,12 @@ DF_VIEW_UI_FUNCTION_DEF(EntityLister) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) { for(S64 idx = visible_row_range.min; @@ -2843,7 +3267,7 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) } //- rjf: submit best match when hitting enter w/ no selection - if(slv->cursor.y == 0 && items.count != 0 && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(slv->cursor.y == 0 && items.count != 0 && ui_slot_press(UI_EventActionSlot_Accept)) { RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, items.v[0].idx); U64 name_size = 0; @@ -2872,7 +3296,12 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &slv->cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &slv->cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) UI_Font(df_font_from_slot(DF_FontSlot_Code)) { @@ -3043,32 +3472,32 @@ DF_VIEW_UI_FUNCTION_DEF(Target) { if(!tv->input_editing) { - UI_NavActionList *nav_actions = ui_nav_actions(); - for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + UI_EventList *events = ui_events(); + for(UI_EventNode *n = events->first; n != 0; n = n->next) { - if(n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste) + if(n->v.string.size != 0 || n->v.flags & UI_EventFlag_Paste) { edit_begin = 1; break; } } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_F2)) + if(ui_slot_press(UI_EventActionSlot_Edit)) { edit_begin = 1; } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(ui_slot_press(UI_EventActionSlot_Accept)) { edit_begin = 1; } } if(tv->input_editing) { - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + if(ui_slot_press(UI_EventActionSlot_Cancel)) { edit_end = 1; edit_commit = 0; } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(ui_slot_press(UI_EventActionSlot_Accept)) { edit_end = 1; edit_commit = 1; @@ -3092,7 +3521,12 @@ DF_VIEW_UI_FUNCTION_DEF(Target) Vec2S64 next_cursor = tv->cursor; UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, tv->input_editing ? 0 : &tv->cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + tv->input_editing ? 0 : &tv->cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) { next_cursor = tv->cursor; @@ -3334,7 +3768,12 @@ DF_VIEW_UI_FUNCTION_DEF(Targets) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) { // rjf: add new ctrl @@ -3518,28 +3957,28 @@ DF_VIEW_UI_FUNCTION_DEF(FilePathMap) { if(!fpms->input_editing) { - UI_NavActionList *nav_actions = ui_nav_actions(); - for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + UI_EventList *events = ui_events(); + for(UI_EventNode *n = events->first; n != 0; n = n->next) { - if(n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste) + if(n->v.string.size != 0 || n->v.flags & UI_EventFlag_Paste) { edit_begin = 1; break; } } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_F2)) + if(ui_slot_press(UI_EventActionSlot_Edit)) { edit_begin = 1; } } if(fpms->input_editing) { - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + if(ui_slot_press(UI_EventActionSlot_Cancel)) { edit_end = 1; edit_commit = 0; } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(ui_slot_press(UI_EventActionSlot_Accept)) { edit_end = 1; edit_commit = 1; @@ -3565,7 +4004,12 @@ DF_VIEW_UI_FUNCTION_DEF(FilePathMap) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, fpms->input_editing ? 0 : &fpms->cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + fpms->input_editing ? 0 : &fpms->cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) UI_TableF(ArrayCount(col_pcts), col_pcts, "###tbl") { @@ -3836,28 +4280,28 @@ DF_VIEW_UI_FUNCTION_DEF(AutoViewRules) { if(!avrs->input_editing) { - UI_NavActionList *nav_actions = ui_nav_actions(); - for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + UI_EventList *events = ui_events(); + for(UI_EventNode *n = events->first; n != 0; n = n->next) { - if(n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste) + if(n->v.string.size != 0 || n->v.flags & UI_EventFlag_Paste) { edit_begin = 1; break; } } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_F2)) + if(ui_slot_press(UI_EventActionSlot_Edit)) { edit_begin = 1; } } if(avrs->input_editing) { - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + if(ui_slot_press(UI_EventActionSlot_Cancel)) { edit_end = 1; edit_commit = 0; } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(ui_slot_press(UI_EventActionSlot_Accept)) { edit_end = 1; edit_commit = 1; @@ -3883,7 +4327,12 @@ DF_VIEW_UI_FUNCTION_DEF(AutoViewRules) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, avrs->input_editing ? 0 : &avrs->cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + avrs->input_editing ? 0 : &avrs->cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) UI_TableF(ArrayCount(col_pcts), col_pcts, "###tbl") { @@ -4169,7 +4618,12 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) UI_TableF(0, 0, "scheduler_table") { @@ -4338,6 +4792,7 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack) { B32 initialized; Vec2S64 cursor; + Vec2S64 mark; F32 selection_col_pct; F32 module_col_pct; F32 function_name_col_pct; @@ -4366,7 +4821,12 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cs->cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &cs->cursor, + &cs->mark, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) { Vec2S64 next_cursor = cs->cursor; @@ -4652,29 +5112,28 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) B32 edit_submit = 0; if(!mv->txt_editing && ui_is_focus_active()) { - UI_NavActionList *nav_actions = ui_nav_actions(); - for(UI_NavActionNode *n = nav_actions->first; n != 0; n = n->next) + UI_EventList *events = ui_events(); + for(UI_EventNode *n = events->first; n != 0; n = n->next) { - if(n->v.insertion.size != 0 || n->v.flags & UI_NavActionFlag_Paste) + if(n->v.string.size != 0 || n->v.flags & UI_EventFlag_Paste) { edit_begin = 1; break; } } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_F2) || - os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(ui_slot_press(UI_EventActionSlot_Edit)) { edit_begin = 1; } } if(mv->txt_editing && ui_is_focus_active()) { - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + if(ui_slot_press(UI_EventActionSlot_Cancel)) { edit_end = 1; edit_commit = 0; } - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(ui_slot_press(UI_EventActionSlot_Accept)) { edit_end = 1; edit_commit = 1; @@ -4696,7 +5155,12 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, mv->txt_editing ? 0 : &cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + mv->txt_editing ? 0 : &cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) UI_TableF(ArrayCount(col_pcts), col_pcts, "modules_table") { @@ -5401,6 +5865,11 @@ DF_VIEW_UI_FUNCTION_DEF(Code) code_slice_params.line_num_width_px = line_num_width_px; code_slice_params.line_text_max_width_px = (F32)line_size_x; code_slice_params.flash_ranges = df_push_entity_child_list_with_kind(scratch.arena, entity, DF_EntityKind_FlashMarker); + code_slice_params.margin_float_off_px = view->scroll_pos.x.idx + view->scroll_pos.x.off; + if(code_slice_params.margin_float_off_px < 1) + { + code_slice_params.margin_float_off_px = 0; + } // rjf: fill text info { @@ -6484,6 +6953,11 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) code_slice_params.line_num_width_px = line_num_width_px; code_slice_params.line_text_max_width_px = (F32)line_size_x; code_slice_params.flash_ranges = df_push_entity_child_list_with_kind(scratch.arena, process, DF_EntityKind_FlashMarker); + code_slice_params.margin_float_off_px = view->scroll_pos.x.idx + view->scroll_pos.x.off; + if(code_slice_params.margin_float_off_px < 1) + { + code_slice_params.margin_float_off_px = 0; + } df_entity_list_push(scratch.arena, &code_slice_params.relevant_binaries, binary); // rjf: fill text info @@ -6935,8 +7409,8 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) DF_VIEW_SETUP_FUNCTION_DEF(Watch) { ProfBeginFunction(); - DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); - df_eval_watch_view_init(ewv, view, DF_EvalWatchViewFillKind_Mutable); + DF_WatchViewState *ewv = df_view_user_state(view, DF_WatchViewState); + df_watch_view_init(ewv, view, DF_WatchViewFillKind_Mutable); // rjf: add roots for watches { @@ -6968,7 +7442,7 @@ DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Watch) { Temp scratch = scratch_begin(&arena, 1); String8List strs = {0}; - DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); + DF_WatchViewState *ewv = df_view_user_state(view, DF_WatchViewState); DF_EvalViewKey eval_view_key = df_eval_view_key_from_eval_watch_view(ewv); DF_EvalView *eval_view = df_eval_view_from_key(eval_view_key); { @@ -6998,16 +7472,16 @@ DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Watch) DF_VIEW_CMD_FUNCTION_DEF(Watch) { ProfBeginFunction(); - DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); - df_eval_watch_view_cmds(ws, panel, view, ewv, cmds); + DF_WatchViewState *ewv = df_view_user_state(view, DF_WatchViewState); + df_watch_view_cmds(ws, panel, view, ewv, cmds); ProfEnd(); } DF_VIEW_UI_FUNCTION_DEF(Watch) { ProfBeginFunction(); - DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); - df_eval_watch_view_build(ws, panel, view, ewv, 1*(view->query_string_size == 0), 10, rect); + DF_WatchViewState *ewv = df_view_user_state(view, DF_WatchViewState); + df_watch_view_build(ws, panel, view, ewv, 1*(view->query_string_size == 0), 10, rect); ProfEnd(); } @@ -7020,9 +7494,9 @@ DF_VIEW_CMD_FUNCTION_DEF(Locals) {} DF_VIEW_UI_FUNCTION_DEF(Locals) { ProfBeginFunction(); - DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); - df_eval_watch_view_init(ewv, view, DF_EvalWatchViewFillKind_Locals); - df_eval_watch_view_build(ws, panel, view, ewv, 0, 10, rect); + DF_WatchViewState *ewv = df_view_user_state(view, DF_WatchViewState); + df_watch_view_init(ewv, view, DF_WatchViewFillKind_Locals); + df_watch_view_build(ws, panel, view, ewv, 0, 10, rect); ProfEnd(); } @@ -7035,9 +7509,9 @@ DF_VIEW_CMD_FUNCTION_DEF(Registers) {} DF_VIEW_UI_FUNCTION_DEF(Registers) { ProfBeginFunction(); - DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); - df_eval_watch_view_init(ewv, view, DF_EvalWatchViewFillKind_Registers); - df_eval_watch_view_build(ws, panel, view, ewv, 0, 16, rect); + DF_WatchViewState *ewv = df_view_user_state(view, DF_WatchViewState); + df_watch_view_init(ewv, view, DF_WatchViewFillKind_Registers); + df_watch_view_build(ws, panel, view, ewv, 0, 16, rect); ProfEnd(); } @@ -7050,9 +7524,9 @@ DF_VIEW_CMD_FUNCTION_DEF(Globals) {} DF_VIEW_UI_FUNCTION_DEF(Globals) { ProfBeginFunction(); - DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); - df_eval_watch_view_init(ewv, view, DF_EvalWatchViewFillKind_Globals); - df_eval_watch_view_build(ws, panel, view, ewv, 0, 10, rect); + DF_WatchViewState *ewv = df_view_user_state(view, DF_WatchViewState); + df_watch_view_init(ewv, view, DF_WatchViewFillKind_Globals); + df_watch_view_build(ws, panel, view, ewv, 0, 10, rect); ProfEnd(); } @@ -7065,9 +7539,9 @@ DF_VIEW_CMD_FUNCTION_DEF(ThreadLocals) {} DF_VIEW_UI_FUNCTION_DEF(ThreadLocals) { ProfBeginFunction(); - DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); - df_eval_watch_view_init(ewv, view, DF_EvalWatchViewFillKind_ThreadLocals); - df_eval_watch_view_build(ws, panel, view, ewv, 0, 10, rect); + DF_WatchViewState *ewv = df_view_user_state(view, DF_WatchViewState); + df_watch_view_init(ewv, view, DF_WatchViewFillKind_ThreadLocals); + df_watch_view_build(ws, panel, view, ewv, 0, 10, rect); ProfEnd(); } @@ -7080,9 +7554,9 @@ DF_VIEW_CMD_FUNCTION_DEF(Types) {} DF_VIEW_UI_FUNCTION_DEF(Types) { ProfBeginFunction(); - DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); - df_eval_watch_view_init(ewv, view, DF_EvalWatchViewFillKind_Types); - df_eval_watch_view_build(ws, panel, view, ewv, 0, 10, rect); + DF_WatchViewState *ewv = df_view_user_state(view, DF_WatchViewState); + df_watch_view_init(ewv, view, DF_WatchViewFillKind_Types); + df_watch_view_build(ws, panel, view, ewv, 0, 10, rect); ProfEnd(); } @@ -7095,9 +7569,9 @@ DF_VIEW_CMD_FUNCTION_DEF(Procedures) {} DF_VIEW_UI_FUNCTION_DEF(Procedures) { ProfBeginFunction(); - DF_EvalWatchViewState *ewv = df_view_user_state(view, DF_EvalWatchViewState); - df_eval_watch_view_init(ewv, view, DF_EvalWatchViewFillKind_Procedures); - df_eval_watch_view_build(ws, panel, view, ewv, 0, 10, rect); + DF_WatchViewState *ewv = df_view_user_state(view, DF_WatchViewState); + df_watch_view_init(ewv, view, DF_WatchViewFillKind_Procedures); + df_watch_view_build(ws, panel, view, ewv, 0, 10, rect); ProfEnd(); } @@ -7319,6 +7793,11 @@ DF_VIEW_UI_FUNCTION_DEF(Output) code_slice_params.line_num_width_px = line_num_width_px; code_slice_params.line_text_max_width_px = (F32)line_size_x; code_slice_params.flash_ranges = df_push_entity_child_list_with_kind(scratch.arena, entity, DF_EntityKind_FlashMarker); + code_slice_params.margin_float_off_px = view->scroll_pos.x.idx + view->scroll_pos.x.off; + if(code_slice_params.margin_float_off_px < 1) + { + code_slice_params.margin_float_off_px = 0; + } } ////////////////////////////// @@ -7847,47 +8326,47 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) { U64 next_cursor = mv->cursor; U64 next_mark = mv->mark; - 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; - UI_NavAction *action = &n->v; + UI_Event *evt = &n->v; Vec2S64 cell_delta = {0}; - switch(action->delta_unit) + switch(evt->delta_unit) { default:{}break; - case UI_NavDeltaUnit_Element: + case UI_EventDeltaUnit_Char: { - cell_delta.x = (S64)action->delta.x; - cell_delta.y = (S64)action->delta.y; + cell_delta.x = (S64)evt->delta_2s32.x; + cell_delta.y = (S64)evt->delta_2s32.y; }break; - case UI_NavDeltaUnit_Chunk: - case UI_NavDeltaUnit_Whole: + case UI_EventDeltaUnit_Word: + case UI_EventDeltaUnit_Page: { - if(action->delta.x < 0) + if(evt->delta_2s32.x < 0) { cell_delta.x = -(S64)(mv->cursor%mv->num_columns); } - else if(action->delta.x > 0) + else if(evt->delta_2s32.x > 0) { cell_delta.x = (mv->num_columns-1) - (S64)(mv->cursor%mv->num_columns); } - if(action->delta.y < 0) + if(evt->delta_2s32.y < 0) { cell_delta.y = -4; } - else if(action->delta.y > 0) + else if(evt->delta_2s32.y > 0) { cell_delta.y = +4; } }break; } B32 good_action = 0; - if(action->delta.x != 0 || action->delta.y != 0) + if(evt->delta_2s32.x != 0 || evt->delta_2s32.y != 0) { good_action = 1; } - if(good_action && action->flags & UI_NavActionFlag_ZeroDeltaOnSelect && mv->cursor != mv->mark) + if(good_action && evt->flags & UI_EventFlag_ZeroDeltaOnSelect && mv->cursor != mv->mark) { MemoryZeroStruct(&cell_delta); } @@ -7899,9 +8378,9 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) next_cursor += cell_delta.y*mv->num_columns; next_cursor = ClampTop(0x7FFFFFFFFFFFull, next_cursor); } - if(good_action && action->flags & UI_NavActionFlag_PickSelectSide && mv->cursor != mv->mark) + if(good_action && evt->flags & UI_EventFlag_PickSelectSide && mv->cursor != mv->mark) { - if(action->delta.x < 0 || action->delta.y < 0) + if(evt->delta_2s32.x < 0 || evt->delta_2s32.y < 0) { next_cursor = Min(mv->cursor, mv->mark); } @@ -7910,14 +8389,14 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) next_cursor = Max(mv->cursor, mv->mark); } } - if(good_action && !(action->flags & UI_NavActionFlag_KeepMark)) + if(good_action && !(evt->flags & UI_EventFlag_KeepMark)) { next_mark = next_cursor; } if(good_action) { mv->contain_cursor = 1; - ui_nav_eat_action_node(nav_actions, n); + ui_eat_event(events, n); } } mv->cursor = next_cursor; @@ -8320,18 +8799,20 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) // rjf: ctrl+scroll -> change font size if(ui_hovering(sig)) { - for(OS_Event *event = ui_events()->first, *next = 0; event != 0; event = next) + UI_EventList *events = ui_events(); + for(UI_EventNode *n = events->first, *next = 0; n != 0; n = next) { - next = event->next; - if(os_handle_match(event->window, ui_window()) && event->kind == OS_EventKind_Scroll && event->flags & OS_EventFlag_Ctrl) + next = n->next; + UI_Event *event = &n->v; + if(event->kind == UI_EventKind_Scroll && event->modifiers & OS_EventFlag_Ctrl) { - os_eat_event(ui_events(), event); - if(event->delta.y < 0) + ui_eat_event(events, n); + if(event->delta_2f32.y < 0) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_IncCodeFontScale)); } - else if(event->delta.y > 0) + else if(event->delta_2f32.y > 0) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_DecCodeFontScale)); @@ -8642,7 +9123,12 @@ DF_VIEW_UI_FUNCTION_DEF(Breakpoints) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) UI_TableF(ArrayCount(col_pcts), col_pcts, "breakpoints_table") { @@ -8812,7 +9298,12 @@ DF_VIEW_UI_FUNCTION_DEF(WatchPins) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) UI_TableF(ArrayCount(col_pcts), col_pcts, "pins_table") { @@ -8986,7 +9477,12 @@ DF_VIEW_UI_FUNCTION_DEF(ExceptionFilters) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &sv->cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &sv->cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) { for(S64 row = visible_row_range.min; row <= visible_row_range.max && row < opts.count; row += 1) @@ -9342,7 +9838,12 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) } UI_ScrollListSignal scroll_list_sig = {0}; UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &view->scroll_pos.y, &sv->cursor, &visible_row_range, &scroll_list_sig) + UI_ScrollList(&scroll_list_params, + &view->scroll_pos.y, + &sv->cursor, + 0, + &visible_row_range, + &scroll_list_sig) UI_Focus(UI_FocusKind_Null) { for(S64 row = visible_row_range.min; row <= visible_row_range.max; row += 1) diff --git a/src/df/gfx/df_views.h b/src/df/gfx/df_views.h index fabaa30b..7f450c41 100644 --- a/src/df/gfx/df_views.h +++ b/src/df/gfx/df_views.h @@ -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 diff --git a/src/df/gfx/generated/df_gfx.meta.c b/src/df/gfx/generated/df_gfx.meta.c index ccc23bfa..9210f578 100644 --- a/src/df/gfx/generated/df_gfx.meta.c +++ b/src/df/gfx/generated/df_gfx.meta.c @@ -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}}, diff --git a/src/df/gfx/generated/df_gfx.meta.h b/src/df/gfx/generated/df_gfx.meta.h index a3995179..e5203b70 100644 --- a/src/df/gfx/generated/df_gfx.meta.h +++ b/src/df/gfx/generated/df_gfx.meta.h @@ -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]; diff --git a/src/lib_raddbg_markup/raddbg_markup.h b/src/lib_raddbg_markup/raddbg_markup.h index bd0b0cc4..66b0fa31 100644 --- a/src/lib_raddbg_markup/raddbg_markup.h +++ b/src/lib_raddbg_markup/raddbg_markup.h @@ -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 diff --git a/src/metagen/metagen_base/metagen_base_context_cracking.h b/src/metagen/metagen_base/metagen_base_context_cracking.h index 65f49e7b..e35b10f4 100644 --- a/src/metagen/metagen_base/metagen_base_context_cracking.h +++ b/src/metagen/metagen_base/metagen_base_context_cracking.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 diff --git a/src/raddbg/raddbg.c b/src/raddbg/raddbg.c index 218b7fa8..c0af86cc 100644 --- a/src/raddbg/raddbg.c +++ b/src/raddbg/raddbg.c @@ -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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, DF_CmdParamSlot_String); df_push_cmd__root(¶ms, 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(¶ms, 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(¶ms, 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); diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index bb0f5087..1e7a1ce1 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -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 diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.c b/src/raddbgi_from_pdb/raddbgi_from_pdb.c index 26901abb..a85e1105 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.c +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb.c @@ -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); diff --git a/src/ui/ui_basic_widgets.c b/src/ui/ui_basic_widgets.c index 9cad0cf7..c1fa8983 100644 --- a/src/ui/ui_basic_widgets.c +++ b/src/ui/ui_basic_widgets.c @@ -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; + } } } diff --git a/src/ui/ui_basic_widgets.h b/src/ui/ui_basic_widgets.h index cc934a52..dc8c2394 100644 --- a/src/ui/ui_basic_widgets.h +++ b/src/ui/ui_basic_widgets.h @@ -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 diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 51f45dc2..cd68bcae 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -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); } } diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index d0f48eb6..6b24be53 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -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);