1
0
mirror of synced 2024-12-22 04:25:54 +01:00
ImHex/lib/libimhex/source/api/content_registry.cpp

1359 lines
49 KiB
C++
Raw Normal View History

#include <hex/api/content_registry.hpp>
#include <hex/api/shortcut_manager.hpp>
#include <hex/helpers/fs.hpp>
2022-01-13 14:33:30 +01:00
#include <hex/helpers/logger.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/default_paths.hpp>
#include <hex/ui/view.hpp>
#include <hex/data_processor/node.hpp>
2024-02-18 11:29:18 +01:00
#include <algorithm>
#include <filesystem>
#include <jthread.hpp>
#if defined(OS_WEB)
#include <emscripten.h>
#endif
#include <hex/api/task_manager.hpp>
#include <nlohmann/json.hpp>
#include <wolv/io/file.hpp>
2023-07-09 12:53:31 +02:00
#include <wolv/utils/string.hpp>
namespace hex {
namespace ContentRegistry::Settings {
[[maybe_unused]] constexpr auto SettingsFile = "settings.json";
namespace impl {
2024-02-18 11:29:18 +01:00
struct OnChange {
u32 id;
OnChangeCallback callback;
};
static AutoReset<std::map<std::string, std::map<std::string, std::vector<OnChange>>>> s_onChangeCallbacks;
static AutoReset<nlohmann::json> s_settings;
const nlohmann::json& getSettingsData() {
return s_settings;
}
nlohmann::json& getSetting(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &defaultValue) {
auto &settings = *s_settings;
sys/build: Properly support per-system metadata file paths (#181) * sys: Move away from metadata paths next to executable in the application Build system doesn't properly install / pack stuff yet * build: Updated README to contain better install instructions * sys: Search for imhex resource files in ~/Application Support * sys: MAX_PATH -> PATH_MAX * sys: Seach for imhex resource files in Application Support using NSFileManager (#180) * sys: Allow for multiple file search paths Also use install prefix instead of just /usr on Linux * build: Fixed IMHEX_INSTALL_PREFIX macro definition * build: Fix duplicate switch entry on Linux * docs: Updated readme to properly reflect new paths and dependencies * sys: Install files in their proper paths on linux (#183) * Install files in their proper paths on linux * Only create user directories * Follow the XDG specification on linux XDG specification specifies how to find config and data directories on linux systems. Specifically, it says this: - Data should be written to $XDG_DATA_HOME - Config should be written to $XDG_CONFIG_HOME - Data should be read from $XDG_DATA_HOME:$XDG_DATA_DIRS - Config should be read from $XDG_CONFIG_HOME:$XDG_CONFIG_DIRS The default values are this: - XDG_DATA_HOME: $HOME/.local/share - XDG_CONFIG_HOME: $HOME/.config - XDG_DATA_DIRS: /usr/share:/usr/local/share - XDG_CONFIG_DIRS: /etc/xdg Platforms with non-standard filesystems (like NixOS) will correctly set up those environment variables, allowing softwares to work unmodified. In order to make integration as simple as possible, we use a simple header-only dependency called XDGPP which does all the hard work for us to find the default directories. * Look for plugins in all Plugin Paths If the plugin folder was missing from one of the PluginPaths, we would immediately stop loading plugins. We now keep looking even if one of the path is missing. Co-authored-by: Nichole Mattera <me@nicholemattera.com> Co-authored-by: Robin Lambertz <unfiltered@roblab.la>
2021-03-01 08:56:49 +01:00
if (!settings.contains(unlocalizedCategory))
settings[unlocalizedCategory] = {};
if (!settings[unlocalizedCategory].contains(unlocalizedName))
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
if (settings[unlocalizedCategory][unlocalizedName].is_null())
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
return settings[unlocalizedCategory][unlocalizedName];
}
#if defined(OS_WEB)
void load() {
char *data = (char *) MAIN_THREAD_EM_ASM_INT({
let data = localStorage.getItem("config");
return data ? stringToNewUTF8(data) : null;
});
if (data == nullptr) {
store();
} else {
s_settings = nlohmann::json::parse(data);
}
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
for (const auto &[name, callbacks] : rest) {
for (const auto &[id, callback] : callbacks) {
try {
callback(getSetting(category, name, {}));
} catch (const std::exception &e) {
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
}
}
}
}
}
void store() {
auto data = s_settings->dump();
MAIN_THREAD_EM_ASM({
localStorage.setItem("config", UTF8ToString($0));
}, data.c_str());
}
void clear() {
MAIN_THREAD_EM_ASM({
localStorage.removeItem("config");
});
feat: Added hex::group attribute and various fixes (#1302) As discussed (many times) on Discord, does the same as the new favorite tag, but instead allows you to add multiple groups. Initially, this would cause some insane issues with draw/reset (apparantly) fighting eachother in the pattern drawer. After a lot of trial and error, I decided to rewrite the flow that is responsible for calling reset. Now evaluating patterns is the one to decide when the reset happens, not the core "game"-loop. To make sure that draw and reset can never happen at the same time, the mutex originally used for the favorites has been repurposed. Due to the restructuring, the mutex in the favorite-task is no longer needed, as that will only ever kick-off after reset is called and if there are actually patterns, which can never line up to be accessed on different threads at the same time. Last but not least, I noticed that hard crashes could result in your config file getting overridden. I added a check to prevent that. Last I issue I can see is that if you use an excessive amount of favorites/groups, a crash can still happen, but it only happens when you close the program (occasionally, but unpredictable). Before, this would happen if you ran the evaluation a second time. I boiled the cause of the crash down to these lines of code in evaluator.cpp > patternDestroyed: ```cpp if (pattern->isPatternLocal()) { if (auto it = this->m_patternLocalStorage.find(pattern->getHeapAddress()); it != this->m_patternLocalStorage.end()) { auto &[key, data] = *it; data.referenceCount--; if (data.referenceCount == 0) this->m_patternLocalStorage.erase(it); } else if (!this->m_evaluated) { err::E0001.throwError(fmt::format("Double free of variable named '{}'.", pattern->getVariableName())); } } ``` Specifically, trying to access the `*it` is the reason for the crash (this was also the cause of the crashes before my fixes, but then during evaluation). I'm suspecting the root cause is somewhere in the `.clone` methods of the patterns. I'd say that for now a crash when closing the program is more acceptable than during evaluation (which can even happen if you use favorites).
2023-09-16 13:09:59 +02:00
}
#else
void load() {
bool loaded = false;
for (const auto &dir : paths::Config.read()) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read);
if (file.isValid()) {
s_settings = nlohmann::json::parse(file.readString());
loaded = true;
break;
}
}
feat: Added hex::group attribute and various fixes (#1302) As discussed (many times) on Discord, does the same as the new favorite tag, but instead allows you to add multiple groups. Initially, this would cause some insane issues with draw/reset (apparantly) fighting eachother in the pattern drawer. After a lot of trial and error, I decided to rewrite the flow that is responsible for calling reset. Now evaluating patterns is the one to decide when the reset happens, not the core "game"-loop. To make sure that draw and reset can never happen at the same time, the mutex originally used for the favorites has been repurposed. Due to the restructuring, the mutex in the favorite-task is no longer needed, as that will only ever kick-off after reset is called and if there are actually patterns, which can never line up to be accessed on different threads at the same time. Last but not least, I noticed that hard crashes could result in your config file getting overridden. I added a check to prevent that. Last I issue I can see is that if you use an excessive amount of favorites/groups, a crash can still happen, but it only happens when you close the program (occasionally, but unpredictable). Before, this would happen if you ran the evaluation a second time. I boiled the cause of the crash down to these lines of code in evaluator.cpp > patternDestroyed: ```cpp if (pattern->isPatternLocal()) { if (auto it = this->m_patternLocalStorage.find(pattern->getHeapAddress()); it != this->m_patternLocalStorage.end()) { auto &[key, data] = *it; data.referenceCount--; if (data.referenceCount == 0) this->m_patternLocalStorage.erase(it); } else if (!this->m_evaluated) { err::E0001.throwError(fmt::format("Double free of variable named '{}'.", pattern->getVariableName())); } } ``` Specifically, trying to access the `*it` is the reason for the crash (this was also the cause of the crashes before my fixes, but then during evaluation). I'm suspecting the root cause is somewhere in the `.clone` methods of the patterns. I'd say that for now a crash when closing the program is more acceptable than during evaluation (which can even happen if you use favorites).
2023-09-16 13:09:59 +02:00
if (!loaded)
store();
2024-02-18 11:29:18 +01:00
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
for (const auto &[name, callbacks] : rest) {
for (const auto &[id, callback] : callbacks) {
try {
callback(getSetting(category, name, {}));
} catch (const std::exception &e) {
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
}
2024-02-18 11:29:18 +01:00
}
}
}
}
void store() {
if (!s_settings.isValid())
return;
const auto &settingsData = *s_settings;
2023-12-27 16:53:03 +01:00
// During a crash settings can be empty, causing them to be overwritten.
2023-12-27 16:53:03 +01:00
if (settingsData.empty()) {
return;
}
const auto result = settingsData.dump(4);
if (result.empty()) {
return;
}
for (const auto &dir : paths::Config.write()) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
if (file.isValid()) {
2023-12-27 16:53:03 +01:00
file.writeString(result);
break;
}
}
}
void clear() {
for (const auto &dir : paths::Config.write()) {
wolv::io::fs::remove(dir / SettingsFile);
}
}
#endif
template<typename T>
static T* insertOrGetEntry(std::vector<T> &vector, const UnlocalizedString &unlocalizedName) {
T *foundEntry = nullptr;
for (auto &entry : vector) {
if (entry.unlocalizedName == unlocalizedName) {
foundEntry = &entry;
break;
}
}
if (foundEntry == nullptr) {
if (unlocalizedName.empty())
foundEntry = &*vector.emplace(vector.begin(), unlocalizedName);
else
foundEntry = &vector.emplace_back(unlocalizedName);
}
return foundEntry;
}
static AutoReset<std::vector<Category>> s_categories;
const std::vector<Category>& getSettings() {
return *s_categories;
}
Widgets::Widget* add(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedSubCategory, const UnlocalizedString &unlocalizedName, std::unique_ptr<Widgets::Widget> &&widget) {
const auto category = insertOrGetEntry(*s_categories, unlocalizedCategory);
2023-11-10 14:48:26 +01:00
const auto subCategory = insertOrGetEntry(category->subCategories, unlocalizedSubCategory);
const auto entry = insertOrGetEntry(subCategory->entries, unlocalizedName);
2022-01-13 14:34:27 +01:00
entry->widget = std::move(widget);
return entry->widget.get();
}
void printSettingReadError(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json::exception& e) {
hex::log::error("Failed to read setting {}/{}: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
}
2024-02-18 11:29:18 +01:00
void runOnChangeHandlers(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &value) {
if (auto categoryIt = s_onChangeCallbacks->find(unlocalizedCategory); categoryIt != s_onChangeCallbacks->end()) {
if (auto nameIt = categoryIt->second.find(unlocalizedName); nameIt != categoryIt->second.end()) {
for (const auto &[id, callback] : nameIt->second) {
try {
callback(value);
} catch (const nlohmann::json::exception &e) {
log::error("Failed to run onChange handler for setting {}/{}: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
}
}
}
}
}
}
void setCategoryDescription(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedDescription) {
const auto category = insertOrGetEntry(*impl::s_categories, unlocalizedCategory);
category->unlocalizedDescription = unlocalizedDescription;
}
2022-01-13 14:34:27 +01:00
2024-02-18 11:29:18 +01:00
u64 onChange(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const OnChangeCallback &callback) {
static u64 id = 1;
(*impl::s_onChangeCallbacks)[unlocalizedCategory][unlocalizedName].emplace_back(id, callback);
auto result = id;
id += 1;
return result;
}
void removeOnChangeHandler(u64 id) {
bool done = false;
auto categoryIt = impl::s_onChangeCallbacks->begin();
for (; categoryIt != impl::s_onChangeCallbacks->end(); ++categoryIt) {
auto nameIt = categoryIt->second.begin();
for (; nameIt != categoryIt->second.end(); ++nameIt) {
done = std::erase_if(nameIt->second, [id](const impl::OnChange &entry) {
return entry.id == id;
}) > 0;
if (done) break;
}
if (done) {
if (nameIt->second.empty())
categoryIt->second.erase(nameIt);
break;
}
}
if (done) {
if (categoryIt->second.empty())
impl::s_onChangeCallbacks->erase(categoryIt);
}
}
namespace Widgets {
bool Checkbox::draw(const std::string &name) {
2023-12-19 13:10:25 +01:00
return ImGui::Checkbox(name.c_str(), &m_value);
}
void Checkbox::load(const nlohmann::json &data) {
if (data.is_number()) {
2023-12-19 13:10:25 +01:00
m_value = data.get<int>() != 0;
} else if (data.is_boolean()) {
2023-12-19 13:10:25 +01:00
m_value = data.get<bool>();
} else {
log::warn("Invalid data type loaded from settings for checkbox!");
}
}
nlohmann::json Checkbox::store() {
2023-12-19 13:10:25 +01:00
return m_value;
}
bool SliderInteger::draw(const std::string &name) {
2023-12-19 13:10:25 +01:00
return ImGui::SliderInt(name.c_str(), &m_value, m_min, m_max);
}
void SliderInteger::load(const nlohmann::json &data) {
if (data.is_number_integer()) {
2023-12-19 13:10:25 +01:00
m_value = data.get<int>();
} else {
log::warn("Invalid data type loaded from settings for slider!");
}
}
nlohmann::json SliderInteger::store() {
2023-12-19 13:10:25 +01:00
return m_value;
}
bool SliderFloat::draw(const std::string &name) {
2023-12-19 13:10:25 +01:00
return ImGui::SliderFloat(name.c_str(), &m_value, m_min, m_max);
}
void SliderFloat::load(const nlohmann::json &data) {
if (data.is_number()) {
2023-12-19 13:10:25 +01:00
m_value = data.get<float>();
} else {
log::warn("Invalid data type loaded from settings for slider!");
}
}
nlohmann::json SliderFloat::store() {
2023-12-19 13:10:25 +01:00
return m_value;
}
bool SliderDataSize::draw(const std::string &name) {
return ImGuiExt::SliderBytes(name.c_str(), &m_value, m_min, m_max);
}
void SliderDataSize::load(const nlohmann::json &data) {
if (data.is_number_integer()) {
m_value = data.get<u64>();
} else {
log::warn("Invalid data type loaded from settings for slider!");
}
}
nlohmann::json SliderDataSize::store() {
return m_value;
}
ColorPicker::ColorPicker(ImColor defaultColor) {
2023-12-19 13:10:25 +01:00
m_value = {
defaultColor.Value.x,
defaultColor.Value.y,
defaultColor.Value.z,
defaultColor.Value.w
};
}
bool ColorPicker::draw(const std::string &name) {
2023-12-19 13:10:25 +01:00
return ImGui::ColorEdit4(name.c_str(), m_value.data(), ImGuiColorEditFlags_NoInputs);
}
void ColorPicker::load(const nlohmann::json &data) {
if (data.is_number()) {
const ImColor color(data.get<u32>());
2023-12-19 13:10:25 +01:00
m_value = { color.Value.x, color.Value.y, color.Value.z, color.Value.w };
} else {
log::warn("Invalid data type loaded from settings for color picker!");
}
}
nlohmann::json ColorPicker::store() {
2023-12-19 13:10:25 +01:00
const ImColor color(m_value[0], m_value[1], m_value[2], m_value[3]);
2023-11-10 14:48:26 +01:00
return static_cast<ImU32>(color);
}
ImColor ColorPicker::getColor() const {
2023-12-19 13:10:25 +01:00
return { m_value[0], m_value[1], m_value[2], m_value[3] };
}
bool DropDown::draw(const std::string &name) {
auto preview = "";
2023-12-19 13:10:25 +01:00
if (static_cast<size_t>(m_value) < m_items.size())
preview = m_items[m_value].c_str();
bool changed = false;
if (ImGui::BeginCombo(name.c_str(), Lang(preview))) {
int index = 0;
2023-12-19 13:10:25 +01:00
for (const auto &item : m_items) {
const bool selected = index == m_value;
if (ImGui::Selectable(Lang(item), selected)) {
2023-12-19 13:10:25 +01:00
m_value = index;
changed = true;
}
if (selected)
ImGui::SetItemDefaultFocus();
index += 1;
}
ImGui::EndCombo();
}
return changed;
}
void DropDown::load(const nlohmann::json &data) {
2023-12-19 13:10:25 +01:00
m_value = 0;
int defaultItemIndex = 0;
int index = 0;
2023-12-19 13:10:25 +01:00
for (const auto &item : m_settingsValues) {
if (item == m_defaultItem)
defaultItemIndex = index;
if (item == data) {
2023-12-19 13:10:25 +01:00
m_value = index;
return;
}
index += 1;
}
2023-12-19 13:10:25 +01:00
m_value = defaultItemIndex;
}
nlohmann::json DropDown::store() {
2023-12-19 13:10:25 +01:00
if (m_value == -1)
return m_defaultItem;
if (static_cast<size_t>(m_value) >= m_items.size())
return m_defaultItem;
2023-12-19 13:10:25 +01:00
return m_settingsValues[m_value];
}
const nlohmann::json& DropDown::getValue() const {
2023-12-19 13:10:25 +01:00
return m_settingsValues[m_value];
}
bool TextBox::draw(const std::string &name) {
2023-12-19 13:10:25 +01:00
return ImGui::InputText(name.c_str(), m_value);
}
void TextBox::load(const nlohmann::json &data) {
if (data.is_string()) {
2023-12-19 13:10:25 +01:00
m_value = data.get<std::string>();
} else {
log::warn("Invalid data type loaded from settings for text box!");
}
}
nlohmann::json TextBox::store() {
2023-12-19 13:10:25 +01:00
return m_value;
}
bool FilePicker::draw(const std::string &name) {
bool changed = false;
auto pathString = wolv::util::toUTF8String(m_path);
if (ImGui::InputText("##font_path", pathString)) {
changed = true;
}
ImGui::SameLine();
if (ImGuiExt::IconButton("...", ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
changed = fs::openFileBrowser(fs::DialogMode::Open, { { "TTF Font", "ttf" }, { "OTF Font", "otf" } },
[&](const std::fs::path &path) {
pathString = wolv::util::toUTF8String(path);
});
}
ImGui::SameLine();
ImGuiExt::TextFormatted("{}", name);
if (changed) {
m_path = pathString;
}
return changed;
}
void FilePicker::load(const nlohmann::json &data) {
if (data.is_string()) {
m_path = data.get<std::fs::path>();
} else {
log::warn("Invalid data type loaded from settings for file picker!");
}
}
nlohmann::json FilePicker::store() {
return m_path;
}
bool Label::draw(const std::string& name) {
ImGui::NewLine();
ImGui::TextUnformatted(name.c_str());
return false;
}
}
}
2021-01-11 21:11:03 +01:00
namespace ContentRegistry::CommandPaletteCommands {
namespace impl {
static AutoReset<std::vector<Entry>> s_entries;
const std::vector<Entry>& getEntries() {
return *s_entries;
}
static AutoReset<std::vector<Handler>> s_handlers;
const std::vector<Handler>& getHandlers() {
return *s_handlers;
}
}
void add(Type type, const std::string &command, const UnlocalizedString &unlocalizedDescription, const impl::DisplayCallback &displayCallback, const impl::ExecuteCallback &executeCallback) {
log::debug("Registered new command palette command: {}", command);
2022-01-13 14:34:27 +01:00
impl::s_entries->push_back(impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
}
void addHandler(Type type, const std::string &command, const impl::QueryCallback &queryCallback, const impl::DisplayCallback &displayCallback) {
log::debug("Registered new command palette command handler: {}", command);
impl::s_handlers->push_back(impl::Handler { type, command, queryCallback, displayCallback });
}
}
namespace ContentRegistry::PatternLanguage {
namespace impl {
static AutoReset<std::map<std::string, Visualizer>> s_visualizers;
const std::map<std::string, Visualizer>& getVisualizers() {
return *s_visualizers;
}
static AutoReset<std::map<std::string, Visualizer>> s_inlineVisualizers;
const std::map<std::string, Visualizer>& getInlineVisualizers() {
return *s_inlineVisualizers;
}
static AutoReset<std::map<std::string, pl::api::PragmaHandler>> s_pragmas;
const std::map<std::string, pl::api::PragmaHandler>& getPragmas() {
return *s_pragmas;
}
static AutoReset<std::vector<FunctionDefinition>> s_functions;
const std::vector<FunctionDefinition>& getFunctions() {
return *s_functions;
}
}
static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) {
std::string functionName;
for (auto &scope : ns)
functionName += scope + "::";
functionName += name;
return functionName;
}
pl::PatternLanguage& getRuntime() {
static PerProvider<pl::PatternLanguage> runtime;
AT_FIRST_TIME {
runtime.setOnCreateCallback([](prv::Provider *provider, pl::PatternLanguage &runtime) {
configureRuntime(runtime, provider);
});
};
return *runtime;
}
std::mutex& getRuntimeLock() {
static std::mutex runtimeLock;
return runtimeLock;
}
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) {
runtime.reset();
if (provider != nullptr) {
2022-12-16 11:20:39 +01:00
runtime.setDataSource(provider->getBaseAddress(), provider->getActualSize(),
[provider](u64 offset, u8 *buffer, size_t size) {
provider->read(offset, buffer, size);
},
[provider](u64 offset, const u8 *buffer, size_t size) {
if (provider->isWritable())
provider->write(offset, buffer, size);
}
);
}
2022-01-13 14:34:27 +01:00
runtime.setIncludePaths(paths::PatternsInclude.read() | paths::Patterns.read());
2023-11-10 14:48:26 +01:00
for (const auto &[ns, name, paramCount, callback, dangerous] : impl::getFunctions()) {
if (dangerous)
runtime.addDangerousFunction(ns, name, paramCount, callback);
else
2023-11-10 14:48:26 +01:00
runtime.addFunction(ns, name, paramCount, callback);
}
2022-01-13 14:34:27 +01:00
for (const auto &[name, callback] : impl::getPragmas()) {
runtime.addPragma(name, callback);
}
runtime.addDefine("__IMHEX__");
runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion());
}
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
log::debug("Registered new pattern language pragma: {}", name);
(*impl::s_pragmas)[name] = handler;
}
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
log::debug("Registered new pattern language function: {}", getFunctionName(ns, name));
impl::s_functions->push_back({
ns, name,
parameterCount, func,
false
});
}
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
log::debug("Registered new dangerous pattern language function: {}", getFunctionName(ns, name));
impl::s_functions->push_back({
ns, name,
parameterCount, func,
true
});
}
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) {
log::debug("Registered new pattern visualizer function: {}", name);
(*impl::s_visualizers)[name] = impl::Visualizer { parameterCount, function };
}
void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) {
log::debug("Registered new inline pattern visualizer function: {}", name);
(*impl::s_inlineVisualizers)[name] = impl::Visualizer { parameterCount, function };
}
}
2021-01-12 16:50:15 +01:00
namespace ContentRegistry::Views {
2021-01-12 16:50:15 +01:00
namespace impl {
static AutoReset<std::map<std::string, std::unique_ptr<View>>> s_views;
const std::map<std::string, std::unique_ptr<View>>& getEntries() {
return *s_views;
}
2022-01-13 14:34:27 +01:00
void add(std::unique_ptr<View> &&view) {
log::debug("Registered new view: {}", view->getUnlocalizedName().get());
s_views->insert({ view->getUnlocalizedName(), std::move(view) });
}
}
2021-01-12 16:50:15 +01:00
View* getViewByName(const UnlocalizedString &unlocalizedName) {
auto &views = *impl::s_views;
if (views.contains(unlocalizedName))
return views[unlocalizedName].get();
else
return nullptr;
}
}
namespace ContentRegistry::Tools {
2021-01-12 16:50:15 +01:00
namespace impl {
static AutoReset<std::vector<Entry>> s_tools;
const std::vector<Entry>& getEntries() {
return *s_tools;
}
}
void add(const UnlocalizedString &unlocalizedName, const impl::Callback &function) {
log::debug("Registered new tool: {}", unlocalizedName.get());
2021-01-12 16:50:15 +01:00
impl::s_tools->emplace_back(impl::Entry { unlocalizedName, function });
}
2022-01-13 14:34:27 +01:00
}
namespace ContentRegistry::DataInspector {
namespace impl {
static AutoReset<std::vector<Entry>> s_entries;
const std::vector<Entry>& getEntries() {
return *s_entries;
}
2021-01-12 16:50:15 +01:00
}
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());
impl::s_entries->push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
}
void add(const UnlocalizedString &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
log::debug("Registered new data inspector format: {}", unlocalizedName.get());
impl::s_entries->push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
}
2022-01-13 14:34:27 +01:00
}
namespace ContentRegistry::DataProcessorNode {
namespace impl {
static AutoReset<std::vector<Entry>> s_nodes;
const std::vector<Entry>& getEntries() {
return *s_nodes;
}
void add(const Entry &entry) {
log::debug("Registered new data processor node type: [{}]: {}", entry.unlocalizedCategory.get(), entry.unlocalizedName.get());
s_nodes->push_back(entry);
}
2022-01-13 14:34:27 +01:00
}
void addSeparator() {
impl::s_nodes->push_back({ "", "", [] { return nullptr; } });
}
}
namespace ContentRegistry::Language {
namespace impl {
static AutoReset<std::map<std::string, std::string>> s_languages;
const std::map<std::string, std::string>& getLanguages() {
return *s_languages;
}
static AutoReset<std::map<std::string, std::vector<LocalizationManager::LanguageDefinition>>> s_definitions;
const std::map<std::string, std::vector<LocalizationManager::LanguageDefinition>>& getLanguageDefinitions() {
return *s_definitions;
}
}
void addLocalization(const nlohmann::json &data) {
2023-02-02 10:08:47 +01:00
if (!data.is_object())
return;
if (!data.contains("code") || !data.contains("country") || !data.contains("language") || !data.contains("translations")) {
log::error("Localization data is missing required fields!");
return;
}
2022-01-13 14:34:27 +01:00
const auto &code = data["code"];
const auto &country = data["country"];
const auto &language = data["language"];
const auto &translations = data["translations"];
if (!code.is_string() || !country.is_string() || !language.is_string() || !translations.is_object()) {
log::error("Localization data has invalid fields!");
return;
}
if (data.contains("fallback")) {
const auto &fallback = data["fallback"];
if (fallback.is_boolean() && fallback.get<bool>())
LocalizationManager::impl::setFallbackLanguage(code.get<std::string>());
}
impl::s_languages->insert({ code.get<std::string>(), hex::format("{} ({})", language.get<std::string>(), country.get<std::string>()) });
std::map<std::string, std::string> translationDefinitions;
for (auto &[key, value] : translations.items()) {
if (!value.is_string()) {
log::error("Localization data has invalid fields!");
continue;
}
translationDefinitions[key] = value.get<std::string>();
}
2022-01-13 14:34:27 +01:00
(*impl::s_definitions)[code.get<std::string>()].emplace_back(std::move(translationDefinitions));
}
}
namespace ContentRegistry::Interface {
namespace impl {
static AutoReset<std::multimap<u32, MainMenuItem>> s_mainMenuItems;
const std::multimap<u32, MainMenuItem>& getMainMenuItems() {
return *s_mainMenuItems;
}
static AutoReset<std::multimap<u32, MenuItem>> s_menuItems;
const std::multimap<u32, MenuItem>& getMenuItems() {
return *s_menuItems;
}
static AutoReset<std::vector<MenuItem*>> s_toolbarMenuItems;
const std::vector<MenuItem*>& getToolbarMenuItems() {
return s_toolbarMenuItems;
}
std::multimap<u32, MenuItem>& getMenuItemsMutable() {
return *s_menuItems;
}
static AutoReset<std::vector<DrawCallback>> s_welcomeScreenEntries;
const std::vector<DrawCallback>& getWelcomeScreenEntries() {
return *s_welcomeScreenEntries;
}
static AutoReset<std::vector<DrawCallback>> s_footerItems;
const std::vector<DrawCallback>& getFooterItems() {
return *s_footerItems;
}
static AutoReset<std::vector<DrawCallback>> s_toolbarItems;
const std::vector<DrawCallback>& getToolbarItems() {
return *s_toolbarItems;
}
static AutoReset<std::vector<SidebarItem>> s_sidebarItems;
const std::vector<SidebarItem>& getSidebarItems() {
return *s_sidebarItems;
}
static AutoReset<std::vector<TitleBarButton>> s_titlebarButtons;
const std::vector<TitleBarButton>& getTitlebarButtons() {
return *s_titlebarButtons;
}
}
void registerMainMenuItem(const UnlocalizedString &unlocalizedName, u32 priority) {
log::debug("Registered new main menu item: {}", unlocalizedName.get());
2022-01-13 14:34:27 +01:00
impl::s_mainMenuItems->insert({ priority, { unlocalizedName } });
}
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, const impl::SelectedCallback &selectedCallback, View *view) {
addMenuItem(unlocalizedMainMenuNames, "", priority, shortcut, function, enabledCallback, selectedCallback, view);
2024-01-08 21:51:48 +01:00
}
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, const Icon &icon, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
addMenuItem(unlocalizedMainMenuNames, icon, priority, shortcut, function, enabledCallback, []{ return false; }, view);
}
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
addMenuItem(unlocalizedMainMenuNames, "", priority, shortcut, function, enabledCallback, []{ return false; }, view);
}
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, const Icon &icon, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, const impl::SelectedCallback &selectedCallback, View *view) {
log::debug("Added new menu item to menu {} with priority {}", unlocalizedMainMenuNames[0].get(), priority);
Icon coloredIcon = icon;
if (coloredIcon.color == 0x00)
coloredIcon.color = ImGuiCustomCol_ToolbarGray;
impl::s_menuItems->insert({
priority, impl::MenuItem { unlocalizedMainMenuNames, coloredIcon, std::make_unique<Shortcut>(shortcut), view, function, enabledCallback, selectedCallback, -1 }
});
2023-11-17 14:46:21 +01:00
if (shortcut != Shortcut::None) {
if (shortcut.isLocal() && view != nullptr)
ShortcutManager::addShortcut(view, shortcut, unlocalizedMainMenuNames.back(), function);
else
ShortcutManager::addGlobalShortcut(shortcut, unlocalizedMainMenuNames.back(), function);
}
}
void addMenuItemSubMenu(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
addMenuItemSubMenu(std::move(unlocalizedMainMenuNames), "", priority, function, enabledCallback);
2024-01-08 21:51:48 +01:00
}
void addMenuItemSubMenu(std::vector<UnlocalizedString> unlocalizedMainMenuNames, const char *icon, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
log::debug("Added new menu item sub menu to menu {} with priority {}", unlocalizedMainMenuNames[0].get(), priority);
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
impl::s_menuItems->insert({
priority, impl::MenuItem { unlocalizedMainMenuNames, icon, std::make_unique<Shortcut>(), nullptr, function, enabledCallback, []{ return false; }, -1 }
});
}
void addMenuItemSeparator(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority) {
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
impl::s_menuItems->insert({
priority, impl::MenuItem { unlocalizedMainMenuNames, "", std::make_unique<Shortcut>(), nullptr, []{}, []{ return true; }, []{ return false; }, -1 }
});
}
void addWelcomeScreenEntry(const impl::DrawCallback &function) {
impl::s_welcomeScreenEntries->push_back(function);
}
void addFooterItem(const impl::DrawCallback &function) {
impl::s_footerItems->push_back(function);
}
void addToolbarItem(const impl::DrawCallback &function) {
impl::s_toolbarItems->push_back(function);
}
void addMenuItemToToolbar(const UnlocalizedString& unlocalizedName, ImGuiCustomCol color) {
const auto maxIndex = std::ranges::max_element(impl::getMenuItems(), [](const auto &a, const auto &b) {
return a.second.toolbarIndex < b.second.toolbarIndex;
})->second.toolbarIndex;
for (auto &[priority, menuItem] : *impl::s_menuItems) {
if (menuItem.unlocalizedNames.back() == unlocalizedName) {
menuItem.toolbarIndex = maxIndex + 1;
menuItem.icon.color = color;
updateToolbarItems();
break;
}
}
}
struct MenuItemSorter {
bool operator()(const auto *a, const auto *b) const {
return a->toolbarIndex < b->toolbarIndex;
}
};
void updateToolbarItems() {
std::set<ContentRegistry::Interface::impl::MenuItem*, MenuItemSorter> menuItems;
for (auto &[priority, menuItem] : impl::getMenuItemsMutable()) {
if (menuItem.toolbarIndex != -1) {
menuItems.insert(&menuItem);
}
}
impl::s_toolbarMenuItems->clear();
for (auto menuItem : menuItems) {
impl::s_toolbarMenuItems->push_back(menuItem);
}
}
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function, const impl::EnabledCallback &enabledCallback) {
impl::s_sidebarItems->push_back({ icon, function, enabledCallback });
}
2021-08-21 00:52:11 +02:00
void addTitleBarButton(const std::string &icon, const UnlocalizedString &unlocalizedTooltip, const impl::ClickCallback &function) {
impl::s_titlebarButtons->push_back({ icon, unlocalizedTooltip, function });
}
}
namespace ContentRegistry::Provider {
2021-12-07 22:47:41 +01:00
namespace impl {
2021-12-07 22:47:41 +01:00
void add(const std::string &typeName, ProviderCreationFunction creationFunction) {
(void)RequestCreateProvider::subscribe([expectedName = typeName, creationFunction](const std::string &name, bool skipLoadInterface, bool selectProvider, prv::Provider **provider) {
if (name != expectedName) return;
2022-01-13 14:34:27 +01:00
auto newProvider = creationFunction();
if (provider != nullptr) {
*provider = newProvider.get();
ImHexApi::Provider::add(std::move(newProvider), skipLoadInterface, selectProvider);
}
});
}
static AutoReset<std::vector<std::string>> s_providerNames;
const std::vector<std::string>& getEntries() {
return *s_providerNames;
}
void addProviderName(const UnlocalizedString &unlocalizedName) {
log::debug("Registered new provider: {}", unlocalizedName.get());
s_providerNames->push_back(unlocalizedName);
}
}
2021-12-07 22:47:41 +01:00
}
namespace ContentRegistry::DataFormatter {
namespace impl {
static AutoReset<std::vector<ExportMenuEntry>> s_exportMenuEntries;
const std::vector<ExportMenuEntry>& getExportMenuEntries() {
return *s_exportMenuEntries;
}
static AutoReset<std::vector<FindExporterEntry>> s_findExportEntries;
const std::vector<FindExporterEntry>& getFindExporterEntries() {
return *s_findExportEntries;
}
}
void addExportMenuEntry(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) {
log::debug("Registered new data formatter: {}", unlocalizedName.get());
impl::s_exportMenuEntries->push_back({ unlocalizedName, callback });
}
void addFindExportFormatter(const UnlocalizedString &unlocalizedName, const std::string fileExtension, const impl::FindExporterCallback &callback) {
log::debug("Registered new export formatter: {}", unlocalizedName.get());
impl::s_findExportEntries->push_back({ unlocalizedName, fileExtension, callback });
}
}
namespace ContentRegistry::FileHandler {
namespace impl {
static AutoReset<std::vector<Entry>> s_entries;
const std::vector<Entry>& getEntries() {
return *s_entries;
}
}
void add(const std::vector<std::string> &extensions, const impl::Callback &callback) {
for (const auto &extension : extensions)
log::debug("Registered new data handler for extensions: {}", extension);
impl::s_entries->push_back({ extensions, callback });
}
}
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
namespace ContentRegistry::HexEditor {
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll | ImGuiInputTextFlags_AlwaysOverwrite;
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
bool DataVisualizer::drawDefaultScalarEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
struct UserData {
u8 *data;
i32 maxChars;
bool editingDone;
};
UserData userData = {
.data = data,
.maxChars = this->getMaxCharsPerCell(),
.editingDone = false
};
ImGui::PushID(reinterpret_cast<void*>(address));
ImGuiExt::InputScalarCallback("##editing_input", dataType, data, format, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
2023-11-10 14:48:26 +01:00
auto &userData = *static_cast<UserData*>(data->UserData);
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
if (data->CursorPos >= userData.maxChars)
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
userData.editingDone = true;
data->Buf[userData.maxChars] = 0x00;
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
return 0;
}, &userData);
ImGui::PopID();
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
}
bool DataVisualizer::drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const {
struct UserData {
std::string *data;
i32 maxChars;
bool editingDone;
};
UserData userData = {
.data = &data,
.maxChars = this->getMaxCharsPerCell(),
.editingDone = false
};
ImGui::PushID(reinterpret_cast<void*>(address));
ImGui::InputText("##editing_input", data.data(), data.size() + 1, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
2023-11-10 14:48:26 +01:00
auto &userData = *static_cast<UserData*>(data->UserData);
userData.data->resize(data->BufSize);
if (data->BufTextLen >= userData.maxChars)
userData.editingDone = true;
return 0;
}, &userData);
ImGui::PopID();
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
}
namespace impl {
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
static AutoReset<std::vector<std::shared_ptr<DataVisualizer>>> s_visualizers;
const std::vector<std::shared_ptr<DataVisualizer>>& getVisualizers() {
return *s_visualizers;
}
static AutoReset<std::vector<std::shared_ptr<MiniMapVisualizer>>> s_miniMapVisualizers;
const std::vector<std::shared_ptr<MiniMapVisualizer>>& getMiniMapVisualizers() {
return *s_miniMapVisualizers;
}
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
void addDataVisualizer(std::shared_ptr<DataVisualizer> &&visualizer) {
s_visualizers->emplace_back(std::move(visualizer));
2024-01-28 15:28:55 +01:00
}
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
}
std::shared_ptr<DataVisualizer> getVisualizerByName(const UnlocalizedString &unlocalizedName) {
for (const auto &visualizer : impl::getVisualizers()) {
if (visualizer->getUnlocalizedName() == unlocalizedName)
return visualizer;
}
return nullptr;
}
2024-01-28 15:28:55 +01:00
void addMiniMapVisualizer(UnlocalizedString unlocalizedName, MiniMapVisualizer::Callback callback) {
impl::s_miniMapVisualizers->emplace_back(std::make_shared<MiniMapVisualizer>(std::move(unlocalizedName), std::move(callback)));
2024-01-28 15:28:55 +01:00
}
}
namespace ContentRegistry::Diffing {
namespace impl {
static AutoReset<std::vector<std::unique_ptr<Algorithm>>> s_algorithms;
const std::vector<std::unique_ptr<Algorithm>>& getAlgorithms() {
return *s_algorithms;
}
void addAlgorithm(std::unique_ptr<Algorithm> &&hash) {
s_algorithms->emplace_back(std::move(hash));
}
}
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
}
namespace ContentRegistry::Hashes {
namespace impl {
static AutoReset<std::vector<std::unique_ptr<Hash>>> s_hashes;
const std::vector<std::unique_ptr<Hash>>& getHashes() {
return *s_hashes;
}
2023-06-11 10:47:17 +02:00
void add(std::unique_ptr<Hash> &&hash) {
s_hashes->emplace_back(std::move(hash));
}
}
}
namespace ContentRegistry::BackgroundServices {
namespace impl {
class Service {
public:
Service(std::string name, std::jthread thread) : m_name(std::move(name)), m_thread(std::move(thread)) { }
Service(const Service&) = delete;
Service(Service &&) = default;
~Service() {
m_thread.request_stop();
if (m_thread.joinable())
m_thread.join();
}
Service& operator=(const Service&) = delete;
Service& operator=(Service &&) = default;
[[nodiscard]] const std::string& getName() const {
return m_name;
}
[[nodiscard]] const std::jthread& getThread() const {
return m_thread;
}
private:
std::string m_name;
std::jthread m_thread;
};
static AutoReset<std::vector<Service>> s_services;
const std::vector<Service>& getServices() {
return *s_services;
}
void stopServices() {
s_services->clear();
}
}
void registerService(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) {
log::debug("Registered new background service: {}", unlocalizedName.get());
impl::s_services->emplace_back(
unlocalizedName,
std::jthread([=](const std::stop_token &stopToken){
TaskManager::setCurrentThreadName(Lang(unlocalizedName));
while (!stopToken.stop_requested()) {
callback();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
})
);
}
}
namespace ContentRegistry::CommunicationInterface {
namespace impl {
static AutoReset<std::map<std::string, NetworkCallback>> s_endpoints;
const std::map<std::string, NetworkCallback>& getNetworkEndpoints() {
return *s_endpoints;
}
}
void registerNetworkEndpoint(const std::string &endpoint, const impl::NetworkCallback &callback) {
log::debug("Registered new network endpoint: {}", endpoint);
impl::s_endpoints->insert({ endpoint, callback });
}
}
2023-11-10 14:48:26 +01:00
namespace ContentRegistry::Experiments {
namespace impl {
static AutoReset<std::map<std::string, Experiment>> s_experiments;
const std::map<std::string, Experiment>& getExperiments() {
return *s_experiments;
2023-11-10 14:48:26 +01:00
}
}
void addExperiment(const std::string &experimentName, const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) {
auto &experiments = *impl::s_experiments;
2023-11-10 14:48:26 +01:00
if (experiments.contains(experimentName)) {
log::error("Experiment with name '{}' already exists!", experimentName);
return;
}
experiments[experimentName] = impl::Experiment {
.unlocalizedName = unlocalizedName,
.unlocalizedDescription = unlocalizedDescription,
.enabled = false
};
}
void enableExperiement(const std::string &experimentName, bool enabled) {
auto &experiments = *impl::s_experiments;
2023-11-10 14:48:26 +01:00
if (!experiments.contains(experimentName)) {
log::error("Experiment with name '{}' does not exist!", experimentName);
return;
}
experiments[experimentName].enabled = enabled;
}
[[nodiscard]] bool isExperimentEnabled(const std::string &experimentName) {
auto &experiments = *impl::s_experiments;
2023-11-10 14:48:26 +01:00
if (!experiments.contains(experimentName)) {
log::error("Experiment with name '{}' does not exist!", experimentName);
return false;
}
return experiments[experimentName].enabled;
}
}
namespace ContentRegistry::Reports {
namespace impl {
static AutoReset<std::vector<ReportGenerator>> s_generators;
const std::vector<ReportGenerator>& getGenerators() {
return *s_generators;
}
}
void addReportProvider(impl::Callback callback) {
impl::s_generators->push_back(impl::ReportGenerator { std::move(callback ) });
}
}
namespace ContentRegistry::DataInformation {
namespace impl {
static AutoReset<std::vector<CreateCallback>> s_informationSectionConstructors;
const std::vector<CreateCallback>& getInformationSectionConstructors() {
return *s_informationSectionConstructors;
}
void addInformationSectionCreator(const CreateCallback &callback) {
s_informationSectionConstructors->emplace_back(callback);
}
}
}
}