#pragma once #include <string>#include <memory>#include <vector>#include <set>#include <cstring> #include "containers.h" #define MIN_CHAR ' '#define MAX_CHAR '~'#define N_CHARS (MAX_CHAR - MIN_CHAR + 1) #ifdef _WIN32 typedef unsigned long THREAD_RETURN_TYPE; // DWORD typedef void* SOURCE_HANDLE; // HANDLE#else typedef void* THREAD_RETURN_TYPE; typedef int SOURCE_HANDLE;#endif typedef void* Texture;typedef void* Surface;typedef void* Renderer;typedef void* Font_Face; struct SDL; Font_Face load_font_face(const char *path);void destroy_font_face(Font_Face face);void ft_quit(); int run(); int count_hex_digits(u64 num);void write_hex(char *out, u64 n, int n_digits);void write_dec(char *out, s64 n); struct Glyph { int atlas_x; int atlas_y; int img_w; int img_h; float box_w; float box_h; int left; int top;}; struct RGBA { float r; float g; float b; float a;}; struct Point { float x, y;}; struct Rect_Int; struct Rect { float x, y; float w, h; Rect_Int to_rect_int() const; bool contains(Point& p) const { return p.x >= x && p.x < x+w && p.y >= y && p.y < y+h; } bool contains(float px, float py) const { return px >= x && px < x+w && py >= y && py < y+h; }}; struct Rect_Int { int x, y; int w, h; Rect to_rect() const; bool contains(Point& p) const { return p.x >= x && p.x < x+w && p.y >= y && p.y < y+h; } bool contains(float px, float py) const { return px >= x && px < x+w && py >= y && py < y+h; }}; #define CLIP_TOP 1#define CLIP_BOTTOM 2#define CLIP_LEFT 4#define CLIP_RIGHT 8#define CLIP_ALL 15 struct Render_Clip { u32 flags = 0; float x_lower = 0, y_lower = 0; float x_upper = 0, y_upper = 0;}; struct Input;struct Camera; enum CursorType { CursorDefault = 0, CursorClick, CursorEdit, CursorPan, CursorResizeNorthSouth, CursorResizeWestEast, CursorResizeNESW, CursorResizeNWSE, NumCursors}; void *sdl_get_hw_renderer();void sdl_set_cursor(CursorType type);void sdl_get_dpi(int& w, int& h); void sdl_log_string(const char *msg);void sdl_log_last_error(); Renderer sdl_acquire_sw_renderer(int w, int h);Texture sdl_bake_sw_render(); bool sdl_init(const char *title, int width, int height, RGBA bg_color);void sdl_close(); bool sdl_poll_input(Input& input);void sdl_update_camera(Camera& camera); void sdl_acquire_mouse();void sdl_release_mouse(); void sdl_copy(std::string& string);int sdl_paste_into(std::string& string, int offset, int (*filterer)(char*, int)); void sdl_apply_texture(Texture tex, Rect_Int& dst, Rect_Int *src, Renderer rdr);void sdl_apply_texture(Texture tex, Rect& dst, Rect_Int *src, Renderer rdr); void sdl_draw_rect(Rect_Int& rect, RGBA& color, Renderer rdr);void sdl_draw_rect(Rect& rect, RGBA& color, Renderer rdr);void sdl_draw_rect_clipped(Rect_Int& rect, Render_Clip& clip, RGBA& color, Renderer rdr);void sdl_draw_rect_clipped(Rect& rect, Render_Clip& clip, RGBA& color, Renderer rdr); void sdl_clear();void sdl_render(); Surface sdl_create_surface(u32 *data, int w, int h);Texture sdl_create_texture(u32 *data, int w, int h);void sdl_get_texture_size(Texture tex, int *w, int *h); void *sdl_lock_texture(Texture tex);void sdl_unlock_texture(Texture tex);void sdl_destroy_texture(Texture *tex); enum IconType { IconNone = 0, IconGoto, IconGlass, IconTriangle}; Texture make_circle(RGBA& color, int diameter);Texture make_triangle(RGBA& color, int width, int height, bool up = false);Texture make_rectangle(RGBA& color, int width, int height, float left, float top, float thickness);Texture make_cross_icon(RGBA& color, int length, float inner, float outer);Texture make_folder_icon(RGBA& dark, RGBA& light, int w, int h);Texture make_file_icon(RGBA& back, RGBA& fold_color, RGBA& line_color, int w, int h);Texture make_process_icon(RGBA& back, RGBA& outline, int length);Texture make_divider_icon(RGBA& color, int width, int height, double gap, double thicc, double sharpness, bool up_down);Texture make_goto_icon(RGBA& color, int length);Texture make_glass_icon(RGBA& color, int length);Texture make_plus_minus_icon(RGBA& color, int length, bool plus); void *allocate_ui_element(Arena& arena, int i_type); #define MAX_FNAME 112 struct File_Entry { u32 flags; char *path; char name[MAX_FNAME];}; enum ColumnType { ColumnNone = 0, ColumnString, ColumnFile, ColumnDec, ColumnHex, ColumnStdString, ColumnImage, ColumnCheckbox, ColumnElement}; // Column Type, Count Per Cell, Fractional Width, Minimum Heights, Maximum Heights, Namestruct Column { ColumnType type = ColumnNone; int count_per_cell = 0; // Number of elements (eg. chars or digits) to allocate or print per cell float width = 0; // Fraction of the width of the whole table float min_size = 0; // Minimum column width in font height units (ie. 1.0 == the height of the current font in pixels) float max_size = 0; const char *name; // Used as the column header text}; // row_idx, length, name_idx, closedstruct Branch { int row_idx; int length; int name_idx; bool closed;}; struct Table { Arena *arena = nullptr; std::vector<Column> headers; std::unique_ptr<std::vector<void*>[]> columns; std::set<int> list; int filtered = -1; bool has_ui_elements = false; void *element_tag = nullptr; void (*element_init_func)(Table*, int, int) = nullptr; String_Vector branch_name_vector; std::vector<Branch> branches; std::vector<int> tree; Table(); Table(const Table& t); Table(Table&& t); ~Table(); int column_count() const { return headers.size(); } int row_count() const { return headers.size() > 0 ? columns[0].size() : 0; } int index_from_filtered(int sel) { return filtered < 0 ? sel : *std::next(list.begin(), sel); } int filtered_from_index(int idx) { auto it = list.find(idx); return it == list.end() ? -1 : std::distance(list.begin(), it); } void set_checkbox(int col, int row, bool state) { *(u8*)&columns[col][row] = state ? 2 : 1; } void toggle_checkbox(int col, int row) { *(u8*)&columns[col][row] = *(u8*)&columns[col][row] == 2 ? 1 : 2; } bool checkbox_checked(int col, int row) const { return *(u8*)&columns[col][row] == 2; } void init(Column *headers, Arena *a, void *m, void (*elem_init)(Table*, int, int), int n_cols, int n_rows); void resize(int n_rows); void clear_filter(); void clear_data(); void update_filter(std::string& line); void update_tree(std::vector<Branch> *new_branches = nullptr); int get_table_index(int view_idx); void release();}; struct Font_Render { Texture tex = nullptr; Glyph glyphs[N_CHARS] = {}; int pts = 0; const Glyph *glyph_for(char c) const { if (c < MIN_CHAR || c > MAX_CHAR) return nullptr; return &glyphs[c - MIN_CHAR]; } float text_width(const char *text, int cursor = 0, float *x_out = nullptr) const { float w = 0; int len = strlen(text); for (int i = 0; i < len; i++) { if (x_out && cursor == i) *x_out = w; const Glyph *gl = glyph_for(text[i]); if (gl) w += gl->box_w; } if (x_out && cursor == len) *x_out = w; return w; } float text_height() const { return glyph_for('j')->box_h; } float digit_width() const { return glyph_for('0')->box_w; } void draw_text_simple(void *renderer, const char *text, float x, float y); void draw_text(void *renderer, const char *text, float x, float y, Render_Clip& clip, int tab_cols = 4, bool multiline = false); Font_Render() = default; ~Font_Render() { sdl_destroy_texture(&tex); }}; struct Font { Font_Face face = nullptr; float size = 0; RGBA color = {1, 1, 1, 1}; float prev_scale = 1.0; Font_Render render = {}; const float line_spacing = 0.1; const float line_offset = 0.15; Font(Font_Face f, float sz, RGBA& color, int dpi_w, int dpi_h); void adjust_scale(float scale, int dpi_w, int dpi_h);}; struct Camera { float x = 0, y = 0; float scale = 1.0; float max_scale = 3.0; float min_scale = 0.1; float zoom_coeff = 0.1; float scroll_delta = 20; int center_x = 0, center_y = 0; bool moving = false; Point to_world(Point p) const { return { x + (p.x - center_x) / scale, y + (p.y - center_y) / scale }; } Point to_world(int px, int py) const { return { x + (float)(px - center_x) / scale, y + (float)(py - center_y) / scale }; } float to_world_x(int p) const { return x + (float)(p - center_x) / scale; } float to_world_y(int p) const { return y + (float)(p - center_y) / scale; } Point to_screen(Point p) const { return { center_x + (p.x - x) * scale, center_y + (p.y - y) * scale }; } Point to_screen(float px, float py) const { return { center_x + (px - x) * scale, center_y + (py - y) * scale }; } Rect_Int to_screen_rect(Rect r) const { return { (int)(center_x + (r.x - x) * scale + 0.5), (int)(center_y + (r.y - y) * scale + 0.5), (int)(r.w * scale + 0.5), (int)(r.h * scale + 0.5) }; }}; Camera& get_default_camera(); struct Input { bool lmouse = false, rmouse = false; bool lclick = false, rclick = false; int scroll_x = 0, scroll_y = 0; int mouse_x = 0, mouse_y = 0; int prev_x = 0, prev_y = 0; int click_x = 0, click_y = 0; int action_x = 0, action_y = 0; int held = 0; bool action = false; bool prevent_action = false; bool double_click = false; float action_circle = 2.5; int action_timer = 0; int action_timeout = 30; bool lctrl = false, rctrl = false; bool lshift = false, rshift = false; int del = 0; int back = 0; int esc = 0; int enter = 0; int tab = 0; int home = 0; int end = 0; int pgup = 0; int pgdown = 0; int left = 0; int down = 0; int right = 0; int up = 0; int last_key = 0; char ch = 0; bool strike(int t) { return t == 1 || (t >= 20 && (t % 5 == 1)); }}; #define REG_PM_EXEC 0#define REG_PM_WRITE 1#define REG_PM_READ 2 struct Span { u8 *data = nullptr; u64 address = 0; int size = 0; int retrieved = 0; int offset = 0; int tag = 0; u32 flags = 0;}; struct Region { char *name = nullptr; u64 base = 0; u64 size = 0; //u32 offset = 0; u32 flags = 0;}; enum SourceType { SourceNone = 0, SourceFile, SourceProcess}; struct Source { SourceType type = SourceNone; std::string name; Arena arena; int pid = 0; void *identifier = nullptr; union { int fd = 0; void *handle; }; u8 *buffer = nullptr; int buf_size = 0; // list of pages, where each page is 4k of text loaded from /proc/<pid>/maps std::vector<char*> proc_map_pages; Map address_to_region; std::vector<Region> regions; std::vector<Span> spans; bool region_refreshed = false; bool block_region_refresh = false; int refresh_region_rate = 60; int refresh_span_rate = 60; int timer = 0; int request_span(); void deactivate_span(int idx); void gather_data();}; #define PAGE_SIZE 0x1000 const char *get_folder_separator();const char *get_root_folder();const char *get_project_path(); bool is_folder(const char *name); std::pair<int, std::unique_ptr<u8[]>> read_file(std::string& path); void get_process_id_list(std::vector<s64>& list);int get_process_names(std::vector<s64> *list, Map& icon_map, std::vector<void*>& icons, std::vector<void*>& pids, std::vector<void*>& names, int count_per_cell); void enumerate_files(char *path, std::vector<File_Entry*>& files, Arena& arena); void refresh_file_region(Source& source);void refresh_file_spans(Source& source, std::vector<Span>& input); void refresh_process_regions(Source& source);void refresh_process_spans(Source& source, std::vector<Span>& input); void close_source(Source& source); SOURCE_HANDLE get_readonly_file_handle(void *identifier);SOURCE_HANDLE get_readonly_process_handle(int pid); int read_page(SOURCE_HANDLE handle, SourceType type, u64 address, char *buf); void wait_ms(int ms); bool start_thread(void** thread_ptr, void *data, THREAD_RETURN_TYPE (*function)(void*));