feat: Add support for custom inspector edit widgets

This commit is contained in:
WerWolv 2025-12-12 13:15:16 +01:00
parent 21e61bfce6
commit de25ce7fbb
4 changed files with 152 additions and 107 deletions

View File

@ -8,6 +8,7 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <bit>
EXPORT_MODULE namespace hex { EXPORT_MODULE namespace hex {
@ -22,8 +23,10 @@ EXPORT_MODULE namespace hex {
namespace impl { namespace impl {
struct DoNotUseThisByItselfTag {};
using DisplayFunction = std::function<std::string()>; using DisplayFunction = std::function<std::string()>;
using EditingFunction = std::function<std::vector<u8>(std::string, std::endian)>; using EditingFunction = std::function<std::optional<std::vector<u8>>(std::string&, std::endian, DoNotUseThisByItselfTag)>;
using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8> &, std::endian, NumberDisplayStyle)>; using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8> &, std::endian, NumberDisplayStyle)>;
struct Entry { struct Entry {
@ -38,6 +41,35 @@ EXPORT_MODULE namespace hex {
} }
namespace EditWidget {
class Widget {
public:
using Function = std::function<std::vector<u8>(const std::string&, std::endian)>;
explicit Widget(const Function &function) : m_function(function) {}
virtual ~Widget() = default;
virtual std::optional<std::vector<u8>> draw(std::string &value, std::endian endian) = 0;
std::optional<std::vector<u8>> operator()(std::string &value, std::endian endian, impl::DoNotUseThisByItselfTag) {
return draw(value, endian);
}
std::vector<u8> getBytes(const std::string &value, std::endian endian) const {
return m_function(value, endian);
}
private:
Function m_function;
};
struct TextInput : Widget {
explicit TextInput(const Function &function) : Widget(function) {}
std::optional<std::vector<u8>> draw(std::string &value, std::endian endian) override;
};
}
/** /**
* @brief Adds a new entry to the data inspector * @brief Adds a new entry to the data inspector
* @param unlocalizedName The unlocalized name of the entry * @param unlocalizedName The unlocalized name of the entry

View File

@ -870,6 +870,18 @@ namespace hex {
} }
namespace EditWidget {
std::optional<std::vector<u8>> TextInput::draw(std::string &value, std::endian endian) {
if (ImGui::InputText("##InspectorLineEditing", value,
ImGuiInputTextFlags_EnterReturnsTrue |
ImGuiInputTextFlags_AutoSelectAll)) {
return getBytes(value, endian);
}
return std::nullopt;
}
}
void add(const UnlocalizedString &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) { void add(const UnlocalizedString &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
log::debug("Registered new data inspector format: {}", unlocalizedName.get()); log::debug("Registered new data inspector format: {}", unlocalizedName.get());

View File

@ -33,7 +33,8 @@ namespace hex::plugin::builtin {
}; };
template<std::unsigned_integral T, size_t Size = sizeof(T)> template<std::unsigned_integral T, size_t Size = sizeof(T)>
static std::vector<u8> stringToUnsigned(const std::string &value, std::endian endian) requires(sizeof(T) <= sizeof(u64)) { static ContentRegistry::DataInspector::impl::EditingFunction stringToUnsigned() requires(sizeof(T) <= sizeof(u64)) {
return ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
const auto result = wolv::util::from_chars<u64>(value).value_or(0); const auto result = wolv::util::from_chars<u64>(value).value_or(0);
if (result > std::numeric_limits<T>::max()) return {}; if (result > std::numeric_limits<T>::max()) return {};
@ -44,10 +45,12 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
});
} }
template<std::signed_integral T, size_t Size = sizeof(T)> template<std::signed_integral T, size_t Size = sizeof(T)>
static std::vector<u8> stringToSigned(const std::string &value, std::endian endian) requires(sizeof(T) <= sizeof(u64)) { static ContentRegistry::DataInspector::impl::EditingFunction stringToSigned() requires(sizeof(T) <= sizeof(u64)) {
return ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
const auto result = wolv::util::from_chars<i64>(value).value_or(0); const auto result = wolv::util::from_chars<i64>(value).value_or(0);
if (result > std::numeric_limits<T>::max() || result < std::numeric_limits<T>::min()) return {}; if (result > std::numeric_limits<T>::max() || result < std::numeric_limits<T>::min()) return {};
@ -58,10 +61,12 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
});
} }
template<std::floating_point T> template<std::floating_point T>
static std::vector<u8> stringToFloat(const std::string &value, std::endian endian) requires(sizeof(T) <= sizeof(long double)) { static ContentRegistry::DataInspector::impl::EditingFunction stringToFloat() requires(sizeof(T) <= sizeof(long double)) {
return ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
const T result = wolv::util::from_chars<double>(value).value_or(0); const T result = wolv::util::from_chars<double>(value).value_or(0);
std::vector<u8> bytes(sizeof(T), 0x00); std::vector<u8> bytes(sizeof(T), 0x00);
@ -71,16 +76,17 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
});
} }
template<std::integral T, size_t Size = sizeof(T)> template<std::integral T, size_t Size = sizeof(T)>
static std::vector<u8> stringToInteger(const std::string &value, std::endian endian) requires(sizeof(T) <= sizeof(u64)) { static ContentRegistry::DataInspector::impl::EditingFunction stringToInteger() requires(sizeof(T) <= sizeof(u64)) {
if constexpr (std::unsigned_integral<T>) if constexpr (std::unsigned_integral<T>)
return stringToUnsigned<T, Size>(value, endian); return stringToUnsigned<T, Size>();
else if constexpr (std::signed_integral<T>) else if constexpr (std::signed_integral<T>)
return stringToSigned<T, Size>(value, endian); return stringToSigned<T, Size>();
else else
return {}; static_assert("Unsupported type for stringToInteger");
} }
template<std::unsigned_integral T, size_t Size = sizeof(T)> template<std::unsigned_integral T, size_t Size = sizeof(T)>
@ -154,7 +160,8 @@ namespace hex::plugin::builtin {
ImGui::TextUnformatted(binary.c_str()); ImGui::TextUnformatted(binary.c_str());
return binary; return binary;
}; };
}, [](const std::string &value, std::endian endian) -> std::vector<u8> { },
ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; std::ignore = endian;
std::string binary = value; std::string binary = value;
@ -167,69 +174,69 @@ namespace hex::plugin::builtin {
return { result.value() }; return { result.value() };
else else
return { }; return { };
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u8", sizeof(u8), ContentRegistry::DataInspector::add("hex.builtin.inspector.u8", sizeof(u8),
drawString<u8>(integerToString<u8>), drawString<u8>(integerToString<u8>),
stringToInteger<u8> stringToInteger<u8>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i8", sizeof(i8), ContentRegistry::DataInspector::add("hex.builtin.inspector.i8", sizeof(i8),
drawString<i8>(integerToString<i8>), drawString<i8>(integerToString<i8>),
stringToInteger<i8> stringToInteger<i8>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u16", sizeof(u16), ContentRegistry::DataInspector::add("hex.builtin.inspector.u16", sizeof(u16),
drawString<u16>(integerToString<u16>), drawString<u16>(integerToString<u16>),
stringToInteger<u16> stringToInteger<u16>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i16", sizeof(i16), ContentRegistry::DataInspector::add("hex.builtin.inspector.i16", sizeof(i16),
drawString<i16>(integerToString<i16>), drawString<i16>(integerToString<i16>),
stringToInteger<i16> stringToInteger<i16>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u24", 3, ContentRegistry::DataInspector::add("hex.builtin.inspector.u24", 3,
drawString<u32, 3>(integerToString<u32, 3>), drawString<u32, 3>(integerToString<u32, 3>),
stringToInteger<u32, 3> stringToInteger<u32, 3>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i24", 3, ContentRegistry::DataInspector::add("hex.builtin.inspector.i24", 3,
drawString<i32, 3>(integerToString<i32, 3>), drawString<i32, 3>(integerToString<i32, 3>),
stringToInteger<i32, 3> stringToInteger<i32, 3>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u32", sizeof(u32), ContentRegistry::DataInspector::add("hex.builtin.inspector.u32", sizeof(u32),
drawString<u32>(integerToString<u32>), drawString<u32>(integerToString<u32>),
stringToInteger<u32> stringToInteger<u32>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i32", sizeof(i32), ContentRegistry::DataInspector::add("hex.builtin.inspector.i32", sizeof(i32),
drawString<i32>(integerToString<i32>), drawString<i32>(integerToString<i32>),
stringToInteger<i32> stringToInteger<i32>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u48", 6, ContentRegistry::DataInspector::add("hex.builtin.inspector.u48", 6,
drawString<u64, 6>(integerToString<u64, 6>), drawString<u64, 6>(integerToString<u64, 6>),
stringToInteger<u64, 6> stringToInteger<u64, 6>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i48", 6, ContentRegistry::DataInspector::add("hex.builtin.inspector.i48", 6,
drawString<i64, 6>(integerToString<i64, 6>), drawString<i64, 6>(integerToString<i64, 6>),
stringToInteger<i64, 6> stringToInteger<i64, 6>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u64", sizeof(u64), ContentRegistry::DataInspector::add("hex.builtin.inspector.u64", sizeof(u64),
drawString<u64>(integerToString<u64>), drawString<u64>(integerToString<u64>),
stringToInteger<u64> stringToInteger<u64>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i64", sizeof(i64), ContentRegistry::DataInspector::add("hex.builtin.inspector.i64", sizeof(i64),
drawString<i64>(integerToString<i64>), drawString<i64>(integerToString<i64>),
stringToInteger<i64> stringToInteger<i64>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.float16", sizeof(u16), ContentRegistry::DataInspector::add("hex.builtin.inspector.float16", sizeof(u16),
@ -255,7 +262,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian)); auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian));
return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
}, },
stringToFloat<float> stringToFloat<float>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.double", sizeof(double), ContentRegistry::DataInspector::add("hex.builtin.inspector.double", sizeof(double),
@ -268,7 +275,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian)); auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian));
return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
}, },
stringToFloat<double> stringToFloat<double>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.long_double", sizeof(long double), ContentRegistry::DataInspector::add("hex.builtin.inspector.long_double", sizeof(long double),
@ -281,7 +288,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian)); auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian));
return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
}, },
stringToFloat<long double> stringToFloat<long double>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.bfloat16", sizeof(u16), ContentRegistry::DataInspector::add("hex.builtin.inspector.bfloat16", sizeof(u16),
@ -359,11 +366,11 @@ namespace hex::plugin::builtin {
return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; std::ignore = endian;
return hex::crypt::encodeSleb128(wolv::util::from_chars<i64>(value).value_or(0)); return hex::crypt::encodeSleb128(wolv::util::from_chars<i64>(value).value_or(0));
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.uleb128", 1, (sizeof(u128) * 8 / 7) + 1, ContentRegistry::DataInspector::add("hex.builtin.inspector.uleb128", 1, (sizeof(u128) * 8 / 7) + 1,
@ -376,11 +383,11 @@ namespace hex::plugin::builtin {
return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; std::ignore = endian;
return hex::crypt::encodeUleb128(wolv::util::from_chars<u64>(value).value_or(0)); return hex::crypt::encodeUleb128(wolv::util::from_chars<u64>(value).value_or(0));
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.bool", sizeof(bool), ContentRegistry::DataInspector::add("hex.builtin.inspector.bool", sizeof(bool),
@ -411,13 +418,13 @@ namespace hex::plugin::builtin {
auto value = makePrintable(*reinterpret_cast<char8_t *>(buffer.data())); auto value = makePrintable(*reinterpret_cast<char8_t *>(buffer.data()));
return [value] { ImGuiExt::TextFormatted("'{0}'", value.c_str()); return value; }; return [value] { ImGuiExt::TextFormatted("'{0}'", value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; std::ignore = endian;
if (value.length() > 1) return { }; if (value.length() > 1) return { };
return { u8(value[0]) }; return { u8(value[0]) };
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.wide", sizeof(wchar_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.wide", sizeof(wchar_t),
@ -432,7 +439,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::wstringToUtf8(std::wstring(&c, 1)).value_or("???")); auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::wstringToUtf8(std::wstring(&c, 1)).value_or("???"));
return [value] { ImGuiExt::TextFormatted("L'{0}'", value.c_str()); return value; }; return [value] { ImGuiExt::TextFormatted("L'{0}'", value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::vector<u8> bytes; std::vector<u8> bytes;
auto wideString = wolv::util::utf8ToWstring(value); auto wideString = wolv::util::utf8ToWstring(value);
if (!wideString.has_value()) if (!wideString.has_value())
@ -445,7 +452,7 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.char16", sizeof(char16_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.char16", sizeof(char16_t),
@ -460,7 +467,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::utf16ToUtf8(std::u16string(&c, 1)).value_or("???")); auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::utf16ToUtf8(std::u16string(&c, 1)).value_or("???"));
return [value] { ImGuiExt::TextFormatted("u'{0}'", value.c_str()); return value; }; return [value] { ImGuiExt::TextFormatted("u'{0}'", value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::vector<u8> bytes; std::vector<u8> bytes;
auto wideString = wolv::util::utf8ToUtf16(value); auto wideString = wolv::util::utf8ToUtf16(value);
if (!wideString.has_value()) if (!wideString.has_value())
@ -473,7 +480,7 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.char32", sizeof(char32_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.char32", sizeof(char32_t),
@ -488,7 +495,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::utf32ToUtf8(std::u32string(&c, 1)).value_or("???")); auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::utf32ToUtf8(std::u32string(&c, 1)).value_or("???"));
return [value] { ImGuiExt::TextFormatted("U'{0}'", value.c_str()); return value; }; return [value] { ImGuiExt::TextFormatted("U'{0}'", value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::vector<u8> bytes; std::vector<u8> bytes;
auto wideString = wolv::util::utf8ToUtf32(value); auto wideString = wolv::util::utf8ToUtf32(value);
if (!wideString.has_value()) if (!wideString.has_value())
@ -501,7 +508,7 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.utf8", sizeof(char8_t) * 4, ContentRegistry::DataInspector::add("hex.builtin.inspector.utf8", sizeof(char8_t) * 4,
@ -551,11 +558,11 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("\"{0}\"", value.c_str()); return copyValue; }; return [value, copyValue] { ImGuiExt::TextFormatted("\"{0}\"", value.c_str()); return copyValue; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; std::ignore = endian;
return hex::decodeByteString(value); return hex::decodeByteString(value);
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.wstring", sizeof(wchar_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.wstring", sizeof(wchar_t),
@ -588,7 +595,7 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("L\"{0}\"", value.c_str()); return copyValue; }; return [value, copyValue] { ImGuiExt::TextFormatted("L\"{0}\"", value.c_str()); return copyValue; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
auto utf8 = hex::decodeByteString(value); auto utf8 = hex::decodeByteString(value);
auto wstring = wolv::util::utf8ToWstring({ utf8.begin(), utf8.end() }); auto wstring = wolv::util::utf8ToWstring({ utf8.begin(), utf8.end() });
if (!wstring.has_value()) if (!wstring.has_value())
@ -601,7 +608,7 @@ namespace hex::plugin::builtin {
std::vector<u8> bytes(wstring->size() * sizeof(wchar_t), 0x00); std::vector<u8> bytes(wstring->size() * sizeof(wchar_t), 0x00);
std::memcpy(bytes.data(), wstring->data(), bytes.size()); std::memcpy(bytes.data(), wstring->data(), bytes.size());
return bytes; return bytes;
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.string16", sizeof(char16_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.string16", sizeof(char16_t),
@ -634,7 +641,7 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("u\"{0}\"", value.c_str()); return copyValue; }; return [value, copyValue] { ImGuiExt::TextFormatted("u\"{0}\"", value.c_str()); return copyValue; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
auto utf8 = hex::decodeByteString(value); auto utf8 = hex::decodeByteString(value);
auto utf16 = wolv::util::utf8ToUtf16({ utf8.begin(), utf8.end() }); auto utf16 = wolv::util::utf8ToUtf16({ utf8.begin(), utf8.end() });
if (!utf16.has_value()) if (!utf16.has_value())
@ -647,7 +654,7 @@ namespace hex::plugin::builtin {
std::vector<u8> bytes(utf16->size() * sizeof(char16_t), 0x00); std::vector<u8> bytes(utf16->size() * sizeof(char16_t), 0x00);
std::memcpy(bytes.data(), utf16->data(), bytes.size()); std::memcpy(bytes.data(), utf16->data(), bytes.size());
return bytes; return bytes;
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.string32", sizeof(char32_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.string32", sizeof(char32_t),
@ -680,7 +687,7 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("U\"{0}\"", value.c_str()); return copyValue; }; return [value, copyValue] { ImGuiExt::TextFormatted("U\"{0}\"", value.c_str()); return copyValue; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
auto utf8 = hex::decodeByteString(value); auto utf8 = hex::decodeByteString(value);
auto utf32 = wolv::util::utf8ToUtf32({ utf8.begin(), utf8.end() }); auto utf32 = wolv::util::utf8ToUtf32({ utf8.begin(), utf8.end() });
if (!utf32.has_value()) if (!utf32.has_value())
@ -693,7 +700,7 @@ namespace hex::plugin::builtin {
std::vector<u8> bytes(utf32->size() * sizeof(char32_t), 0x00); std::vector<u8> bytes(utf32->size() * sizeof(char32_t), 0x00);
std::memcpy(bytes.data(), utf32->data(), bytes.size()); std::memcpy(bytes.data(), utf32->data(), bytes.size());
return bytes; return bytes;
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.custom_encoding", 1, [encodingFile = EncodingFile()](const std::vector<u8> &, std::endian, Style) mutable { ContentRegistry::DataInspector::add("hex.builtin.inspector.custom_encoding", 1, [encodingFile = EncodingFile()](const std::vector<u8> &, std::endian, Style) mutable {

View File

@ -198,8 +198,7 @@ namespace hex::plugin::builtin {
// Set up the editing function if a write formatter is available // Set up the editing function if a write formatter is available
std::optional<ContentRegistry::DataInspector::impl::EditingFunction> editingFunction; std::optional<ContentRegistry::DataInspector::impl::EditingFunction> editingFunction;
if (!pattern->getWriteFormatterFunction().empty()) { if (!pattern->getWriteFormatterFunction().empty()) {
editingFunction = [&pattern](const std::string &value, editingFunction = ContentRegistry::DataInspector::EditWidget::TextInput([&pattern](const std::string &value, std::endian) -> std::vector<u8> {
std::endian) -> std::vector<u8> {
try { try {
pattern->setValue(value); pattern->setValue(value);
} catch (const pl::core::err::EvaluatorError::Exception &error) { } catch (const pl::core::err::EvaluatorError::Exception &error) {
@ -208,7 +207,7 @@ namespace hex::plugin::builtin {
} }
return {}; return {};
}; });
} }
try { try {
@ -441,7 +440,7 @@ namespace hex::plugin::builtin {
ImGui::SameLine(); ImGui::SameLine();
// Handle copying the value to the clipboard when clicking the row // Handle copying the value to the clipboard when clicking the row
if (ImGui::Selectable("##InspectorLine", m_selectedEntryName == entry.unlocalizedName, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap)) { if (ImGui::Selectable("##InspectorLine", m_selectedEntryName == entry.unlocalizedName, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_AllowDoubleClick)) {
m_selectedEntryName = entry.unlocalizedName; m_selectedEntryName = entry.unlocalizedName;
if (auto selection = ImHexApi::HexEditor::getSelection(); selection.has_value()) { if (auto selection = ImHexApi::HexEditor::getSelection(); selection.has_value()) {
ImHexApi::HexEditor::setSelection(Region { selection->getStartAddress(), entry.requiredSize }); ImHexApi::HexEditor::setSelection(Region { selection->getStartAddress(), entry.requiredSize });
@ -476,10 +475,7 @@ namespace hex::plugin::builtin {
} }
ImGui::EndPopup(); ImGui::EndPopup();
} }
} else {
return;
}
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
entry.editing = false; entry.editing = false;
} }
@ -489,18 +485,14 @@ namespace hex::plugin::builtin {
ImGui::SetNextItemWidth(-1); ImGui::SetNextItemWidth(-1);
ImGui::SetKeyboardFocusHere(); ImGui::SetKeyboardFocusHere();
// Draw input text box // Draw editing widget and capture edited value
if (ImGui::InputText("##InspectorLineEditing", m_editingValue, auto bytes = (*entry.editingFunction)(m_editingValue, m_endian, {});
ImGuiInputTextFlags_EnterReturnsTrue | if (bytes.has_value()) {
ImGuiInputTextFlags_AutoSelectAll)) {
// Turn the entered value into bytes
auto bytes = entry.editingFunction.value()(m_editingValue, m_endian);
if (m_invert) if (m_invert)
std::ranges::transform(bytes, bytes.begin(), [](auto byte) { return byte ^ 0xFF; }); std::ranges::transform(*bytes, bytes->begin(), [](auto byte) { return byte ^ 0xFF; });
// Write those bytes to the selected provider at the current address // Write those bytes to the selected provider at the current address
m_selectedProvider->write(m_startAddress, bytes.data(), bytes.size()); m_selectedProvider->write(m_startAddress, bytes->data(), bytes->size());
// Disable editing mode // Disable editing mode
m_editingValue.clear(); m_editingValue.clear();
@ -519,6 +511,8 @@ namespace hex::plugin::builtin {
} }
} }
}
void ViewDataInspector::drawEndianSetting() { void ViewDataInspector::drawEndianSetting() {
if (ui::endiannessSlider(m_endian)) { if (ui::endiannessSlider(m_endian)) {
m_shouldInvalidate = true; m_shouldInvalidate = true;