add section focus/expansion
This commit is contained in:
parent
4d06065933
commit
a39bad260e
7 changed files with 111 additions and 23 deletions
|
@ -37,6 +37,9 @@ struct App_State {
|
|||
#endif
|
||||
|
||||
String8 ntpl_name;
|
||||
// This is used:
|
||||
// - in interactive mode: for aux section management
|
||||
// - in terminal mode: to know which is the first byte to display
|
||||
u64 base_display_addr;
|
||||
|
||||
Delta_Time_Accum delta_time_accum;
|
||||
|
|
|
@ -12,7 +12,7 @@ void print_help(const char *argv0)
|
|||
"\n\t-l: display LEN bytes (only in terminal mode)"
|
||||
"\n\t-k: print information about the TKeys in the file and exit"
|
||||
"\n\t-n: list the names of the RNTuples found in the file and exit"
|
||||
"\n\t-s: set first displayed byte to START"
|
||||
"\n\t-s: set first displayed byte to START (only in terminal mode)"
|
||||
"\n\t-t: no graphics, output to terminal"
|
||||
"\n\t-v: print version and copyright info"
|
||||
"\n\t-w: display WIDTH bytes per column"
|
||||
|
|
|
@ -170,10 +170,17 @@ void run_main_loop(GLFWwindow *window, Arena *arena, App_State &app)
|
|||
init_viewer_title(app.viewer, app.fdata, app.inspected_file.name);
|
||||
}
|
||||
|
||||
if ((app.user_input.key_state[KEY_ESC] & KEY_STATE_IS_DOWN) || glfwWindowShouldClose(window)) {
|
||||
app.should_quit = true; // superfluous right now, but set it just in case.
|
||||
break;
|
||||
if (app.user_input.key_state[KEY_ESC] & KEY_STATE_JUST_PRESSED) {
|
||||
if (app.viewer.aux.buf_size) {
|
||||
// We were viewing a subsection: back to the main view
|
||||
app.viewer.aux.buf_size = app.base_display_addr = 0;
|
||||
} else {
|
||||
app.should_quit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (glfwWindowShouldClose(window))
|
||||
app.should_quit = true;
|
||||
|
||||
b32 focused = glfwGetWindowAttrib(window, GLFW_FOCUSED);
|
||||
if (focused) {
|
||||
|
@ -186,6 +193,7 @@ void run_main_loop(GLFWwindow *window, Arena *arena, App_State &app)
|
|||
u8 *mouse_btn_state = app.user_input.mouse_btn_state;
|
||||
monitor_mouse_btn(window, mouse_btn_state, GLFW_MOUSE_BUTTON_LEFT, MOUSE_BTN_LEFT);
|
||||
monitor_mouse_btn(window, mouse_btn_state, GLFW_MOUSE_BUTTON_RIGHT, MOUSE_BTN_RIGHT);
|
||||
monitor_mouse_btn(window, mouse_btn_state, GLFW_MOUSE_BUTTON_MIDDLE, MOUSE_BTN_MIDDLE);
|
||||
|
||||
app.user_input.mouse_pos.x = static_cast<i32>(mposx);
|
||||
app.user_input.mouse_pos.y = static_cast<i32>(mposy);
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// NOTE: we reserve more space than kMAXZIPBUF for the aux buf so we can fit also a TKey
|
||||
// or other similar pre-section in the buffer.
|
||||
#define AUX_BUF_SIZE (2 * kMAXZIPBUF)
|
||||
|
||||
constexpr f32 max3(f32 a, f32 b, f32 c)
|
||||
{
|
||||
return (a > b) ? (a > c) ? a : (b > c) ? b : c : (b > c) ? b : c;
|
||||
|
@ -98,10 +102,10 @@ internal
|
|||
u32 mem_edit_bg_color_fn(const u8 *data, u64 off, void *user_data)
|
||||
{
|
||||
App_State *app = reinterpret_cast<App_State *>(user_data);
|
||||
off += app->base_display_addr;
|
||||
u64 abs_off = off + app->base_display_addr;
|
||||
|
||||
f32 brighten = 0;
|
||||
if (app->viewer.hovered_range.start <= off && off < app->viewer.hovered_range.end())
|
||||
if (app->viewer.hovered_range.start <= abs_off && abs_off < app->viewer.hovered_range.end())
|
||||
brighten = 0.3;
|
||||
|
||||
u32 col = highlight_zstd_header(data, off, *app, brighten);
|
||||
|
@ -109,7 +113,12 @@ u32 mem_edit_bg_color_fn(const u8 *data, u64 off, void *user_data)
|
|||
return col;
|
||||
|
||||
i64 hilite_cluster = app->viewer.highlight_cluster ? app->viewer.highlighted_cluster : -1;
|
||||
Section section = find_section(*app, off, hilite_cluster);
|
||||
Section section;
|
||||
if (app->viewer.aux.buf_size && off > app->viewer.aux.section.pre_size) {
|
||||
section = app->viewer.aux.section;
|
||||
} else {
|
||||
section = find_section(*app, abs_off, hilite_cluster);
|
||||
}
|
||||
|
||||
if (section.highlighted)
|
||||
return imcol(app->viewer.col_highlight, brighten);
|
||||
|
@ -184,6 +193,9 @@ void init_viewer(App_State &app, u16 n_cols)
|
|||
viewer.mem_edit = make_memory_editor(app, (i32)n_cols);
|
||||
init_viewer_title(viewer, app.fdata, app.inspected_file.name);
|
||||
|
||||
// This lives as long as the viewer (i.e. forever)
|
||||
viewer.aux.buf = (u8 *)malloc(AUX_BUF_SIZE);
|
||||
|
||||
#define COL(c, r, g, b) viewer.c[0] = r/255.0, viewer.c[1] = g/255.0, viewer.c[2] = b/255.0
|
||||
COL(col_key, 0, 100, 50);
|
||||
COL(col_page_start, 200, 0, 200);
|
||||
|
@ -361,7 +373,12 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
|
|||
|
||||
{
|
||||
f32 *c = app.viewer.col_title;
|
||||
ImGui::TextColored(ImColor(c[0], c[1], c[2]), "%s", app.viewer.title.c());
|
||||
String8 title = app.viewer.title;
|
||||
if (app.viewer.aux.buf_size)
|
||||
title = push_str8f(scratch.arena, "%s [viewing section \"%s\" at 0x%" PRIX64 "-0x%" PRIX64 "]", title.c(),
|
||||
section_names[app.viewer.aux.section.id].c(),
|
||||
app.base_display_addr, app.base_display_addr + app.viewer.aux.section_comp_size);
|
||||
ImGui::TextColored(ImColor(c[0], c[1], c[2]), "%s", title.c());
|
||||
}
|
||||
|
||||
// Draw stats
|
||||
|
@ -391,7 +408,7 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
|
|||
|
||||
ImGui::BeginTable("Hex View", 2, ImGuiTableFlags_Resizable);
|
||||
|
||||
u64 content_size = app.inspected_file.size - app.base_display_addr;
|
||||
u64 content_size = app.viewer.aux.buf_size ? app.viewer.aux.buf_size : app.inspected_file.size - app.base_display_addr;
|
||||
MemoryEditor::Sizes sizes;
|
||||
app.viewer.mem_edit.CalcSizes(sizes, content_size, app.base_display_addr);
|
||||
|
||||
|
@ -406,16 +423,21 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
|
|||
// 0 means "invalid", otherwise the actual offset is `hovered_off - 1`.
|
||||
u64 hovered_off = app.viewer.mem_edit.MouseHovered * (app.viewer.mem_edit.MouseHoveredAddr + 1);
|
||||
|
||||
if (LIKELY(app.inspected_file.size)) {
|
||||
assert(app.base_display_addr < app.inspected_file.size);
|
||||
void *content = app.inspected_file.mem + app.base_display_addr;
|
||||
app.last_pinfo = &invalid_pinfo;
|
||||
app.last_other_root_obj = &invalid_section;
|
||||
app.viewer.mem_edit.DrawContents(content, content_size, app.base_display_addr);
|
||||
} else {
|
||||
ImGui::Text("(File is empty)");
|
||||
|
||||
void *content = nullptr;
|
||||
if (app.viewer.aux.buf_size) {
|
||||
content = app.viewer.aux.buf;
|
||||
} else if (LIKELY(app.inspected_file.size)) {
|
||||
content = app.inspected_file.mem;
|
||||
}
|
||||
|
||||
if (LIKELY(content))
|
||||
app.viewer.mem_edit.DrawContents(content, content_size, 0);
|
||||
else
|
||||
ImGui::Text("(File is empty)");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
const ImGuiColorEditFlags edit_flags = ImGuiColorEditFlags_NoInputs|ImGuiColorEditFlags_NoLabel;
|
||||
|
||||
|
@ -535,21 +557,30 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
|
|||
|
||||
if (hovered_off)
|
||||
{
|
||||
ImGui::TextColored(ImColor(0.f, 0.65f, 0.f), "Offset: 0x%" PRIX64, hovered_off - 1);
|
||||
Section hovered_section = find_section(app, hovered_off - 1);
|
||||
b8 hover_display_grouped = !(app.user_input.key_state[KEY_ALT] & KEY_STATE_IS_DOWN);
|
||||
u64 abs_hovered_off = hovered_off - 1 + app.base_display_addr;
|
||||
ImGui::TextColored(ImColor(0.f, 0.65f, 0.f), "Offset: 0x%" PRIX64, abs_hovered_off);
|
||||
|
||||
Section hovered_section = app.viewer.aux.buf_size ? app.viewer.aux.section : find_section(app, hovered_off - 1);
|
||||
Section_Id sec_id = hovered_section.id;
|
||||
// NOTE: anchor/header/footer sections all have their *info point to their parent rntuple anchor info.
|
||||
b8 old_version =
|
||||
(sec_id == Sec_RNTuple_Anchor || sec_id == Sec_RNTuple_Header || sec_id == Sec_RNTuple_Footer) &&
|
||||
rntuple_is_old_version(((const RNTuple_Anchor_Info *)hovered_section.info)->anchor);
|
||||
b8 hover_display_grouped = !(app.user_input.key_state[KEY_ALT] & KEY_STATE_IS_DOWN);
|
||||
const u8 *section_info_data = app.viewer.aux.buf_size ? app.viewer.aux.buf : app.inspected_file.mem;
|
||||
Sec_Hover_Info hover_info = get_section_hover_info(scratch.arena, hovered_section, hovered_off - 1,
|
||||
app.inspected_file.mem, hover_display_grouped, old_version);
|
||||
section_info_data, hover_display_grouped, old_version);
|
||||
|
||||
ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "(Hint: hold Alt for single-field hover information)");
|
||||
ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "(Hint: Shift-Click to jump to the start of this section)");
|
||||
if (!app.viewer.aux.buf_size)
|
||||
ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "(Hint: Middle-Click to focus/expand current section)");
|
||||
else
|
||||
ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "(Hint: Escape to go back to full view)");
|
||||
if (hover_info.desc)
|
||||
imgui_render_string_tree(scratch.arena, hover_info.desc->head, hover_info.highlighted_desc);
|
||||
app.viewer.hovered_range = hover_info.rng;
|
||||
app.viewer.hovered_range.start += !!app.viewer.aux.buf_size * app.base_display_addr;
|
||||
|
||||
// Shift-clicking on a page section will update the current page in the legend
|
||||
if ((app.user_input.key_state[KEY_SHIFT] & KEY_STATE_IS_DOWN) &&
|
||||
|
@ -562,6 +593,38 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
|
|||
viewer_jump_to(app, hovered_section.range.start);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Handle section focusing/expanding.
|
||||
// This feature isolates a single section and displays it uncompressed, allowing individual values hovering
|
||||
// even for zipped payloads.
|
||||
//
|
||||
if (!app.viewer.aux.buf_size && (app.user_input.mouse_btn_state[MOUSE_BTN_MIDDLE] & MOUSE_BTN_STATE_JUST_PRESSED)) {
|
||||
// Check if this section is compressed; decompress it if it's the case.
|
||||
u8 *sec_buf = app.inspected_file.mem + hovered_section.range.start - hovered_section.pre_size;
|
||||
auto comp = R__getCompressionAlgorithm(sec_buf + hovered_section.pre_size, hovered_section.range.len);
|
||||
app.viewer.aux.section = hovered_section;
|
||||
app.base_display_addr = hovered_section.range.start - hovered_section.pre_size;
|
||||
app.viewer.aux.section.range.start = hovered_section.pre_size;
|
||||
app.viewer.aux.section_comp_size = hovered_section.range.len + hovered_section.pre_size;
|
||||
if (comp == ROOT::RCompressionSetting::EAlgorithm::kUndefined) {
|
||||
// Not a compressed block: just copy it to the aux buffer.
|
||||
app.viewer.aux.buf_size = hovered_section.range.len + hovered_section.pre_size;
|
||||
memcpy(app.viewer.aux.buf, sec_buf, min(AUX_BUF_SIZE, app.viewer.aux.buf_size));
|
||||
} else {
|
||||
// Copy over the pre-section (usually the TKey)
|
||||
memcpy(app.viewer.aux.buf, sec_buf, hovered_section.pre_size);
|
||||
|
||||
// Decompress the block
|
||||
i32 src_size = hovered_section.range.len;
|
||||
i32 tgt_size = kMAXZIPBUF;
|
||||
i32 unzipped_nbytes;
|
||||
R__unzip(&src_size, sec_buf + hovered_section.pre_size, &tgt_size,
|
||||
app.viewer.aux.buf + hovered_section.pre_size, &unzipped_nbytes);
|
||||
app.viewer.aux.buf_size = hovered_section.pre_size + unzipped_nbytes;
|
||||
app.viewer.aux.section.range.len = unzipped_nbytes;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app.viewer.hovered_range = {};
|
||||
}
|
||||
|
|
12
src/render.h
12
src/render.h
|
@ -1,3 +1,13 @@
|
|||
// Contains the data of the currently focused/expanded section (middle-click on the section)
|
||||
struct Viewer_Aux_Section {
|
||||
// This is an allocation AUX_BUF_SIZE wide.
|
||||
u8 *buf;
|
||||
// The aux section (i.e. all the data inside this struct) is considered valid if and only if this is > 0
|
||||
u64 buf_size;
|
||||
Section section;
|
||||
u64 section_comp_size;
|
||||
};
|
||||
|
||||
struct Viewer {
|
||||
// Imgui colors
|
||||
f32 col_section[Sec_COUNT][3];
|
||||
|
@ -27,6 +37,8 @@ struct Viewer {
|
|||
|
||||
// maps glfw keys to our keys
|
||||
Input_Key glfw_key_mapping[GLFW_KEY_LAST];
|
||||
|
||||
Viewer_Aux_Section aux;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -158,6 +158,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
app.ntpl_name = args.ntpl_name; // may be null
|
||||
if (!is_interactive)
|
||||
app.base_display_addr = args.start_addr;
|
||||
u32 walk_tkeys_flags = WTK_NONE;
|
||||
if (args.print_keys_info)
|
||||
|
|
|
@ -25,6 +25,7 @@ enum Key_State : u8 {
|
|||
enum Mouse_Button {
|
||||
MOUSE_BTN_LEFT,
|
||||
MOUSE_BTN_RIGHT,
|
||||
MOUSE_BTN_MIDDLE,
|
||||
MOUSE_BTN_COUNT
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue