arresting confirmation ui - use in exit-while-debugging

This commit is contained in:
Ryan Fleury
2024-01-13 14:47:05 -08:00
parent 096d85168a
commit c0322437d6
7 changed files with 142 additions and 20 deletions
+21 -16
View File
@@ -80,22 +80,23 @@ DF_EntityKindTable:
@table(name, name_lower, c_type)
DF_CmdParamSlotTable:
{
{Window, window, `DF_Handle`}
{Panel, panel, `DF_Handle`}
{DestPanel, dest_panel, `DF_Handle`}
{PrevView, prev_view, `DF_Handle`}
{View, view, `DF_Handle`}
{Entity, entity, `DF_Handle`}
{EntityList, entity_list, `DF_HandleList`}
{String, string, `String8`}
{FilePath, file_path, `String8`}
{TextPoint, text_point, `TxtPt`}
{CmdSpec, cmd_spec, `struct DF_CmdSpec *`}
{VirtualAddr, vaddr, `U64`}
{VirtualOff, voff, `U64`}
{Index, index, `U64`}
{ID, id, `U64`}
{PreferDisassembly, prefer_dasm, `B32`}
{Window, window, `DF_Handle`}
{Panel, panel, `DF_Handle`}
{DestPanel, dest_panel, `DF_Handle`}
{PrevView, prev_view, `DF_Handle`}
{View, view, `DF_Handle`}
{Entity, entity, `DF_Handle`}
{EntityList, entity_list, `DF_HandleList`}
{String, string, `String8`}
{FilePath, file_path, `String8`}
{TextPoint, text_point, `TxtPt`}
{CmdSpec, cmd_spec, `struct DF_CmdSpec *`}
{VirtualAddr, vaddr, `U64`}
{VirtualOff, voff, `U64`}
{Index, index, `U64`}
{ID, id, `U64`}
{PreferDisassembly, prefer_dasm, `B32`}
{ForceConfirm, force_confirm,`B32`}
}
@table(name, display_string, args_desc)
@@ -185,6 +186,10 @@ DF_CoreCmdTable:
{CloseWindow 0 0 0 0 0 Window Null Null Null Null 0 0 Window "close_window" "Close Window" "Closes an opened window." "" }
{ToggleFullscreen 0 0 0 0 0 Window Null Null Null Null 0 0 Window "toggle_fullscreen" "Toggle Fullscreen" "Toggles fullscreen view on the active window." "" }
//- rjf: confirmations
{ConfirmAccept 1 0 0 0 0 Null Null Null Null Null 0 0 Null "confirm_accept" "Confirm Accept" "Accepts the active confirmation prompt." "" }
{ConfirmCancel 1 0 0 0 0 Null Null Null Null Null 0 0 Null "confirm_cancel" "Confirm Cancel" "Cancels the active confirmation prompt." "" }
//- rjf: panel splitting
{ResetToDefaultPanels 0 0 0 0 0 Window Null Null Null Null 0 0 Window "reset_to_default_panels" "Reset To Default Panel Layout" "Resets the window to the default panel layout." "panel" }
{NewPanelRight 0 0 0 0 0 Window Panel Null Null Null 0 0 XSplit "new_panel_right" "Split Panel Vertically" "Creates a new panel to the right of the active panel." "panel" }
+2
View File
@@ -54,6 +54,8 @@ DF_CmdSpecInfo df_g_core_cmd_kind_spec_info_table[] =
{ str8_lit_comp("open_window"), str8_lit_comp("Opens a new window."), str8_lit_comp(""), str8_lit_comp("Open New Window"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Window, {0, 0}},
{ str8_lit_comp("close_window"), str8_lit_comp("Closes an opened window."), str8_lit_comp(""), str8_lit_comp("Close Window"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Window, {0, 0}},
{ str8_lit_comp("toggle_fullscreen"), str8_lit_comp("Toggles fullscreen view on the active window."), str8_lit_comp(""), str8_lit_comp("Toggle Fullscreen"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Window, {0, 0}},
{ str8_lit_comp("confirm_accept"), str8_lit_comp("Accepts the active confirmation prompt."), str8_lit_comp(""), str8_lit_comp("Confirm Accept"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}},
{ str8_lit_comp("confirm_cancel"), str8_lit_comp("Cancels the active confirmation prompt."), str8_lit_comp(""), str8_lit_comp("Confirm Cancel"), (DF_CmdSpecFlag_OmitFromLists*1) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Null, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Null, {0, 0}},
{ str8_lit_comp("reset_to_default_panels"), str8_lit_comp("Resets the window to the default panel layout."), str8_lit_comp("panel"), str8_lit_comp("Reset To Default Panel Layout"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Null, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_Window, {0, 0}},
{ str8_lit_comp("new_panel_right"), str8_lit_comp("Creates a new panel to the right of the active panel."), str8_lit_comp("panel"), str8_lit_comp("Split Panel Vertically"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_XSplit, {0, 0}},
{ str8_lit_comp("new_panel_down"), str8_lit_comp("Creates a new panel at the bottom of the active panel."), str8_lit_comp("panel"), str8_lit_comp("Split Panel Horizontally"), (DF_CmdSpecFlag_OmitFromLists*0) | (DF_CmdSpecFlag_RunKeepsQuery*0) | (DF_CmdSpecFlag_QueryUsesOldInput*0) | (DF_CmdSpecFlag_AppliesToView*0) | (DF_CmdSpecFlag_QueryIsCode*0), {DF_CmdParamSlot_Window, DF_CmdParamSlot_Panel, DF_CmdParamSlot_Null}, DF_CmdQueryRule_Null, DF_IconKind_YSplit, {0, 0}},
+4
View File
@@ -104,6 +104,8 @@ DF_CoreCmdKind_DecCodeFontScale,
DF_CoreCmdKind_OpenWindow,
DF_CoreCmdKind_CloseWindow,
DF_CoreCmdKind_ToggleFullscreen,
DF_CoreCmdKind_ConfirmAccept,
DF_CoreCmdKind_ConfirmCancel,
DF_CoreCmdKind_ResetToDefaultPanels,
DF_CoreCmdKind_NewPanelRight,
DF_CoreCmdKind_NewPanelDown,
@@ -368,6 +370,7 @@ DF_CmdParamSlot_VirtualOff,
DF_CmdParamSlot_Index,
DF_CmdParamSlot_ID,
DF_CmdParamSlot_PreferDisassembly,
DF_CmdParamSlot_ForceConfirm,
DF_CmdParamSlot_COUNT
} DF_CmdParamSlot;
@@ -407,6 +410,7 @@ U64 voff;
U64 index;
U64 id;
B32 prefer_dasm;
B32 force_confirm;
};
DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(array);
+101 -1
View File
@@ -1145,6 +1145,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D
{
ProfBeginFunction();
B32 window_is_focused = os_window_is_focused(ws->os);
B32 confirm_open = df_gfx_state->confirm_active;
B32 hover_eval_is_open = (ws->hover_eval_string.size != 0 && ws->hover_eval_first_frame_idx+20 < ws->hover_eval_last_frame_idx && df_frame_index()-ws->hover_eval_last_frame_idx < 20);
B32 any_query_is_focused = !df_panel_is_nil(ws->focused_panel) && !df_view_is_nil(df_query_view_from_panel(ws->focused_panel));
if(!window_is_focused)
@@ -3861,6 +3862,55 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D
scratch_end(scratch);
}
//- rjf: confirmation popup
{
if(df_gfx_state->confirm_t > 0.005f) UI_Focus(1) UI_TextAlignment(UI_TextAlign_Center)
{
Vec2F32 window_dim = dim_2f32(window_rect);
UI_Box *bg_box = &ui_g_nil_box;
UI_Rect(window_rect) UI_ChildLayoutAxis(Axis2_X)
{
Vec4F32 bg_color = ui_top_background_color();
bg_color.w *= df_gfx_state->confirm_t;
ui_set_next_blur_size(10*df_gfx_state->confirm_t);
ui_set_next_background_color(bg_color);
bg_box = ui_build_box_from_stringf(UI_BoxFlag_FixedSize|UI_BoxFlag_Floating|UI_BoxFlag_Clickable|UI_BoxFlag_Scroll|UI_BoxFlag_DefaultFocusNav|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawBackground, "###confirm_popup_%p", ws);
}
if(df_gfx_state->confirm_active) UI_Parent(bg_box)
{
ui_ctx_menu_close();
UI_WidthFill UI_PrefHeight(ui_children_sum(1.f)) UI_Column UI_Padding(ui_pct(1, 0))
{
UI_FontSize(ui_top_font_size()*2.f) UI_PrefHeight(ui_em(3.f, 1.f)) ui_label(df_gfx_state->confirm_title);
UI_PrefHeight(ui_em(3.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_label(df_gfx_state->confirm_msg);
ui_spacer(ui_em(1.5f, 1.f));
UI_Row UI_Padding(ui_pct(1.f, 0.f)) UI_WidthFill UI_PrefHeight(ui_em(5.f, 1.f))
{
UI_CornerRadius00(ui_top_font_size()*0.25f)
UI_CornerRadius01(ui_top_font_size()*0.25f)
if(ui_buttonf("Cancel").clicked || os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc))
{
DF_CmdParams p = df_cmd_params_zero();
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ConfirmCancel));
}
UI_CornerRadius10(ui_top_font_size()*0.25f)
UI_CornerRadius11(ui_top_font_size()*0.25f)
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_buttonf("OK").clicked)
{
DF_CmdParams p = df_cmd_params_zero();
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ConfirmAccept));
}
}
ui_spacer(ui_em(3.f, 1.f));
}
}
ui_signal_from_box(bg_box);
}
}
//- rjf: build auto-complete lister
ProfScope("build autocomplete lister")
if(!ws->autocomp_force_closed && !ui_key_match(ws->autocomp_root_key, ui_key_zero()) && ws->autocomp_last_frame_idx+1 >= df_frame_index())
@@ -10898,6 +10948,7 @@ df_gfx_init(OS_WindowRepaintFunctionType *window_repaint_entry_point, DF_StateDe
df_gfx_state->num_frames_requested = 2;
df_gfx_state->hist = hist;
df_gfx_state->key_map_arena = arena_alloc();
df_gfx_state->confirm_arena = arena_alloc();
df_gfx_state->view_spec_table_size = 256;
df_gfx_state->view_spec_table = push_array(arena, DF_ViewSpec *, df_gfx_state->view_spec_table_size);
df_gfx_state->view_rule_spec_table_size = 1024;
@@ -10942,6 +10993,17 @@ df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds)
arena_clear(df_gfx_state->frame_arena);
df_gfx_state->hover_line_set_this_frame = 0;
//- rjf: animate confirmation
{
F32 rate = 1 - pow_f32(2, (-10.f * df_dt()));
B32 confirm_open = df_gfx_state->confirm_active;
df_gfx_state->confirm_t += rate * ((F32)!!confirm_open-df_gfx_state->confirm_t);
if(abs_f32(df_gfx_state->confirm_t - (F32)!!confirm_open) > 0.005f)
{
df_gfx_request_frame();
}
}
//- rjf: capture is active? -> keep rendering
if(ProfIsCapturing())
{
@@ -11002,10 +11064,32 @@ df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds)
DF_Window *ws = df_window_from_handle(params.window);
if(ws != 0)
{
DF_EntityList running_processes = df_query_cached_entity_list_with_kind(DF_EntityKind_Process);
// NOTE(rjf): if this is the last window, and targets are running, but
// this command is not force-confirmed, then we should query the user
// to ensure they want to close the debugger before exiting
UI_Key key = ui_key_from_string(ui_key_zero(), str8_lit("lossy_exit_confirmation"));
if(!ui_key_match(key, df_gfx_state->confirm_key) && running_processes.count != 0 && ws == df_gfx_state->first_window && ws == df_gfx_state->last_window && !params.force_confirm)
{
df_gfx_state->confirm_key = key;
df_gfx_state->confirm_active = 1;
arena_clear(df_gfx_state->confirm_arena);
MemoryZeroStruct(&df_gfx_state->confirm_cmds);
df_gfx_state->confirm_title = push_str8f(df_gfx_state->confirm_arena, "Are you sure you want to exit?");
df_gfx_state->confirm_msg = push_str8f(df_gfx_state->confirm_arena, "The debugger is still attached to %slive process%s.",
running_processes.count == 1 ? "a " : "",
running_processes.count == 1 ? "" : "es");
DF_CmdParams p = df_cmd_params_from_window(ws);
p.force_confirm = 1;
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_ForceConfirm);
df_cmd_list_push(df_gfx_state->confirm_arena, &df_gfx_state->confirm_cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseWindow));
}
// NOTE(rjf): if this is the last window, and it is being closed, then
// we need to auto-save, and provide one last chance to process saving
// commands. after doing so, we can retry.
if(ws == df_gfx_state->first_window && ws == df_gfx_state->last_window && df_gfx_state->last_window_queued_save == 0)
else if(ws == df_gfx_state->first_window && ws == df_gfx_state->last_window && df_gfx_state->last_window_queued_save == 0)
{
df_gfx_state->last_window_queued_save = 1;
{
@@ -11047,6 +11131,22 @@ df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds)
}
}break;
//- rjf: confirmations
case DF_CoreCmdKind_ConfirmAccept:
{
df_gfx_state->confirm_active = 0;
df_gfx_state->confirm_key = ui_key_zero();
for(DF_CmdNode *n = df_gfx_state->confirm_cmds.first; n != 0; n = n->next)
{
df_push_cmd__root(&n->cmd.params, n->cmd.spec);
}
}break;
case DF_CoreCmdKind_ConfirmCancel:
{
df_gfx_state->confirm_active = 0;
df_gfx_state->confirm_key = ui_key_zero();
}break;
//- rjf: commands with implications for graphical systems, but generated
// without context needed - pick selected window & dispatch
case DF_CoreCmdKind_SelectThread:
+9
View File
@@ -681,6 +681,15 @@ struct DF_GfxState
DF_CmdSpec *bind_change_cmd_spec;
DF_Binding bind_change_binding;
// rjf: confirmation popup state
UI_Key confirm_key;
B32 confirm_active;
F32 confirm_t;
Arena *confirm_arena;
DF_CmdList confirm_cmds;
String8 confirm_title;
String8 confirm_msg;
// rjf: string search state
Arena *string_search_arena;
String8 string_search_string;
+1 -1
View File
@@ -66,7 +66,7 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data)
U64 begin_time_us = os_now_microseconds();
//- rjf: bind change
if(df_gfx_state->bind_change_active)
if(!df_gfx_state->confirm_active && df_gfx_state->bind_change_active)
{
if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Esc))
{
+4 -2
View File
@@ -2568,8 +2568,10 @@ ui_signal_from_box(UI_Box *box)
}
//- rjf: set hovering status
result.hovering = mouse_is_over && (ui_key_match(ui_state->active_box_key[Side_Min], ui_key_zero()) ||
ui_key_match(ui_state->active_box_key[Side_Min], box->key));
result.hovering = mouse_is_over && ((ui_key_match(ui_state->hot_box_key, ui_key_zero()) ||
ui_key_match(ui_state->hot_box_key, box->key)) &&
(ui_key_match(ui_state->active_box_key[Side_Min], ui_key_zero()) ||
ui_key_match(ui_state->active_box_key[Side_Min], box->key)));
result.mouse_over = mouse_is_over;
//- rjf: clicking in default nav -> set navigation state to this box