diff --git a/plugins/builtin/source/content/tools/ascii_table.cpp b/plugins/builtin/source/content/tools/ascii_table.cpp index 4eaf6d266..f3dad37b6 100644 --- a/plugins/builtin/source/content/tools/ascii_table.cpp +++ b/plugins/builtin/source/content/tools/ascii_table.cpp @@ -2,14 +2,23 @@ #include #include +#include +#include +#include + +#include #include namespace hex::plugin::builtin { - void drawASCIITable() { + static void drawColumnASCIITable() { static bool asciiTableShowOctal = false; + ImGui::SameLine(); + ImGuiExt::DimmedIconToggle("0o", &asciiTableShowOctal); + ImGui::SetItemTooltip("%s", "hex.builtin.tools.ascii_table.octal"_lang.get()); + if (ImGui::BeginTable("##asciitable", 4, ImGuiTableFlags_SizingStretchSame)) { ImGui::TableSetupColumn("##1"); ImGui::TableSetupColumn("##2"); @@ -52,8 +61,133 @@ namespace hex::plugin::builtin { } ImGui::EndTable(); } + } - ImGui::Checkbox("hex.builtin.tools.ascii_table.octal"_lang, &asciiTableShowOctal); + static void drawGridASCIITable() { + constexpr static std::array Characters = { + "␀", "␁", "␂", "␃", "␄", "␅", "␆", "␇", + "␈", "␉", "␊", "␋", "␌", "␍", "␎", "␏", + "␐", "␑", "␒", "␓", "␔", "␕", "␖", "␗", + "␘", "␙", "␚", "␛", "␜", "␝", "␞", "␟", + "␣", "!", "\"", "#", "$", "%", "&", "'", + "(", ")", "*", "+", ",", "-", ".", "/", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", ":", ";", "<", "=", ">", "?", + "@", "A", "B", "C", "D", "E", "F", "G", + "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", + "X", "Y", "Z", "[", "\\", "]", "^", "_", + "`", "a", "b", "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", "m", "n", "o", + "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "{", "|", "}", "~", "␡" + }; + + using HighlightFunction = int(*)(int); + constexpr static std::array HighlightFunctionNames = { + "iscntrl", "isprint", "isspace", "isblank", + "isgraph", "ispunct", "isalnum", "isalpha", + "isupper", "islower", "isdigit", "isxdigit" + }; + const static std::array HighlightFunctions = { + std::iscntrl, std::isprint, std::isspace, std::isblank, + std::isgraph, std::ispunct, std::isalnum, std::isalpha, + std::isupper, std::islower, std::isdigit, std::isxdigit + }; + + static std::array highlightFunctionEnabled; + static HighlightFunction hoverHighlightFunction = nullptr; + + if (ImGui::BeginTable("##asciitable", 1 + 0x10, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchSame, ImVec2(ImGui::GetContentRegionAvail().x, 0))) { + ImGui::TableSetupColumn("##ascii", ImGuiTableColumnFlags_WidthFixed, ImGui::GetTextLineHeight()); + for (u8 i = 0; i < 0x10; i += 1) { + ImGui::TableSetupColumn(fmt::format("{:X}", i).c_str()); + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + for (u8 i = 0; i < 0x10; i += 1) { + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted(" {:X}", i); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImGuiCol_TableHeaderBg)); + } + + for (u8 row = 0; row < 0x08; row += 1) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted(" {:X}", row); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImGuiCol_TableHeaderBg)); + + for (u8 column = 0; column < 0x10; column += 1) { + ImGui::TableNextColumn(); + + const auto character = row * 0x10 + column; + for (u8 i = 0; i < HighlightFunctions.size(); i++) { + if (highlightFunctionEnabled[i] && HighlightFunctions[i](character) != 0) { + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImGuiCustomCol_Highlight)); + break; + } + } + if (hoverHighlightFunction != nullptr && hoverHighlightFunction(character) != 0) { + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImGuiCol_PlotHistogram, 0.25F)); + } + + if (ImGui::GetIO().KeyShift) + ImGuiExt::TextFormattedDisabled("0x{:02X}", character); + else + ImGuiExt::TextFormatted(" {}", Characters[character]); + } + } + + { + const auto hoveredRow = ImGui::TableGetHoveredRow(); + const auto hoveredColumn = ImGui::TableGetHoveredColumn(); + if (hoveredRow > 0 && hoveredColumn > 0) { + const auto character = (hoveredRow - 1) * 0x10 + (hoveredColumn - 1); + ImGui::SetNextWindowSize(ImVec2(ImGui::CalcTextSize(" bin: 0b00000000 ").x, 0), ImGuiCond_Always); + if (ImGui::BeginTooltip()) { + fonts::Default().push(2.0F); + ImGuiExt::TextFormattedCenteredHorizontal(" {}", Characters[character]); + fonts::Default().pop(); + + ImGui::Separator(); + + ImGuiExt::TextFormatted("dec: {}", character); + ImGuiExt::TextFormatted("hex: 0x{:02X}", character); + ImGuiExt::TextFormatted("oct: 0o{:03o}", character); + ImGuiExt::TextFormatted("bin: 0b{:08b}", character); + + ImGui::EndTooltip(); + } + } + } + + ImGui::EndTable(); + } + + hoverHighlightFunction = nullptr; + for (size_t i = 0; i < HighlightFunctions.size(); i++) { + if (i % 6 != 0) + ImGui::SameLine(); + + auto &spacing = ImGui::GetStyle().ItemSpacing.x; + ImGuiExt::DimmedButtonToggle(HighlightFunctionNames[i], &highlightFunctionEnabled[i], ImVec2((ImGui::GetWindowSize().x - spacing) / 6 - spacing, 0)); + if (ImGui::IsItemHovered()) { + hoverHighlightFunction = HighlightFunctions[i]; + } + + } + } + + void drawASCIITable() { + static bool columnLayout = false; + + ImGuiExt::DimmedIconToggle(ICON_VS_SPLIT_HORIZONTAL, &columnLayout); + + if (columnLayout) + drawColumnASCIITable(); + else + drawGridASCIITable(); } }