memory view go-to-address / cursor/mark tracking fixes

This commit is contained in:
Ryan Fleury
2025-06-06 12:09:07 -07:00
parent 60d88ac446
commit 2d9929452c
3 changed files with 201 additions and 189 deletions
+1 -1
View File
@@ -419,7 +419,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[24] =
{str8_lit_comp("watch"), str8_lit_comp("@inherit(tab) x:\n{\n @override @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n 'label': code_string,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': expr_string,\n @no_expand 'watches': query,\n}\n")}, {str8_lit_comp("watch"), str8_lit_comp("@inherit(tab) x:\n{\n @override @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n 'label': code_string,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': expr_string,\n @no_expand 'watches': query,\n}\n")},
{str8_lit_comp("text"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': expr_string,\n @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': code_string,\n @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description(\"Scrolls to the bottom if the text is changed.\")\n 'scroll_to_bottom_on_change':bool,\n @no_callee_helper @no_revert @default(0) @display_name('Transient') @description(\"Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.\")\n 'auto': bool,\n}\n")}, {str8_lit_comp("text"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': expr_string,\n @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': code_string,\n @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description(\"Scrolls to the bottom if the text is changed.\")\n 'scroll_to_bottom_on_change':bool,\n @no_callee_helper @no_revert @default(0) @display_name('Transient') @description(\"Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.\")\n 'auto': bool,\n}\n")},
{str8_lit_comp("disasm"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the disassembly.\")\n 'expression': expr_string,\n 'arch': code_string,\n 'syntax': code_string,\n 'size': expr_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not addresses are shown in the disassembly text.\")\n 'show_addresses': bool,\n @no_callee_helper @default(0) @description(\"Controls whether or not code bytes are shown in the disassembly text.\")\n 'show_code_bytes': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not source lines, corresponding to disassembly instruction ranges, are shown in the disassembly text.\")\n 'show_source_lines': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not disassembly text is decorated with symbol names.\")\n 'show_symbol_names': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers': bool,\n}\n")}, {str8_lit_comp("disasm"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the disassembly.\")\n 'expression': expr_string,\n 'arch': code_string,\n 'syntax': code_string,\n 'size': expr_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not addresses are shown in the disassembly text.\")\n 'show_addresses': bool,\n @no_callee_helper @default(0) @description(\"Controls whether or not code bytes are shown in the disassembly text.\")\n 'show_code_bytes': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not source lines, corresponding to disassembly instruction ranges, are shown in the disassembly text.\")\n 'show_source_lines': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not disassembly text is decorated with symbol names.\")\n 'show_symbol_names': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers': bool,\n}\n")},
{str8_lit_comp("memory"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression which refers to the base address of data which should be viewed as memory.\")\n 'expression': expr_string,\n @display_name(\"Address Range Size\") @description(\"The number of bytes of the viewed memory range.\")\n 'size': expr_string,\n @display_name(\"Cursor Address\") @description(\"The address of the cursor.\")\n 'cursor': expr_string,\n @display_name(\"Cursor Size\") @description(\"The size, in bytes, of the cursor.\")\n 'cursor_size': @range[1, 16] u64,\n @default(16) @description(\"The number of columns to build before building new rows.\")\n 'num_columns': @range[1, 64] u64,\n}\n")}, {str8_lit_comp("memory"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression which refers to the base address of data which should be viewed as memory.\")\n 'expression': expr_string,\n @display_name(\"Address Range Size\") @description(\"The number of bytes of the viewed memory range.\")\n 'size': expr_string,\n @display_name(\"Cursor Address\") @description(\"The address of the cursor.\")\n 'cursor': expr_string,\n @display_name(\"Cursor Size\") @description(\"The size, in bytes, of the cursor.\")\n 'cursor_size': @range[1, 16] u64,\n @default(16) @description(\"The number of columns to build before building new rows.\")\n 'num_columns': @range[1, 64] u64,\n @default(1) @display_name(\"Track Mark To Cursor\") @description(\"Ensures that the mark always follows the cursor, if the cursor value is updated.\")\n 'track_mark_to_cursor': bool,\n}\n")},
{str8_lit_comp("bitmap"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression which refers to the base address of data which should be viewed as a bitmap.\")\n 'expression': expr_string,\n @description(\"An expression describing the width of the bitmap, in pixels.\") @order(0) 'w': u64,\n @description(\"An expression describing the height of the bitmap, in pixels.\") @order(1) 'h': u64,\n @display_name(\"Bitmap Format\") @description(\"The pixel format that the bitmap data should be interpreted as being within.\")\n 'fmt': code_string,\n}\n")}, {str8_lit_comp("bitmap"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression which refers to the base address of data which should be viewed as a bitmap.\")\n 'expression': expr_string,\n @description(\"An expression describing the width of the bitmap, in pixels.\") @order(0) 'w': u64,\n @description(\"An expression describing the height of the bitmap, in pixels.\") @order(1) 'h': u64,\n @display_name(\"Bitmap Format\") @description(\"The pixel format that the bitmap data should be interpreted as being within.\")\n 'fmt': code_string,\n}\n")},
{str8_lit_comp("color"), str8_lit_comp("@inherit(tab) x:\n{\n @display_name(\"Value\") @description(\"An expression to describe the value or location of the color.\")\n 'expression': expr_string,\n}\n")}, {str8_lit_comp("color"), str8_lit_comp("@inherit(tab) x:\n{\n @display_name(\"Value\") @description(\"An expression to describe the value or location of the color.\")\n 'expression': expr_string,\n}\n")},
{str8_lit_comp("geo3d"), str8_lit_comp("@inherit(tab) x:\n{\n @display_name(\"Expression\") @description(\"An expression to describe the base address of the index buffer.\")\n 'expression': expr_string,\n 'count': expr_string,\n 'vtx': expr_string,\n 'vtx_size': expr_string,\n 'yaw': @range[0, 1] f32,\n 'pitch': @range[-0.5, 0] f32,\n 'zoom': @range[0, 100] f32,\n}\n")}, {str8_lit_comp("geo3d"), str8_lit_comp("@inherit(tab) x:\n{\n @display_name(\"Expression\") @description(\"An expression to describe the base address of the index buffer.\")\n 'expression': expr_string,\n 'count': expr_string,\n 'vtx': expr_string,\n 'vtx_size': expr_string,\n 'yaw': @range[0, 1] f32,\n 'pitch': @range[-0.5, 0] f32,\n 'zoom': @range[0, 100] f32,\n}\n")},
+2
View File
@@ -517,6 +517,8 @@ RD_VocabTable:
'cursor_size': @range[1, 16] u64, 'cursor_size': @range[1, 16] u64,
@default(16) @description("The number of columns to build before building new rows.") @default(16) @description("The number of columns to build before building new rows.")
'num_columns': @range[1, 64] u64, 'num_columns': @range[1, 64] u64,
@default(1) @display_name("Track Mark To Cursor") @description("Ensures that the mark always follows the cursor, if the cursor value is updated.")
'track_mark_to_cursor': bool,
} }
``` ```
} }
+87 -77
View File
@@ -2536,6 +2536,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
U64 initial_cursor_base_vaddr = cursor_base_vaddr; U64 initial_cursor_base_vaddr = cursor_base_vaddr;
U64 initial_mark_base_vaddr = mark_base_vaddr; U64 initial_mark_base_vaddr = mark_base_vaddr;
U64 num_columns = rd_view_setting_u64_from_name(str8_lit("num_columns")); U64 num_columns = rd_view_setting_u64_from_name(str8_lit("num_columns"));
B32 track_mark_to_cursor = rd_view_setting_b32_from_name(str8_lit("track_mark_to_cursor"));
if(num_columns == 0) if(num_columns == 0)
{ {
num_columns = 16; num_columns = 16;
@@ -2580,29 +2581,6 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
F32 row_height_px = floor_f32(font_size*2.f); F32 row_height_px = floor_f32(font_size*2.f);
F32 cell_width_px = floor_f32(font_size*2.f); F32 cell_width_px = floor_f32(font_size*2.f);
//////////////////////////////
//- rjf: determine legal scroll range
//
U64 view_range_last = view_range.max;
if(view_range_last != 0)
{
view_range_last -= 1;
}
Rng1S64 scroll_idx_rng = r1s64(0, (view_range_last - view_range.min) / num_columns);
//////////////////////////////
//- rjf: determine visible range of rows (including occluded)
//
Rng1S64 viz_range_rows = {0};
S64 num_possible_visible_rows = 0;
{
num_possible_visible_rows = dim_2f32(rect).y/row_height_px;
viz_range_rows.min = scroll_pos.y.idx + (S64)scroll_pos.y.off - !!(scroll_pos.y.off<0);
viz_range_rows.max = scroll_pos.y.idx + (S64)scroll_pos.y.off + num_possible_visible_rows,
viz_range_rows.min = clamp_1s64(scroll_idx_rng, viz_range_rows.min);
viz_range_rows.max = clamp_1s64(scroll_idx_rng, viz_range_rows.max);
}
////////////////////////////// //////////////////////////////
//- rjf: calculate rectangles //- rjf: calculate rectangles
// //
@@ -2614,41 +2592,52 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
Rng2F32 content_rect = r2f32p(0, row_height_px, panel_dim.x-scroll_bar_dim, panel_dim.y); Rng2F32 content_rect = r2f32p(0, row_height_px, panel_dim.x-scroll_bar_dim, panel_dim.y);
////////////////////////////// //////////////////////////////
//- rjf: determine visible range of rows (only non-occluded) //- rjf: determine visible range of rows (occluded & non-occluded)
// //
Rng1S64 viz_range_nonoccluded_rows = {0}; S64 num_possible_visible_rows = num_possible_visible_rows = dim_2f32(rect).y/row_height_px;;
S64 num_possible_nonoccluded_visible_rows = 0; S64 num_possible_nonoccluded_visible_rows = (dim_2f32(content_rect).y - dim_2f32(footer_rect).y) / row_height_px;
{
num_possible_nonoccluded_visible_rows = (dim_2f32(content_rect).y - dim_2f32(footer_rect).y) / row_height_px;
viz_range_nonoccluded_rows.min = viz_range_rows.min + (S64)(content_rect.y0 / row_height_px);
viz_range_nonoccluded_rows.max = viz_range_nonoccluded_rows.min + num_possible_nonoccluded_visible_rows;
viz_range_nonoccluded_rows.min = clamp_1s64(scroll_idx_rng, viz_range_nonoccluded_rows.min);
viz_range_nonoccluded_rows.max = clamp_1s64(scroll_idx_rng, viz_range_nonoccluded_rows.max);
}
////////////////////////////// //////////////////////////////
//- rjf: bump backwards if we are past the first //- rjf: determine legal scroll range
if(viz_range_rows.min > 0)
{
viz_range_rows.min -= 1;
content_rect.y0 -= row_height_px;
}
//////////////////////////////
//- rjf: determine visible range of bytes
// //
Rng1U64 viz_range_bytes = {0}; U64 view_range_last = view_range.max;
viz_range_bytes.min = view_range.min + (viz_range_rows.min)*num_columns; if(view_range_last != 0)
viz_range_bytes.max = view_range.min + (viz_range_rows.max+1)*num_columns+1;
if(viz_range_bytes.min > viz_range_bytes.max)
{ {
Swap(U64, viz_range_bytes.min, viz_range_bytes.max); view_range_last -= 1;
} }
viz_range_bytes = intersect_1u64(view_range, viz_range_bytes); Rng1S64 scroll_idx_rng = r1s64(0, (view_range_last - view_range.min) / num_columns);
////////////////////////////// //////////////////////////////
//- rjf: on cursor rugpull -> update mark if needed
//
{
Rng1U64 cursor_range = r1u64(cursor_base_vaddr, cursor_base_vaddr+cursor_size);
if(mv->last_cursor_range.min != cursor_range.min ||
mv->last_cursor_range.max != cursor_range.max)
{
mv->contain_cursor = 1;
if(track_mark_to_cursor)
{
mark_base_vaddr = cursor_base_vaddr;
}
}
}
//////////////////////////////
//- rjf: loop: compute boundaries, take events, repeat
//
B32 need_update = 1;
Rng1U64 cursor_valid_rng = {0};
for(;;)
{
//- rjf: break if no further updates needed
if(!need_update)
{
break;
}
need_update = 0;
//- rjf: take keyboard controls //- rjf: take keyboard controls
//
UI_Focus(UI_FocusKind_On) if(ui_is_focus_active()) UI_Focus(UI_FocusKind_On) if(ui_is_focus_active())
{ {
U64 next_cursor_base_vaddr = cursor_base_vaddr; U64 next_cursor_base_vaddr = cursor_base_vaddr;
@@ -2718,6 +2707,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
} }
if(good_action) if(good_action)
{ {
need_update = 1;
mv->contain_cursor = 1; mv->contain_cursor = 1;
ui_eat_event(evt); ui_eat_event(evt);
} }
@@ -2726,10 +2716,8 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
mark_base_vaddr = next_mark_base_vaddr; mark_base_vaddr = next_mark_base_vaddr;
} }
//////////////////////////////
//- rjf: clamp cursor //- rjf: clamp cursor
// cursor_valid_rng = view_range;
Rng1U64 cursor_valid_rng = view_range;
if(cursor_valid_rng.max != 0) if(cursor_valid_rng.max != 0)
{ {
cursor_valid_rng.max -= 1; cursor_valid_rng.max -= 1;
@@ -2743,17 +2731,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
mark_base_vaddr = clamp_1u64(cursor_valid_rng, mark_base_vaddr); mark_base_vaddr = clamp_1u64(cursor_valid_rng, mark_base_vaddr);
} }
//////////////////////////////
//- rjf: unpack post-move cursor/mark info
//
Rng1U64 cursor_range = r1u64(cursor_base_vaddr, cursor_base_vaddr + cursor_size);
Rng1U64 mark_range = r1u64(mark_base_vaddr, mark_base_vaddr + cursor_size);
Rng1U64 selection = union_1u64(r1u64(cursor_base_vaddr, cursor_base_vaddr+cursor_size-1),
r1u64(mark_base_vaddr, mark_base_vaddr+cursor_size-1));
//////////////////////////////
//- rjf: center cursor if range has changed //- rjf: center cursor if range has changed
//
if(mv->last_view_range.max != view_range.max || if(mv->last_view_range.max != view_range.max ||
mv->last_view_range.min != view_range.min) mv->last_view_range.min != view_range.min)
{ {
@@ -2761,20 +2739,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
mv->last_view_range = view_range; mv->last_view_range = view_range;
} }
//////////////////////////////
//- rjf: match mark to cursor if cursor has changed
//
if(mv->last_cursor_range.min != cursor_range.min ||
mv->last_cursor_range.max != cursor_range.max)
{
mv->contain_cursor = 1;
mv->last_cursor_range = cursor_range;
mark_range = cursor_range;
}
//////////////////////////////
//- rjf: center cursor //- rjf: center cursor
//
if(mv->center_cursor) if(mv->center_cursor)
{ {
mv->center_cursor = 0; mv->center_cursor = 0;
@@ -2784,12 +2749,15 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
ui_scroll_pt_target_idx(&scroll_pos.y, new_idx); ui_scroll_pt_target_idx(&scroll_pos.y, new_idx);
} }
//////////////////////////////
//- rjf: contain cursor //- rjf: contain cursor
//
if(mv->contain_cursor) if(mv->contain_cursor)
{ {
mv->contain_cursor = 0; mv->contain_cursor = 0;
Rng1S64 viz_range_nonoccluded_rows = {0};
viz_range_nonoccluded_rows.min = scroll_pos.y.idx + (S64)(content_rect.y0 / row_height_px);
viz_range_nonoccluded_rows.max = viz_range_nonoccluded_rows.min + num_possible_nonoccluded_visible_rows;
viz_range_nonoccluded_rows.min = clamp_1s64(scroll_idx_rng, viz_range_nonoccluded_rows.min);
viz_range_nonoccluded_rows.max = clamp_1s64(scroll_idx_rng, viz_range_nonoccluded_rows.max);
S64 cursor_row_idx = (cursor_base_vaddr - view_range.min) / num_columns; S64 cursor_row_idx = (cursor_base_vaddr - view_range.min) / num_columns;
Rng1S64 cursor_viz_range = r1s64(clamp_1s64(scroll_idx_rng, cursor_row_idx-2), clamp_1s64(scroll_idx_rng, cursor_row_idx+3)); Rng1S64 cursor_viz_range = r1s64(clamp_1s64(scroll_idx_rng, cursor_row_idx-2), clamp_1s64(scroll_idx_rng, cursor_row_idx+3));
S64 min_delta = Min(0, cursor_viz_range.min-viz_range_nonoccluded_rows.min); S64 min_delta = Min(0, cursor_viz_range.min-viz_range_nonoccluded_rows.min);
@@ -2798,6 +2766,47 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
new_idx = clamp_1s64(scroll_idx_rng, new_idx); new_idx = clamp_1s64(scroll_idx_rng, new_idx);
ui_scroll_pt_target_idx(&scroll_pos.y, new_idx); ui_scroll_pt_target_idx(&scroll_pos.y, new_idx);
} }
}
////////////////////////////
//- rjf: determine selection
//
Rng1U64 selection = union_1u64(r1u64(cursor_base_vaddr, cursor_base_vaddr+cursor_size-1),
r1u64(mark_base_vaddr, mark_base_vaddr+cursor_size-1));
////////////////////////////
//- rjf: determine visible range of rows (including occluded)
//
Rng1S64 viz_range_rows = {0};
{
viz_range_rows.min = scroll_pos.y.idx + (S64)scroll_pos.y.off - !!(scroll_pos.y.off<0);
viz_range_rows.max = scroll_pos.y.idx + (S64)scroll_pos.y.off + num_possible_visible_rows,
viz_range_rows.min = clamp_1s64(scroll_idx_rng, viz_range_rows.min);
viz_range_rows.max = clamp_1s64(scroll_idx_rng, viz_range_rows.max);
}
////////////////////////////
//- rjf: bump backwards if we are past the first
//
if(viz_range_rows.min > 0)
{
viz_range_rows.min -= 1;
content_rect.y0 -= row_height_px;
}
////////////////////////////
//- rjf: determine visible range of bytes
//
Rng1U64 viz_range_bytes = {0};
{
viz_range_bytes.min = view_range.min + (viz_range_rows.min)*num_columns;
viz_range_bytes.max = view_range.min + (viz_range_rows.max+1)*num_columns+1;
if(viz_range_bytes.min > viz_range_bytes.max)
{
Swap(U64, viz_range_bytes.min, viz_range_bytes.max);
}
viz_range_bytes = intersect_1u64(view_range, viz_range_bytes);
}
////////////////////////////// //////////////////////////////
//- rjf: produce fancy strings for all possible byte values in all cells //- rjf: produce fancy strings for all possible byte values in all cells
@@ -3414,6 +3423,7 @@ RD_VIEW_UI_FUNCTION_DEF(memory)
////////////////////////////// //////////////////////////////
//- rjf: save parameters //- rjf: save parameters
// //
mv->last_cursor_range = r1u64(cursor_base_vaddr, cursor_base_vaddr + cursor_size);
if(cursor_base_vaddr != initial_cursor_base_vaddr) if(cursor_base_vaddr != initial_cursor_base_vaddr)
{ {
rd_store_view_param_u64(str8_lit("cursor"), cursor_base_vaddr); rd_store_view_param_u64(str8_lit("cursor"), cursor_base_vaddr);