1
0
mirror of synced 2024-12-24 13:34:50 +01:00
ImHex/plugins/builtin/source/content/data_visualizers.cpp

319 lines
14 KiB
C++

#include <hex/api/content_registry.hpp>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <hex/helpers/utils.hpp>
#include <wolv/utils/string.hpp>
namespace hex::plugin::builtin {
template<std::integral T>
class DataVisualizerHexadecimal : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
explicit DataVisualizerHexadecimal(const std::string &name) : DataVisualizer(name, ByteCount, CharCount) { }
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
hex::unused(address);
if (size == ByteCount)
ImGuiExt::TextFormatted(upperCase ? "{:0{}X}" : "{:0{}x}", *reinterpret_cast<const T*>(data), sizeof(T) * 2);
else
ImGuiExt::TextFormatted("{: {}s}", CharCount);
}
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
hex::unused(address, startedEditing);
if (size == ByteCount) {
return drawDefaultScalarEditingTextBox(address, getFormatString(upperCase), ImGuiExt::getImGuiDataType<T>(), data, ImGuiInputTextFlags_CharsHexadecimal);
} else {
return false;
}
}
private:
constexpr static inline auto ByteCount = sizeof(T);
constexpr static inline auto CharCount = ByteCount * 2;
const static inline auto FormattingUpperCase = hex::format("%0{}{}X", CharCount, ImGuiExt::getFormatLengthSpecifier<T>());
const static inline auto FormattingLowerCase = hex::format("%0{}{}x", CharCount, ImGuiExt::getFormatLengthSpecifier<T>());
const char *getFormatString(bool upperCase) {
if (upperCase)
return FormattingUpperCase.c_str();
else
return FormattingLowerCase.c_str();
}
};
class DataVisualizerHexii : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
DataVisualizerHexii() : DataVisualizer("hex.builtin.visualizer.hexii", ByteCount, CharCount) { }
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
hex::unused(address);
if (size == ByteCount) {
const u8 c = data[0];
switch (c) {
case 0x00:
ImGui::TextUnformatted(" ");
break;
case 0xFF:
ImGuiExt::TextFormattedDisabled("##");
break;
default:
if (c >= ' ' && c <= '~')
ImGuiExt::TextFormatted(".{:c}", char(c));
else
ImGui::Text(getFormatString(upperCase), c);
break;
}
} else {
ImGuiExt::TextFormatted("{: {}s}", CharCount);
}
}
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
hex::unused(address, startedEditing);
if (size == ByteCount) {
return drawDefaultScalarEditingTextBox(address, getFormatString(upperCase), ImGuiExt::getImGuiDataType<u8>(), data, ImGuiInputTextFlags_None);
} else {
return false;
}
}
private:
constexpr static inline auto ByteCount = 1;
constexpr static inline auto CharCount = ByteCount * 2;
const static inline auto FormattingUpperCase = hex::format("%0{}{}X", CharCount, ImGuiExt::getFormatLengthSpecifier<u8>());
const static inline auto FormattingLowerCase = hex::format("%0{}{}x", CharCount, ImGuiExt::getFormatLengthSpecifier<u8>());
static const char *getFormatString(bool upperCase) {
if (upperCase)
return FormattingUpperCase.c_str();
else
return FormattingLowerCase.c_str();
}
};
template<std::integral T>
class DataVisualizerDecimal : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
explicit DataVisualizerDecimal(const std::string &name) : DataVisualizer(name, ByteCount, CharCount) { }
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
hex::unused(address, upperCase);
if (size == ByteCount) {
if (std::is_signed_v<T>)
ImGui::Text(getFormatString(), static_cast<i64>(*reinterpret_cast<const T*>(data)));
else
ImGui::Text(getFormatString(), static_cast<u64>(*reinterpret_cast<const T*>(data)));
} else {
ImGuiExt::TextFormatted("{: {}s}", CharCount);
}
}
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
hex::unused(address, upperCase, startedEditing);
if (size == ByteCount) {
return drawDefaultScalarEditingTextBox(address, FormatString.c_str(), ImGuiExt::getImGuiDataType<T>(), data, ImGuiInputTextFlags_None);
} else {
return false;
}
}
private:
constexpr static inline auto ByteCount = sizeof(T);
constexpr static inline auto CharCount = std::numeric_limits<T>::digits10 + 2;
const static inline auto FormatString = hex::format("%{}{}{}", CharCount, ImGuiExt::getFormatLengthSpecifier<T>(), std::is_signed_v<T> ? "d" : "u");
const char *getFormatString() {
return FormatString.c_str();
}
};
enum class Float16 : u16 {};
template<typename T>
class DataVisualizerFloatingPoint : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
explicit DataVisualizerFloatingPoint(const std::string &name) : DataVisualizer(name, ByteCount, CharCount) { }
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
hex::unused(address);
if (size == ByteCount)
ImGui::Text(getFormatString(upperCase), *reinterpret_cast<const T*>(data));
else
ImGuiExt::TextFormatted("{: {}s}", CharCount);
}
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
hex::unused(address, upperCase, startedEditing);
if (size == ByteCount) {
return drawDefaultScalarEditingTextBox(address, getFormatString(upperCase), ImGuiExt::getImGuiDataType<T>(), data, ImGuiInputTextFlags_CharsScientific);
} else {
return false;
}
}
private:
constexpr static inline auto ByteCount = sizeof(T);
constexpr static inline auto CharCount = 14;
const static inline auto FormatStringUpperCase = hex::format("%{}G", CharCount);
const static inline auto FormatStringLowerCase = hex::format("%{}g", CharCount);
const char *getFormatString(bool upperCase) const {
if (upperCase)
return FormatStringUpperCase.c_str();
else
return FormatStringLowerCase.c_str();
}
};
template<>
class DataVisualizerFloatingPoint<Float16> : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
explicit DataVisualizerFloatingPoint(const std::string &name) : DataVisualizer(name, ByteCount, CharCount) { }
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
hex::unused(address);
if (size == ByteCount)
ImGui::Text(getFormatString(upperCase), hex::float16ToFloat32(*reinterpret_cast<const u16*>(data)));
else
ImGuiExt::TextFormatted("{: {}s}", CharCount);
}
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
hex::unused(startedEditing);
this->draw(address, data, size, upperCase);
return false;
}
private:
constexpr static inline auto ByteCount = sizeof(Float16);
constexpr static inline auto CharCount = 14;
const static inline auto FormatStringUpperCase = hex::format("%{}G", CharCount);
const static inline auto FormatStringLowerCase = hex::format("%{}g", CharCount);
static const char *getFormatString(bool upperCase) {
if (upperCase)
return FormatStringUpperCase.c_str();
else
return FormatStringLowerCase.c_str();
}
};
class DataVisualizerRGBA8 : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
DataVisualizerRGBA8() : DataVisualizer("hex.builtin.visualizer.rgba8", 4, 2) { }
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
hex::unused(address, upperCase);
if (size == 4)
ImGui::ColorButton("##color", ImColor(data[0], data[1], data[2], data[3]), ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoDragDrop, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
else
ImGui::ColorButton("##color", ImColor(0, 0, 0, 0xFF), ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoDragDrop, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
}
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
hex::unused(address, data, size, upperCase);
m_currColor = { float(data[0]) / 0xFF, float(data[1]) / 0xFF, float(data[2]) / 0xFF, float(data[3]) / 0xFF };
if (startedEditing) {
ImGui::OpenPopup("##color_popup");
}
ImGui::ColorButton("##color", ImColor(m_currColor[0], m_currColor[1], m_currColor[2], m_currColor[3]), ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoDragDrop, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
if (ImGui::BeginPopup("##color_popup")) {
if (ImGui::ColorPicker4("##picker", m_currColor.data(), ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_InputRGB)) {
for (u8 i = 0; i < 4; i++)
data[i] = m_currColor[i] * 0xFF;
}
ImGui::EndPopup();
} else {
return true;
}
return false;
}
std::array<float, 4> m_currColor = { 0 };
};
class DataVisualizerBinary : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
DataVisualizerBinary() : DataVisualizer("hex.builtin.visualizer.binary", 1, 8) { }
void draw(u64 address, const u8 *data, size_t size, bool) override {
hex::unused(address);
if (size == 1)
ImGuiExt::TextFormatted("{:08b}", *data);
}
bool drawEditing(u64 address, u8 *data, size_t, bool, bool startedEditing) override {
hex::unused(address, startedEditing);
if (startedEditing) {
m_inputBuffer = hex::format("{:08b}", *data);
}
if (drawDefaultTextEditingTextBox(address, m_inputBuffer, ImGuiInputTextFlags_None)) {
if (auto result = hex::parseBinaryString(wolv::util::trim(m_inputBuffer)); result.has_value()) {
*data = result.value();
return true;
}
}
return false;
}
private:
std::string m_inputBuffer;
};
void registerDataVisualizers() {
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerHexadecimal<u8>>("hex.builtin.visualizer.hexadecimal.8bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerHexadecimal<u16>>("hex.builtin.visualizer.hexadecimal.16bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerHexadecimal<u32>>("hex.builtin.visualizer.hexadecimal.32bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerHexadecimal<u64>>("hex.builtin.visualizer.hexadecimal.64bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<u8>>("hex.builtin.visualizer.decimal.unsigned.8bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<u16>>("hex.builtin.visualizer.decimal.unsigned.16bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<u32>>("hex.builtin.visualizer.decimal.unsigned.32bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<u64>>("hex.builtin.visualizer.decimal.unsigned.64bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i8>>("hex.builtin.visualizer.decimal.signed.8bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i16>>("hex.builtin.visualizer.decimal.signed.16bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i32>>("hex.builtin.visualizer.decimal.signed.32bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i64>>("hex.builtin.visualizer.decimal.signed.64bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<Float16>>("hex.builtin.visualizer.floating_point.16bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<float>>("hex.builtin.visualizer.floating_point.32bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<double>>("hex.builtin.visualizer.floating_point.64bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerRGBA8>();
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerHexii>();
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerBinary>();
}
}