diff --git a/platforms/desktop-shared/imgui/memory_editor.cpp b/platforms/desktop-shared/imgui/memory_editor.cpp index ca632b6..9fa612a 100644 --- a/platforms/desktop-shared/imgui/memory_editor.cpp +++ b/platforms/desktop-shared/imgui/memory_editor.cpp @@ -18,26 +18,31 @@ */ #include "memory_editor.h" +#include +#include -GearMemoryEditor::GearMemoryEditor() +MemEditor::MemEditor() { - m_editing_address = -1; - m_set_keyboard_here = false; - m_selection_start = -1; - m_selection_end = -1; + m_separator_column_width = 8.0f; + m_selection_start = 0; + m_selection_end = 0; m_bytes_per_row = 16; - m_separator_column_width = 8.0f;; - m_uppercase_hex = true; m_row_scroll_top = 0; m_row_scroll_bottom = 0; + m_editing_address = -1; + m_set_keyboard_here = false; + m_uppercase_hex = true; + m_gray_out_zeros = true; + m_preview_data_type = 0; + m_preview_endianess = 0; } -GearMemoryEditor::~GearMemoryEditor() +MemEditor::~MemEditor() { } -void GearMemoryEditor::Draw(uint8_t* mem_data, int mem_size, int base_display_addr) +void MemEditor::Draw(uint8_t* mem_data, int mem_size, int base_display_addr) { int total_rows = (mem_size + (m_bytes_per_row - 1)) / m_bytes_per_row; int separator_count = (m_bytes_per_row - 1) / 4; @@ -47,17 +52,52 @@ void GearMemoryEditor::Draw(uint8_t* mem_data, int mem_size, int base_display_ad int max_chars_per_cell = 2; ImVec2 character_size = ImGui::CalcTextSize("0"); char buf[16]; - - ImGui::Text("Selection start: %d", m_selection_start); - ImGui::Text("Selection end: %d", m_selection_end); - ImGui::Text("Scroll top: %d", m_row_scroll_top); - ImGui::Text("Scroll bottom: %d", m_row_scroll_bottom); - - if (ImGui::BeginChild("##mem", ImVec2(ImGui::GetContentRegionAvail().x, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav)) + ImVec4 addr_color = ImVec4(0.1f,0.9f,0.9f,1.0f); + ImVec4 ascii_color = ImVec4(1.0f,0.502f,0.957f,1.0f); + ImVec4 column_color = ImVec4(1.0f,0.90f,0.05f,1.0f); + ImVec4 normal_color = ImVec4(1.0f,1.0f,1.0f,1.0f); + ImVec4 gray_color = ImVec4(0.4f,0.4f,0.4f,1.0f); + float height_separator = ImGui::GetStyle().ItemSpacing.y; + float footer_height = ImGui::GetFrameHeightWithSpacing() * 4; + + if (ImGui::BeginChild("##mem", ImVec2(ImGui::GetContentRegionAvail().x, -footer_height), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav)) { ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.5, 0)); - if (ImGui::BeginTable("##hex", byte_column_count, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoKeepColumnsVisible | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) + if (ImGui::BeginTable("##header", byte_column_count, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoKeepColumnsVisible)) + { + ImGui::TableSetupColumn("ADDR "); + ImGui::TableSetupColumn(""); + + for (int i = 0; i < m_bytes_per_row; i++) { + if (IsColumnSeparator(i, m_bytes_per_row)) + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, m_separator_column_width); + + sprintf(buf, "%02X", i); + + ImGui::TableSetupColumn(buf, ImGuiTableColumnFlags_WidthFixed, character_size.x * max_chars_per_cell + (6 + byte_cell_padding) * 1); + } + + ImGui::TableSetupColumn(""); + ImGui::TableSetupColumn("ASCII", ImGuiTableColumnFlags_WidthFixed, (character_size.x + character_cell_padding * 1) * m_bytes_per_row); + + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + ImGui::TextColored(addr_color, "%s", ImGui::TableGetColumnName(0)); + + for (int i = 1; i < (ImGui::TableGetColumnCount() - 1); i++) { + ImGui::TableNextColumn(); + ImGui::TextColored(column_color, "%s", ImGui::TableGetColumnName(i)); + } + + ImGui::TableNextColumn(); + ImGui::TextColored(ascii_color, "%s", ImGui::TableGetColumnName(ImGui::TableGetColumnCount() - 1)); + + ImGui::EndTable(); + } + + if (ImGui::BeginTable("##hex", byte_column_count, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoKeepColumnsVisible /*| ImGuiTableFlags_RowBg*/ | ImGuiTableFlags_ScrollY)) { m_row_scroll_top = ImGui::GetScrollY() / character_size.y; m_row_scroll_bottom = m_row_scroll_top + (ImGui::GetWindowHeight() / character_size.y); @@ -138,7 +178,9 @@ void GearMemoryEditor::Draw(uint8_t* mem_data, int mem_size, int base_display_ad else { ImGui::PushItemWidth((character_size).x); - ImGui::Text("%02X", mem_data[byte_address]); + + bool gray_out = m_gray_out_zeros && mem_data[byte_address] == 0; + ImGui::TextColored(gray_out ? gray_color : normal_color, m_uppercase_hex ? "%02X" : "%02x", mem_data[byte_address]); if (cell_hovered && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { @@ -179,7 +221,8 @@ void GearMemoryEditor::Draw(uint8_t* mem_data, int mem_size, int base_display_ad int byte_address = address + x; unsigned char c = mem_data[byte_address]; - ImGui::Text("%c", (c >= 32 && c < 128) ? c : '.'); + bool gray_out = m_gray_out_zeros && (c < 32 || c >= 128); + ImGui::TextColored(gray_out ? gray_color : normal_color, "%c", (c >= 32 && c < 128) ? c : '.'); ImGui::PopItemWidth(); ImGui::PopStyleVar(); @@ -200,14 +243,17 @@ void GearMemoryEditor::Draw(uint8_t* mem_data, int mem_size, int base_display_ad } ImGui::EndChild(); + + DrawOptions(mem_size, base_display_addr); + DrawDataPreview(m_selection_start, mem_data, mem_size); } -bool GearMemoryEditor::IsColumnSeparator(int current_column, int column_count) +bool MemEditor::IsColumnSeparator(int current_column, int column_count) { return (current_column > 0) && (current_column < column_count) && ((current_column % 4) == 0); } -void GearMemoryEditor::DrawSelectionFrame(int x, int y, int address, ImVec2 cell_pos, ImVec2 cell_size) +void MemEditor::DrawSelectionFrame(int x, int y, int address, ImVec2 cell_pos, ImVec2 cell_size) { ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec4 frame_color = ImVec4(0.1f,0.9f,0.9f,1.0f); @@ -238,7 +284,7 @@ void GearMemoryEditor::DrawSelectionFrame(int x, int y, int address, ImVec2 cell drawList->AddLine(cell_pos + ImVec2(0, cell_size.y), cell_pos + cell_size + ImVec2(1, 0), ImColor(frame_color), 1); } -void GearMemoryEditor::HandleSelection(int address, int row) +void MemEditor::HandleSelection(int address, int row) { if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { @@ -268,3 +314,82 @@ void GearMemoryEditor::HandleSelection(int address, int row) m_selection_end = tmp; } } + +void MemEditor::JumpToAddress(int address) +{ + ImVec2 character_size = ImGui::CalcTextSize("0"); + ImGui::SetScrollY((address / m_bytes_per_row) * character_size.y); +} + +void MemEditor::DrawOptions(int mem_size, int base_display_addr) +{ + ImVec4 color = ImVec4(0.1f,0.9f,0.9f,1.0f); + + ImGui::TextColored(color, "REGION:"); + ImGui::SameLine(); + ImGui::Text("%04X-%04X", base_display_addr, base_display_addr + mem_size); + ImGui::SameLine(); + ImGui::TextColored(color, " SELECTION:"); + ImGui::SameLine(); + ImGui::Text("%04X-%04X",m_selection_start, m_selection_end); + + if (ImGui::Button("Options")) + ImGui::OpenPopup("context"); + + if (ImGui::BeginPopup("context")) + { + ImGui::Text("Columns: "); + ImGui::SameLine(); + ImGui::PushItemWidth(120.0f); + ImGui::SliderInt("##columns", &m_bytes_per_row, 4, 16); + ImGui::Text("Preview as:"); + ImGui::SameLine(); + ImGui::PushItemWidth(120.0f); + ImGui::Combo("##preview_type", &m_preview_data_type, "Uint8\0Int8\0Uint16\0Int16\0UInt32\0Int32\0\0"); + ImGui::Text("Preview as:"); + ImGui::SameLine(); + ImGui::PushItemWidth(120.0f); + ImGui::Combo("##preview_endianess", &m_preview_endianess, "Little Endian\0Big Endian\0\0"); + ImGui::Checkbox("Uppercase hex", &m_uppercase_hex); + ImGui::Checkbox("Gray out zeros", &m_gray_out_zeros); + + ImGui::EndPopup(); + } + + ImGui::SameLine(); + ImGui::Text("Go to:"); + ImGui::SameLine(); + ImGui::PushItemWidth(45); + char goto_address[5] = ""; + if (ImGui::InputTextWithHint("##gotoaddr", "XXXX", goto_address, IM_ARRAYSIZE(goto_address), ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) + { + try + { + JumpToAddress((int)std::stoul(goto_address, 0, 16)); + } + catch(const std::invalid_argument&) + { + } + goto_address[0] = 0; + } +} + +void MemEditor::DrawDataPreview(int address, uint8_t* mem_data, int mem_size) +{ + if (address < 0 || address >= mem_size) + return; + + ImVec4 color = ImVec4(0.992f,0.592f,0.122f,1.0f); + + ImGui::TextColored(color, "Dec:"); + ImGui::SameLine(); + ImGui::Text("%d", mem_data[address]); + + ImGui::TextColored(color, "Hex:"); + ImGui::SameLine(); + ImGui::Text("%02X", mem_data[address]); + + ImGui::TextColored(color, "Bin:"); + ImGui::SameLine(); + ImGui::Text("%02X", mem_data[address]); +} \ No newline at end of file diff --git a/platforms/desktop-shared/imgui/memory_editor.h b/platforms/desktop-shared/imgui/memory_editor.h index 8a72e73..64c2f59 100644 --- a/platforms/desktop-shared/imgui/memory_editor.h +++ b/platforms/desktop-shared/imgui/memory_editor.h @@ -17,18 +17,18 @@ * */ -#ifndef GEAR_MEMORY_EDITOR_H -#define GEAR_MEMORY_EDITOR_H +#ifndef MEM_EDITOR_H +#define MEM_EDITOR_H #include #include #include "imgui.h" -class GearMemoryEditor +class MemEditor { public: - GearMemoryEditor(); - ~GearMemoryEditor(); + MemEditor(); + ~MemEditor(); void Draw(uint8_t* mem_data, int mem_size, int base_display_addr = 0x0000); @@ -36,17 +36,23 @@ class GearMemoryEditor bool IsColumnSeparator(int current_column, int column_count); void DrawSelectionFrame(int x, int y, int address, ImVec2 cellPos, ImVec2 cellSize); void HandleSelection(int address, int row); + void JumpToAddress(int address); + void DrawOptions(int mem_size, int base_display_addr); + void DrawDataPreview(int address, uint8_t* mem_data, int mem_size); private: - int m_bytes_per_row; float m_separator_column_width; - bool m_uppercase_hex; - int m_editing_address; - bool m_set_keyboard_here; int m_selection_start; int m_selection_end; + int m_bytes_per_row; int m_row_scroll_top; int m_row_scroll_bottom; + int m_editing_address; + bool m_set_keyboard_here; + bool m_uppercase_hex; + bool m_gray_out_zeros; + int m_preview_data_type; + int m_preview_endianess; }; -#endif /* GEAR_MEMORY_EDITOR_H */ \ No newline at end of file +#endif /* MEM_EDITOR_H */ \ No newline at end of file