add colors for header/footer
This commit is contained in:
parent
f683654ba0
commit
b9a490d8cc
15 changed files with 309 additions and 147 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,4 +3,5 @@ build/
|
|||
*.swo
|
||||
*.swp
|
||||
rntviewer
|
||||
*.gdbhist
|
||||
.gdbhist
|
||||
.gdb_history
|
||||
|
|
5
Makefile
5
Makefile
|
@ -13,7 +13,10 @@ build/imgui.o: src/imgui_inc.cpp third_party/imgui/imgui.h
|
|||
$(CXX) -O3 -fPIC -c -Ithird_party/imgui $< -o $@
|
||||
|
||||
d:
|
||||
$(MOLD) $(CXX) -DDEBUG -g -O0 $(CFLAGS) -fsanitize=undefined $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o -lasan $(ROOTLIBS) $(LIBS)
|
||||
$(MOLD) $(CXX) -DDEBUG -g -O0 -DENABLE_ASAN $(CFLAGS) -fsanitize=undefined $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o -lasan $(ROOTLIBS) $(LIBS)
|
||||
|
||||
noasan:
|
||||
$(MOLD) $(CXX) -DDEBUG -g -O0 $(CFLAGS) -fsanitize=undefined $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o $(ROOTLIBS) $(LIBS)
|
||||
|
||||
r:
|
||||
$(MOLD) $(CXX) -O2 $(CFLAGS) $(INC) $(ROOTFLAGS) -o rntviewer src/rntviewer.cpp build/imgui.o $(ROOTLIBS) $(LIBS)
|
||||
|
|
|
@ -8,7 +8,7 @@ Size=1152,1414
|
|||
|
||||
[Window][main]
|
||||
Pos=0,0
|
||||
Size=1143,1388
|
||||
Size=1775,680
|
||||
|
||||
[Window][Hex View]
|
||||
Pos=91,62
|
||||
|
|
|
@ -1,57 +1,23 @@
|
|||
enum Input_Key {
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
KEY_LEFT,
|
||||
KEY_RIGHT,
|
||||
KEY_Q,
|
||||
KEY_ALT,
|
||||
KEY_TAB,
|
||||
|
||||
KEY_COUNT
|
||||
};
|
||||
|
||||
enum Mouse_Button {
|
||||
MOUSE_BTN_LEFT,
|
||||
MOUSE_BTN_RIGHT,
|
||||
|
||||
MOUSE_BTN_COUNT
|
||||
};
|
||||
|
||||
enum Mouse_Button_State : u16 {
|
||||
MOUSE_BTN_STATE_IS_DOWN = 0x1,
|
||||
MOUSE_BTN_STATE_JUST_PRESSED = 0x2,
|
||||
MOUSE_BTN_STATE_JUST_RELEASED = 0x4,
|
||||
};
|
||||
|
||||
enum Key_State : u16 {
|
||||
KEY_STATE_IS_DOWN = 0x1,
|
||||
KEY_STATE_JUST_PRESSED = 0x2,
|
||||
KEY_STATE_JUST_RELEASED = 0x4,
|
||||
};
|
||||
|
||||
struct User_Input {
|
||||
u16 key_state[KEY_COUNT];
|
||||
|
||||
u16 mouse_btn_state[MOUSE_BTN_COUNT];
|
||||
struct { i32 x; i32 y; } mouse_pos;
|
||||
};
|
||||
|
||||
struct Window_Data {
|
||||
// Real width and height of the window
|
||||
i32 width;
|
||||
i32 height;
|
||||
bool size_just_changed;
|
||||
|
||||
f32 desired_aspect_ratio;
|
||||
};
|
||||
|
||||
struct App_State {
|
||||
Window_Data win_data;
|
||||
User_Input user_input;
|
||||
RNTuple_Info *rntinfo;
|
||||
|
||||
FILE *inspected_file;
|
||||
u8 *inspected_fmem;
|
||||
u64 inspected_file_size;
|
||||
// @Platform: inotify file descriptor
|
||||
int inot;
|
||||
|
||||
const char *ntpl_name;
|
||||
};
|
||||
|
||||
internal
|
||||
size_t file_size(FILE *f)
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t res = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
internal
|
||||
size_t file_size(FILE *f)
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t res = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
return res;
|
||||
}
|
||||
|
||||
internal
|
||||
void monitor_key(GLFWwindow *window, u16 *key_state, i32 glfw_key, Input_Key haru_key) {
|
||||
u16& state = key_state[haru_key];
|
||||
|
|
34
src/mem.cpp
34
src/mem.cpp
|
@ -4,7 +4,7 @@
|
|||
#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
|
||||
#define SLLStackPop_N(f,next) ((f)=(f)->next)
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef ENABLE_ASAN
|
||||
#define asan_poison_memory_region(mem, cmt) __asan_poison_memory_region(mem, cmt)
|
||||
#define asan_unpoison_memory_region(mem, cmt) __asan_unpoison_memory_region(mem, cmt)
|
||||
#else
|
||||
|
@ -12,27 +12,6 @@
|
|||
#define asan_unpoison_memory_region(mem, cmt)
|
||||
#endif
|
||||
|
||||
// @Platform
|
||||
internal
|
||||
void *os_reserve(u64 size)
|
||||
{
|
||||
return mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
// @Platform
|
||||
internal
|
||||
void os_release(void *mem, u64 size)
|
||||
{
|
||||
munmap(mem, size);
|
||||
}
|
||||
|
||||
// @Platform
|
||||
internal
|
||||
b32x os_commit(void *addr, u64 size)
|
||||
{
|
||||
return mprotect(addr, size, PROT_READ|PROT_WRITE) == 0;
|
||||
}
|
||||
|
||||
// init_res: initial reserved size
|
||||
// init_cmt: initial committed size
|
||||
internal
|
||||
|
@ -143,6 +122,15 @@ T *arena_push(Arena *arena)
|
|||
return (T *)mem;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
internal
|
||||
T *arena_push_zeroed(Arena *arena)
|
||||
{
|
||||
T *mem = arena_push<T>(arena);
|
||||
memset(mem, 0, sizeof(T));
|
||||
return mem;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
internal
|
||||
T *arena_push_array_no_zero(Arena *arena, u64 count)
|
||||
|
@ -181,7 +169,7 @@ u64 arena_pos(Arena *arena)
|
|||
internal
|
||||
void arena_pop_to(Arena *arena, u64 big_pos_unclamped)
|
||||
{
|
||||
u64 big_pos = min(ARENA_HEADER_SIZE, big_pos_unclamped);
|
||||
u64 big_pos = max(ARENA_HEADER_SIZE, big_pos_unclamped);
|
||||
|
||||
// unroll the chain
|
||||
Arena *current = arena->cur;
|
||||
|
|
65
src/platform_linux.h
Normal file
65
src/platform_linux.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include <sys/mman.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h> // for NAME_MAX
|
||||
|
||||
internal
|
||||
void os_open_and_map_file(const char *fname, App_State &app)
|
||||
{
|
||||
FILE *file = fopen(fname, "rb");
|
||||
int fd = fileno(file);
|
||||
size_t fsize = file_size(file);
|
||||
|
||||
void *fmem = mmap(0, fsize, PROT_READ, MAP_SHARED_VALIDATE, fd, 0);
|
||||
if (!fmem)
|
||||
fprintf(stderr, "Failed to open file %s\n", fname);
|
||||
|
||||
app.inspected_file = file;
|
||||
app.inspected_file_size = fsize;
|
||||
app.inspected_fmem = reinterpret_cast<u8*>(fmem);
|
||||
}
|
||||
|
||||
internal
|
||||
void os_unmap_file(u8 *&mem, u64 size)
|
||||
{
|
||||
if (mem) munmap(mem, size);
|
||||
mem = nullptr;
|
||||
}
|
||||
|
||||
internal
|
||||
void os_start_file_watch(const char *fname, App_State &app)
|
||||
{
|
||||
int inot = inotify_init1(IN_NONBLOCK);
|
||||
if (inot == -1)
|
||||
fprintf(stderr, "Failed to init inotify: %s (%d)\n", strerror(errno), errno);
|
||||
if (inotify_add_watch(inot, fname, IN_MODIFY) == -1)
|
||||
fprintf(stderr, "Failed to add inotify watch: %s (%d)\n", strerror(errno), errno);
|
||||
|
||||
app.inot = inot;
|
||||
}
|
||||
|
||||
internal
|
||||
void os_stop_file_watch(App_State &app)
|
||||
{
|
||||
if (app.inot != -1) close(app.inot);
|
||||
app.inot = -1;
|
||||
}
|
||||
|
||||
internal
|
||||
void *os_reserve(u64 size)
|
||||
{
|
||||
return mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
internal
|
||||
void os_release(void *mem, u64 size)
|
||||
{
|
||||
munmap(mem, size);
|
||||
}
|
||||
|
||||
internal
|
||||
b32x os_commit(void *addr, u64 size)
|
||||
{
|
||||
return mprotect(addr, size, PROT_READ|PROT_WRITE) == 0;
|
||||
}
|
||||
|
|
@ -1,34 +1,53 @@
|
|||
internal
|
||||
MemoryEditor make_memory_editor()
|
||||
u32 mem_edit_bg_color_fn(const u8 *data, u64 off, const void *user_data)
|
||||
{
|
||||
const RNTuple_Info *ntinfo = reinterpret_cast<const RNTuple_Info *>(user_data);
|
||||
|
||||
if (ntinfo->header.start <= off && off <= ntinfo->header.end())
|
||||
return IM_COL32(200, 0, 50, 255);
|
||||
if (ntinfo->footer.start <= off && off <= ntinfo->footer.end())
|
||||
return IM_COL32(50, 0, 200, 255);
|
||||
return IM_COL32(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
internal
|
||||
MemoryEditor make_memory_editor(const RNTuple_Info &ntpl_info)
|
||||
{
|
||||
MemoryEditor mem_edit;
|
||||
// mem_edit.ReadOnly = true;
|
||||
mem_edit.Cols = 32;
|
||||
mem_edit.BgColorFn = mem_edit_bg_color_fn;
|
||||
mem_edit.BgColorFnUserData = &ntpl_info;
|
||||
return mem_edit;
|
||||
}
|
||||
|
||||
internal
|
||||
void update_and_render(Arena *arena, App_State &app, f32 delta_time)
|
||||
{
|
||||
(void)delta_time;
|
||||
|
||||
ImGui::SetNextWindowPos({ 0, 0 });
|
||||
ImGui::SetNextWindowSize({ (f32)app.win_data.width, (f32)app.win_data.height });
|
||||
|
||||
Temp scratch = temp_begin(arena);
|
||||
defer { temp_end(scratch); };
|
||||
|
||||
u64 text_buf_size = min(app.inspected_file_size * 2, 2048);
|
||||
const u64 inspected_max_size = 2048;
|
||||
u64 text_buf_size = min(app.inspected_file_size * 2, inspected_max_size);
|
||||
char *text_buf = arena_push_array_no_zero<char>(scratch.arena, text_buf_size + 1);
|
||||
// TODO: convert file content to human readable
|
||||
// Convert file content to human readable
|
||||
// @Speed: maybe do this only when the file changes
|
||||
for (u64 i = 0; i < text_buf_size / 2; ++i)
|
||||
sprintf(&text_buf[2 * i], "%02X", app.inspected_fmem[i]);
|
||||
text_buf[text_buf_size] = 0;
|
||||
|
||||
if (ImGui::Begin("main")) {
|
||||
// ImGui::SetNextWindowContentSize({ 500, 600 });
|
||||
// ImGui::SetCursorX(30);
|
||||
// ImGui::TextWrapped("%s", text_buf);
|
||||
static MemoryEditor mem_edit = make_memory_editor();
|
||||
ImGui::Text("Inspecting RNTuple '%s' (%s)", app.ntpl_name,
|
||||
(const char *)rntuple_description(scratch.arena, app.rntinfo->anchor));
|
||||
|
||||
static MemoryEditor mem_edit = make_memory_editor(*app.rntinfo);
|
||||
mem_edit.DrawWindow("Hex View", app.inspected_fmem, app.inspected_file_size);
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
|
38
src/rntuple.cpp
Normal file
38
src/rntuple.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
internal
|
||||
String8 rntuple_description(Arena *arena, const RNTuple &anchor)
|
||||
{
|
||||
String8 desc = push_str8f(arena, "version %u.%u.%u.%u",
|
||||
anchor.GetVersionEpoch(),
|
||||
anchor.GetVersionMajor(),
|
||||
anchor.GetVersionMinor(),
|
||||
anchor.GetVersionPatch());
|
||||
return desc;
|
||||
}
|
||||
|
||||
internal
|
||||
RNTuple_Info *get_rntuple_info(Arena *arena, const char *fname, const char *ntpl_name)
|
||||
{
|
||||
RNTuple_Info *info = arena_push_zeroed<RNTuple_Info>(arena);
|
||||
|
||||
// Open the TFile
|
||||
TFile *tfile = TFile::Open(fname, "READ");
|
||||
if (!tfile) {
|
||||
fprintf(stderr, "Failed to open TFile.\n");
|
||||
return info;
|
||||
}
|
||||
defer { delete tfile; };
|
||||
|
||||
// Get the RNTuple information
|
||||
const RNTuple *anchor = tfile->Get<RNTuple>(ntpl_name);
|
||||
if (anchor) {
|
||||
info->anchor = *anchor;
|
||||
info->header.start = anchor->GetSeekHeader();
|
||||
info->header.len = anchor->GetNBytesHeader();
|
||||
info->footer.start = anchor->GetSeekFooter();
|
||||
info->footer.len = anchor->GetNBytesFooter();
|
||||
} else {
|
||||
fprintf(stderr, "RNTuple '%s' not found in %s.\n", ntpl_name, fname);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
13
src/rntuple.h
Normal file
13
src/rntuple.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
using RNTuple = ROOT::Experimental::RNTuple;
|
||||
|
||||
struct Byte_Range {
|
||||
u64 start, len;
|
||||
u64 end() const { return start + len; }
|
||||
};
|
||||
|
||||
struct RNTuple_Info {
|
||||
RNTuple anchor;
|
||||
|
||||
Byte_Range header;
|
||||
Byte_Range footer;
|
||||
};
|
|
@ -6,12 +6,6 @@
|
|||
#include <cstdint>
|
||||
#include <chrono>
|
||||
|
||||
// @Platform
|
||||
#include <sys/mman.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h> // for NAME_MAX
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#endif
|
||||
|
@ -27,11 +21,19 @@
|
|||
#include "types.h"
|
||||
#include "defer.hpp"
|
||||
#include "mem.h"
|
||||
#include "str.h"
|
||||
#include "rntuple.h"
|
||||
#include "window.h"
|
||||
#include "app_state.h"
|
||||
|
||||
// @Platform
|
||||
#include "platform_linux.h"
|
||||
|
||||
namespace chr = std::chrono;
|
||||
|
||||
#include "mem.cpp"
|
||||
#include "str.cpp"
|
||||
#include "rntuple.cpp"
|
||||
#include "render.cpp"
|
||||
#include "mainloop.cpp"
|
||||
|
||||
|
@ -86,16 +88,25 @@ GLFWwindow* init_glfw(i32 desired_win_width, i32 desired_win_height)
|
|||
return window;
|
||||
}
|
||||
|
||||
internal
|
||||
void app_cleanup(App_State &app)
|
||||
{
|
||||
os_stop_file_watch(app);
|
||||
os_unmap_file(app.inspected_fmem, app.inspected_file_size);
|
||||
if (app.inspected_file) fclose(app.inspected_file);
|
||||
app.inspected_file = nullptr;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
if (argc > 1 && argv[1][0] == '-') {
|
||||
fprintf(stderr, "Usage: %s <ntuple_name> <ntuple_file.root>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Collect arguments
|
||||
const char *ntpl_name = argv[1];
|
||||
const char *fname = argv[2];
|
||||
const char *ntpl_name = argc > 1 ? argv[1] : nullptr;
|
||||
const char *fname = argc > 2 ? argv[2] : nullptr;
|
||||
|
||||
// Allocate program memory
|
||||
Arena *arena = arena_alloc();
|
||||
|
@ -118,57 +129,22 @@ int main(int argc, char **argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Open and map te file
|
||||
FILE *file = fopen(fname, "rb");
|
||||
defer { fclose(file); };
|
||||
|
||||
int fd = fileno(file);
|
||||
size_t fsize = file_size(file);
|
||||
// @Platform
|
||||
void *fmem = mmap(0, fsize, PROT_READ, MAP_SHARED_VALIDATE, fd, 0);
|
||||
if (!fmem) {
|
||||
fprintf(stderr, "Failed to open file %s\n", fname);
|
||||
return 1;
|
||||
}
|
||||
defer { munmap(fmem, fsize); };
|
||||
|
||||
// @Platform: watch file for changes (to adapt the displayed file size - otherwise
|
||||
// we may try to access invalid memory when the file gets shrunk)
|
||||
int inot = inotify_init1(IN_NONBLOCK);
|
||||
if (inot == -1) {
|
||||
fprintf(stderr, "Failed to init inotify: %s (%d)\n", strerror(errno), errno);
|
||||
return 1;
|
||||
}
|
||||
if (inotify_add_watch(inot, fname, IN_MODIFY) == -1) {
|
||||
fprintf(stderr, "Failed to add inotify watch: %s (%d)\n", strerror(errno), errno);
|
||||
return 1;
|
||||
}
|
||||
defer { close(inot); };
|
||||
|
||||
// Open the TFile
|
||||
#if 0
|
||||
TFile *tfile = TFile::Open(fname, "READ");
|
||||
if (!tfile) {
|
||||
fprintf(stderr, "Failed to open TFile.\n");
|
||||
return 1;
|
||||
}
|
||||
defer { delete tfile; };
|
||||
|
||||
// Get the RNTuple information
|
||||
const RNTuple *anchor = tfile->Get<RNTuple>(ntpl_name);
|
||||
if (!anchor) {
|
||||
fprintf(stderr, "RNTuple '%s' not found in %s.\n", ntpl_name, fname);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Start main loop
|
||||
App_State app {};
|
||||
app.inspected_file = file;
|
||||
app.inspected_fmem = (u8*)fmem;
|
||||
app.inspected_file_size = fsize;
|
||||
app.inot = inot;
|
||||
defer { app_cleanup(app); };
|
||||
|
||||
// Open and map the file
|
||||
if (fname) {
|
||||
os_open_and_map_file(fname, app);
|
||||
|
||||
// Watch file for changes (to adapt the displayed file size - otherwise
|
||||
// we may try to access invalid memory when the file gets shrunk)
|
||||
os_start_file_watch(fname, app);
|
||||
}
|
||||
|
||||
app.ntpl_name = ntpl_name;
|
||||
app.rntinfo = get_rntuple_info(arena, fname, ntpl_name);
|
||||
|
||||
// Start main loop
|
||||
run_main_loop(window, arena, app);
|
||||
|
||||
return 0;
|
||||
|
|
22
src/str.cpp
Normal file
22
src/str.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
internal
|
||||
String8 push_str8fv(Arena *arena, const char *fmt, va_list args)
|
||||
{
|
||||
va_list args2;
|
||||
va_copy(args2, args);
|
||||
u32 needed_bytes = vsnprintf(0, 0, fmt, args) + 1;
|
||||
String8 result = {};
|
||||
result.str = arena_push_array_no_zero<u8>(arena, needed_bytes);
|
||||
result.size = vsnprintf((char*)result.str, needed_bytes, fmt, args2);
|
||||
result.str[result.size] = 0;
|
||||
va_end(args2);
|
||||
return result;
|
||||
}
|
||||
|
||||
String8 push_str8f(Arena *arena, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 result = push_str8fv(arena, fmt, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
12
src/str.h
Normal file
12
src/str.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
struct String8 {
|
||||
u8* str;
|
||||
u64 size;
|
||||
|
||||
operator const char *() const {
|
||||
return (const char *)str;
|
||||
}
|
||||
};
|
||||
|
||||
#define str8(s) String8((u8*)(s), sizeof(s) - 1)
|
||||
|
||||
String8 push_str8f(Arena *arena, char *fmt, ...);
|
47
src/window.h
Normal file
47
src/window.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
enum Input_Key {
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
KEY_LEFT,
|
||||
KEY_RIGHT,
|
||||
KEY_Q,
|
||||
KEY_ALT,
|
||||
KEY_TAB,
|
||||
|
||||
KEY_COUNT
|
||||
};
|
||||
|
||||
enum Mouse_Button {
|
||||
MOUSE_BTN_LEFT,
|
||||
MOUSE_BTN_RIGHT,
|
||||
|
||||
MOUSE_BTN_COUNT
|
||||
};
|
||||
|
||||
enum Mouse_Button_State : u16 {
|
||||
MOUSE_BTN_STATE_IS_DOWN = 0x1,
|
||||
MOUSE_BTN_STATE_JUST_PRESSED = 0x2,
|
||||
MOUSE_BTN_STATE_JUST_RELEASED = 0x4,
|
||||
};
|
||||
|
||||
enum Key_State : u16 {
|
||||
KEY_STATE_IS_DOWN = 0x1,
|
||||
KEY_STATE_JUST_PRESSED = 0x2,
|
||||
KEY_STATE_JUST_RELEASED = 0x4,
|
||||
};
|
||||
|
||||
struct User_Input {
|
||||
u16 key_state[KEY_COUNT];
|
||||
|
||||
u16 mouse_btn_state[MOUSE_BTN_COUNT];
|
||||
struct { i32 x; i32 y; } mouse_pos;
|
||||
};
|
||||
|
||||
struct Window_Data {
|
||||
// Real width and height of the window
|
||||
i32 width;
|
||||
i32 height;
|
||||
bool size_just_changed;
|
||||
|
||||
f32 desired_aspect_ratio;
|
||||
};
|
||||
|
21
third_party/imgui_club/imgui_memory_editor.h
vendored
21
third_party/imgui_club/imgui_memory_editor.h
vendored
|
@ -94,6 +94,8 @@ struct MemoryEditor
|
|||
ImU8 (*ReadFn)(const ImU8* data, size_t off); // = 0 // optional handler to read bytes.
|
||||
void (*WriteFn)(ImU8* data, size_t off, ImU8 d); // = 0 // optional handler to write bytes.
|
||||
bool (*HighlightFn)(const ImU8* data, size_t off);//= 0 // optional handler to return Highlight property (to support non-contiguous highlighting).
|
||||
ImU32 (*BgColorFn)(const ImU8* data, size_t off, const void *UserData); // = 0 // optional handler to return custom background color of individual bytes.
|
||||
const void *BgColorFnUserData;
|
||||
|
||||
// [Internal State]
|
||||
bool ContentsWidthChanged;
|
||||
|
@ -126,6 +128,8 @@ struct MemoryEditor
|
|||
ReadFn = NULL;
|
||||
WriteFn = NULL;
|
||||
HighlightFn = NULL;
|
||||
BgColorFn = NULL;
|
||||
BgColorFnUserData = NULL;
|
||||
|
||||
// State/Internals
|
||||
ContentsWidthChanged = false;
|
||||
|
@ -302,6 +306,19 @@ struct MemoryEditor
|
|||
}
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), HighlightColor);
|
||||
}
|
||||
else if (BgColorFn)
|
||||
{
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
float highlight_width = s.GlyphWidth * 2;
|
||||
bool is_next_byte_highlighted = (addr + 1 < mem_size) && ((BgColorFn(mem_data, addr + 1, BgColorFnUserData) & IM_COL32_A_MASK) != 0);
|
||||
if (is_next_byte_highlighted || (n + 1 == Cols))
|
||||
{
|
||||
highlight_width = s.HexCellWidth;
|
||||
if (OptMidColsCount > 0 && n > 0 && (n + 1) < Cols && ((n + 1) % OptMidColsCount) == 0)
|
||||
highlight_width += s.SpacingBetweenMidCols;
|
||||
}
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), BgColorFn(mem_data, addr, BgColorFnUserData));
|
||||
}
|
||||
|
||||
if (DataEditingAddr == addr)
|
||||
{
|
||||
|
@ -413,6 +430,10 @@ struct MemoryEditor
|
|||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg));
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg));
|
||||
}
|
||||
else if (BgColorFn)
|
||||
{
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), BgColorFn(mem_data, addr, BgColorFnUserData));
|
||||
}
|
||||
unsigned char c = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr];
|
||||
char display_c = (c < 32 || c >= 128) ? '.' : c;
|
||||
draw_list->AddText(pos, (display_c == c) ? color_text : color_disabled, &display_c, &display_c + 1);
|
||||
|
|
Loading…
Reference in a new issue