add display-grouped to hover
This commit is contained in:
parent
7385210e66
commit
fdbfcbc3a6
2 changed files with 156 additions and 59 deletions
210
src/hover.cpp
210
src/hover.cpp
|
@ -14,14 +14,14 @@ template <> u64 bswap_if_needed(u64 x) { return bswap(x); }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, T val)
|
String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, T val)
|
||||||
{
|
{
|
||||||
|
static_assert(!std::is_same_v<T, String8>);
|
||||||
val = bswap_if_needed(val);
|
val = bswap_if_needed(val);
|
||||||
return push_str8_node_child(arena, prev, fmt, val);
|
return push_str8_node_child(arena, prev, fmt, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
String8_Node *hover_display_val_str8(Arena *arena, String8_Node *prev, const char *fmt, String8 val)
|
||||||
String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, String8 val)
|
|
||||||
{
|
{
|
||||||
return push_str8_node_child(arena, prev, fmt, val.c());
|
return push_str8_node_child(arena, prev, fmt, val.str ? val.c() : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -86,6 +86,16 @@ String8_Node *display_val_rootzip(Arena *arena, String8_Node *prev, const char *
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using Display_Fn = String8_Node *(*)(Arena *, String8_Node *, const char *, T);
|
using Display_Fn = String8_Node *(*)(Arena *, String8_Node *, const char *, T);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
internal
|
||||||
|
T read_buf(const void *buf, u64 &off)
|
||||||
|
{
|
||||||
|
T val;
|
||||||
|
memcpy(&val, (u8 *)buf + off, sizeof(val));
|
||||||
|
off += sizeof(val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
// Functor used by get_section_hover_info to describe the structure of a section and print data about it.
|
// Functor used by get_section_hover_info to describe the structure of a section and print data about it.
|
||||||
struct Sec_Hover_Fn {
|
struct Sec_Hover_Fn {
|
||||||
u64 start;
|
u64 start;
|
||||||
|
@ -94,6 +104,7 @@ struct Sec_Hover_Fn {
|
||||||
Arena *arena;
|
Arena *arena;
|
||||||
Sec_Hover_Info &info;
|
Sec_Hover_Info &info;
|
||||||
u64 &cur_field_off;
|
u64 &cur_field_off;
|
||||||
|
b8 display_grouped;
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
b8 titled_section(const char *title, F &&fn) const
|
b8 titled_section(const char *title, F &&fn) const
|
||||||
|
@ -110,6 +121,31 @@ struct Sec_Hover_Fn {
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T add_to_desc(const char *fmt, Display_Fn<T> display_val = hover_display_val_le<T>) const
|
||||||
|
{
|
||||||
|
static_assert(!std::is_same_v<T, String8>, "use add_to_desc_str8 instead.");
|
||||||
|
T val = read_buf<T>(data + start, cur_field_off);
|
||||||
|
display_val(arena, info.desc, fmt, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TStrSize>
|
||||||
|
String8 add_to_desc_str8(const char *fmt, Display_Fn<String8> display_val = hover_display_val_str8) const
|
||||||
|
{
|
||||||
|
TStrSize str_size = read_buf<TStrSize>(data + start, cur_field_off);
|
||||||
|
u8 *buf = nullptr;
|
||||||
|
if (str_size > 0) {
|
||||||
|
buf = arena_push_array_nozero<u8>(arena, str_size + 1);
|
||||||
|
memcpy(buf, data + start + cur_field_off, str_size);
|
||||||
|
buf[str_size] = 0;
|
||||||
|
cur_field_off += str_size;
|
||||||
|
}
|
||||||
|
String8 s = { buf, str_size };
|
||||||
|
display_val(arena, info.desc, fmt, s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
b8 field(const char *desc_fmt, Display_Fn<T> display_val) const
|
b8 field(const char *desc_fmt, Display_Fn<T> display_val) const
|
||||||
{
|
{
|
||||||
|
@ -117,9 +153,7 @@ struct Sec_Hover_Fn {
|
||||||
u64 field_len = sizeof(T);
|
u64 field_len = sizeof(T);
|
||||||
if (roff < cur_field_off + field_len) {
|
if (roff < cur_field_off + field_len) {
|
||||||
info.rng = { start + cur_field_off, field_len };
|
info.rng = { start + cur_field_off, field_len };
|
||||||
T val;
|
add_to_desc<T>(desc_fmt, display_val);
|
||||||
memcpy(&val, data + info.rng.start, info.rng.len);
|
|
||||||
display_val(arena, info.desc, desc_fmt, val);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
cur_field_off += field_len;
|
cur_field_off += field_len;
|
||||||
|
@ -139,14 +173,11 @@ struct Sec_Hover_Fn {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TStrSize>
|
template <typename TStrSize>
|
||||||
b8 field_str8(const char *desc_fmt, Display_Fn<String8> display_val = hover_display_val_be<String8>) const
|
b8 field_str8(const char *desc_fmt, Display_Fn<String8> display_val = hover_display_val_str8) const
|
||||||
{
|
{
|
||||||
// String size can be stored as different types, like u8 (by ROOT I/O) or u32 (by RNTuple).
|
// String size can be stored as different types, like u8 (by ROOT I/O) or u32 (by RNTuple).
|
||||||
TStrSize str_size;
|
TStrSize str_size;
|
||||||
memcpy(&str_size, data + start + cur_field_off, sizeof(TStrSize));
|
memcpy(&str_size, data + start + cur_field_off, sizeof(TStrSize));
|
||||||
// TEMP DEBUG
|
|
||||||
if (str_size > 1000)
|
|
||||||
return false;
|
|
||||||
if (roff < cur_field_off + sizeof(TStrSize) + str_size) {
|
if (roff < cur_field_off + sizeof(TStrSize) + str_size) {
|
||||||
info.rng = { start + cur_field_off, sizeof(TStrSize) + (u64)str_size };
|
info.rng = { start + cur_field_off, sizeof(TStrSize) + (u64)str_size };
|
||||||
u8 *buf = arena_push_array_nozero<u8>(arena, str_size + 1);
|
u8 *buf = arena_push_array_nozero<u8>(arena, str_size + 1);
|
||||||
|
@ -279,61 +310,124 @@ struct Sec_Hover_Fn {
|
||||||
static const char *const field_struct_names[] = {
|
static const char *const field_struct_names[] = {
|
||||||
"Leaf", "Collection", "Record", "Variant", "Unsplit"
|
"Leaf", "Collection", "Record", "Variant", "Unsplit"
|
||||||
};
|
};
|
||||||
return titled_section("Field", [this] {
|
|
||||||
u64 flags_off = start + cur_field_off + 22;
|
if (display_grouped) {
|
||||||
u16 flags;
|
i64 size;
|
||||||
memcpy(&flags, data + flags_off, sizeof(flags));
|
memcpy(&size, data + start + cur_field_off, sizeof(size));
|
||||||
b8 ok = field_le<i64>("Size: %" PRIi64)
|
u64 field_desc_len = (u64)std::abs(size);
|
||||||
|| field_le<u32>("Field version: %u")
|
if (roff < cur_field_off + field_desc_len) {
|
||||||
|| field_le<u32>("Type version: %u")
|
return titled_section("Field", [this, field_desc_len] {
|
||||||
|| field_le<u32>("On-disk parent id: %u")
|
info.rng = { start + cur_field_off, (u64)field_desc_len };
|
||||||
|| field<u16>("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) {
|
add_to_desc<i64>("Size: %" PRIi64);
|
||||||
|
add_to_desc<u32>("Field version: %u");
|
||||||
|
add_to_desc<u32>("Type version: %u");
|
||||||
|
add_to_desc<u32>("On-disk parent id: %u");
|
||||||
|
add_to_desc<u16>("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) {
|
||||||
const char *name = (type >= countof(field_struct_names)) ? "Unknown" : field_struct_names[type];
|
const char *name = (type >= countof(field_struct_names)) ? "Unknown" : field_struct_names[type];
|
||||||
return push_str8_node_child(arena, prev, fmt, name);
|
return push_str8_node_child(arena, prev, fmt, name);
|
||||||
})
|
});
|
||||||
|| field_le<u16>("Flags: 0b%b")
|
u16 flags = add_to_desc<u16>("Flags: 0b%b");
|
||||||
;
|
|
||||||
if (ok)
|
|
||||||
return ok;
|
|
||||||
|
|
||||||
if ((flags & RNTupleSerializer::kFlagRepetitiveField) && field_le<u64>("N Repetitions: %" PRIu64))
|
if (flags & RNTupleSerializer::kFlagRepetitiveField)
|
||||||
return true;
|
add_to_desc<u64>("N Repetitions: %" PRIu64);
|
||||||
if ((flags & RNTupleSerializer::kFlagProjectedField) && field_le<u32>("On disk proj.src id: %u"))
|
if (flags & RNTupleSerializer::kFlagProjectedField)
|
||||||
return true;
|
add_to_desc<u32>("On disk proj.src id: %u");
|
||||||
if ((flags & RNTupleSerializer::kFlagHasTypeChecksum) && field_le<u32>("Checksum: %u"))
|
if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
|
||||||
return true;
|
add_to_desc<u32>("Checksum: %u");
|
||||||
|
|
||||||
return field_str8<u32>("Name: %s")
|
add_to_desc_str8<u32>("Name: %s");
|
||||||
|| field_str8<u32>("Type Name: %s")
|
add_to_desc_str8<u32>("Type Name: %s");
|
||||||
|| field_str8<u32>("Type Alias: %s")
|
add_to_desc_str8<u32>("Type Alias: %s");
|
||||||
|| field_str8<u32>("Description: %s")
|
add_to_desc_str8<u32>("Description: %s");
|
||||||
;
|
|
||||||
});
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
cur_field_off += field_desc_len;
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return titled_section("Field", [this] {
|
||||||
|
u64 flags_off = start + cur_field_off + 22;
|
||||||
|
u16 flags;
|
||||||
|
memcpy(&flags, data + flags_off, sizeof(flags));
|
||||||
|
b8 ok = field_le<i64>("Size: %" PRIi64)
|
||||||
|
|| field_le<u32>("Field version: %u")
|
||||||
|
|| field_le<u32>("Type version: %u")
|
||||||
|
|| field_le<u32>("On-disk parent id: %u")
|
||||||
|
|| field<u16>("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) {
|
||||||
|
const char *name = (type >= countof(field_struct_names)) ? "Unknown" : field_struct_names[type];
|
||||||
|
return push_str8_node_child(arena, prev, fmt, name);
|
||||||
|
})
|
||||||
|
|| field_le<u16>("Flags: 0b%b")
|
||||||
|
;
|
||||||
|
if (ok)
|
||||||
|
return ok;
|
||||||
|
|
||||||
|
if ((flags & RNTupleSerializer::kFlagRepetitiveField) && field_le<u64>("N Repetitions: %" PRIu64))
|
||||||
|
return true;
|
||||||
|
if ((flags & RNTupleSerializer::kFlagProjectedField) && field_le<u32>("On disk proj.src id: %u"))
|
||||||
|
return true;
|
||||||
|
if ((flags & RNTupleSerializer::kFlagHasTypeChecksum) && field_le<u32>("Checksum: %u"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return field_str8<u32>("Name: %s")
|
||||||
|
|| field_str8<u32>("Type Name: %s")
|
||||||
|
|| field_str8<u32>("Type Alias: %s")
|
||||||
|
|| field_str8<u32>("Description: %s")
|
||||||
|
;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b8 column_desc() const
|
b8 column_desc() const
|
||||||
{
|
{
|
||||||
return titled_section("Column", [this] {
|
if (display_grouped) {
|
||||||
u64 flags_off = start + cur_field_off + 16;
|
i64 size;
|
||||||
u16 flags;
|
memcpy(&size, data + start + cur_field_off, sizeof(size));
|
||||||
memcpy(&flags, data + flags_off, sizeof(flags));
|
u64 col_desc_len = (u64)std::abs(size);
|
||||||
b8 ok = field_le<i64>("Size: %" PRIi64)
|
if (roff < cur_field_off + col_desc_len) {
|
||||||
|| field_le<u16>("Column Type: 0x%X") // TODO: prettify name
|
return titled_section("Column", [this, col_desc_len] {
|
||||||
|| field_le<u16>("Bits on storage: %u")
|
info.rng = { start + cur_field_off, col_desc_len };
|
||||||
|| field_le<u32>("Field ID: %u")
|
add_to_desc<i64>("Size: %" PRIi64 " B");
|
||||||
|| field_le<u16>("Flags: 0b%b")
|
add_to_desc<u16>("Column type: %u"); // TODO: human-readable type
|
||||||
|| field_le<u16>("Representation idx: %u")
|
add_to_desc<u16>("Bits on storage: %u");
|
||||||
;
|
add_to_desc<u32>("Field ID: %u");
|
||||||
if (ok)
|
u16 flags = add_to_desc<u16>("Flags: 0b%b");
|
||||||
return ok;
|
add_to_desc<u16>("Representation idx: %u");
|
||||||
|
if (flags & RNTupleSerializer::kFlagDeferredColumn)
|
||||||
if ((flags & RNTupleSerializer::kFlagDeferredColumn) && field_le<u64>("First element: %" PRIu64))
|
add_to_desc<u64>("First element: %" PRIu64);
|
||||||
return true;
|
// if (flags & RNTupleSerializer::kFlagHasValueRange) {
|
||||||
if ((flags & RNTupleSerializer::kFlagHasValueRange) && (field_le<double>("Value Min: %f") || field_le<double>("Value Max: %f")))
|
// add_to_desc<double>("Value Min: %f");
|
||||||
return true;
|
// add_to_desc<double>("Value Max: %f");
|
||||||
|
// }
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
cur_field_off += col_desc_len;
|
||||||
return false;
|
return false;
|
||||||
});
|
} else {
|
||||||
|
return titled_section("Column", [this] {
|
||||||
|
u64 flags_off = start + cur_field_off + 16;
|
||||||
|
u16 flags;
|
||||||
|
memcpy(&flags, data + flags_off, sizeof(flags));
|
||||||
|
b8 ok = field_le<i64>("Size: %" PRIi64)
|
||||||
|
|| field_le<u16>("Column Type: 0x%X") // TODO: prettify name
|
||||||
|
|| field_le<u16>("Bits on storage: %u")
|
||||||
|
|| field_le<u32>("Field ID: %u")
|
||||||
|
|| field_le<u16>("Flags: 0b%b")
|
||||||
|
|| field_le<u16>("Representation idx: %u")
|
||||||
|
;
|
||||||
|
if (ok)
|
||||||
|
return ok;
|
||||||
|
|
||||||
|
if ((flags & RNTupleSerializer::kFlagDeferredColumn) && field_le<u64>("First element: %" PRIu64))
|
||||||
|
return true;
|
||||||
|
// if ((flags & RNTupleSerializer::kFlagHasValueRange) && (field_le<double>("Value Min: %f") || field_le<double>("Value Max: %f")))
|
||||||
|
// return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b8 schema_description() const
|
b8 schema_description() const
|
||||||
|
@ -369,7 +463,7 @@ struct Sec_Hover_Fn {
|
||||||
|
|
||||||
// `off` is the absolute offset into `data`.
|
// `off` is the absolute offset into `data`.
|
||||||
internal
|
internal
|
||||||
Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data)
|
Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data, b8 display_grouped)
|
||||||
{
|
{
|
||||||
Sec_Hover_Info info {};
|
Sec_Hover_Info info {};
|
||||||
|
|
||||||
|
@ -393,7 +487,7 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co
|
||||||
u64 start = section.range.start - section.pre_size;
|
u64 start = section.range.start - section.pre_size;
|
||||||
u64 roff = off - start; // offset relative to `section`
|
u64 roff = off - start; // offset relative to `section`
|
||||||
u64 cur_field_off = 0;
|
u64 cur_field_off = 0;
|
||||||
Sec_Hover_Fn hover { start, roff, data, arena, info, cur_field_off };
|
Sec_Hover_Fn hover { start, roff, data, arena, info, cur_field_off, display_grouped };
|
||||||
|
|
||||||
switch (section.id) {
|
switch (section.id) {
|
||||||
case Sec_RNTuple_Anchor: {
|
case Sec_RNTuple_Anchor: {
|
||||||
|
|
|
@ -387,7 +387,10 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
|
||||||
if (hovered_off)
|
if (hovered_off)
|
||||||
{
|
{
|
||||||
Section hovered_section = find_section(app, hovered_off - 1);
|
Section hovered_section = find_section(app, hovered_off - 1);
|
||||||
Sec_Hover_Info hover_info = get_section_hover_info(scratch.arena, hovered_section, hovered_off - 1, app.inspected_file.mem);
|
b8 hover_display_grouped = !(app.user_input.key_state[KEY_ALT] & KEY_STATE_IS_DOWN);
|
||||||
|
Sec_Hover_Info hover_info = get_section_hover_info(scratch.arena, hovered_section, hovered_off - 1,
|
||||||
|
app.inspected_file.mem, hover_display_grouped);
|
||||||
|
ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "(Hint: press Alt for single-field hover information)");
|
||||||
imgui_render_string_tree(scratch.arena, hover_info.desc->head);
|
imgui_render_string_tree(scratch.arena, hover_info.desc->head);
|
||||||
app.viewer.hovered_range = hover_info.rng;
|
app.viewer.hovered_range = hover_info.rng;
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue