impr: Rewrote entire settings API and UI (#1378)
This commit is contained in:
parent
f114239f51
commit
7fe9a768d4
@ -14,16 +14,18 @@
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if defined(OS_WEB)
|
||||
#include <jthread.hpp>
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using ImGuiDataType = int;
|
||||
using ImGuiInputTextFlags = int;
|
||||
struct ImColor;
|
||||
|
||||
namespace hex {
|
||||
|
||||
@ -47,127 +49,237 @@ namespace hex {
|
||||
/* Settings Registry. Allows adding of new entries into the ImHex preferences window. */
|
||||
namespace Settings {
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
class Widget {
|
||||
public:
|
||||
virtual ~Widget() = default;
|
||||
|
||||
virtual bool draw(const std::string &name) = 0;
|
||||
|
||||
virtual void load(const nlohmann::json &data) = 0;
|
||||
virtual nlohmann::json store() = 0;
|
||||
|
||||
class Interface {
|
||||
public:
|
||||
friend class Widget;
|
||||
|
||||
Interface& requiresRestart() {
|
||||
this->m_requiresRestart = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Interface& setEnabledCallback(std::function<bool()> callback) {
|
||||
this->m_enabledCallback = std::move(callback);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Interface& setChangedCallback(std::function<void(Widget&)> callback) {
|
||||
this->m_changedCallback = std::move(callback);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Interface& setTooltip(const std::string &tooltip) {
|
||||
this->m_tooltip = tooltip;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
Widget& getWidget() const {
|
||||
return *this->m_widget;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit Interface(Widget *widget) : m_widget(widget) {}
|
||||
Widget *m_widget;
|
||||
|
||||
bool m_requiresRestart = false;
|
||||
std::function<bool()> m_enabledCallback;
|
||||
std::function<void(Widget&)> m_changedCallback;
|
||||
std::optional<std::string> m_tooltip;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
bool doesRequireRestart() const {
|
||||
return this->m_interface.m_requiresRestart;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool isEnabled() const {
|
||||
return !this->m_interface.m_enabledCallback || this->m_interface.m_enabledCallback();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::optional<std::string>& getTooltip() const {
|
||||
return this->m_interface.m_tooltip;
|
||||
}
|
||||
|
||||
void onChanged() {
|
||||
if (this->m_interface.m_changedCallback)
|
||||
this->m_interface.m_changedCallback(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
Interface& getInterface() {
|
||||
return this->m_interface;
|
||||
}
|
||||
|
||||
private:
|
||||
Interface m_interface = Interface(this);
|
||||
};
|
||||
|
||||
class Checkbox : public Widget {
|
||||
public:
|
||||
explicit Checkbox(bool defaultValue) : m_value(defaultValue) { }
|
||||
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]] bool isChecked() const { return this->m_value; }
|
||||
|
||||
private:
|
||||
bool m_value;
|
||||
};
|
||||
class SliderInteger : public Widget {
|
||||
public:
|
||||
SliderInteger(i32 defaultValue, i32 min, i32 max) : m_value(defaultValue), m_min(min), m_max(max) { }
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]] i32 getValue() const { return this->m_value; }
|
||||
|
||||
private:
|
||||
int m_value;
|
||||
i32 m_min, m_max;
|
||||
};
|
||||
class SliderFloat : public Widget {
|
||||
public:
|
||||
SliderFloat(float defaultValue, float min, float max) : m_value(defaultValue), m_min(min), m_max(max) { }
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]] float getValue() const { return this->m_value; }
|
||||
|
||||
private:
|
||||
float m_value;
|
||||
float m_min, m_max;
|
||||
};
|
||||
class ColorPicker : public Widget {
|
||||
public:
|
||||
explicit ColorPicker(ImColor defaultColor);
|
||||
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]] ImColor getColor() const;
|
||||
|
||||
private:
|
||||
std::array<float, 4> m_value;
|
||||
};
|
||||
class DropDown : public Widget {
|
||||
public:
|
||||
explicit DropDown(const std::vector<std::string> &items, const std::vector<nlohmann::json> &settingsValues) : m_items(items), m_settingsValues(settingsValues) { }
|
||||
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]]
|
||||
const nlohmann::json& getValue() const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_items;
|
||||
std::vector<nlohmann::json> m_settingsValues;
|
||||
int m_value = 0;
|
||||
};
|
||||
class TextBox : public Widget {
|
||||
public:
|
||||
explicit TextBox(std::string defaultValue) : m_value(std::move(defaultValue)) { }
|
||||
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& getValue() const { return this->m_value; }
|
||||
|
||||
private:
|
||||
std::string m_value;
|
||||
};
|
||||
class FilePicker : public Widget {
|
||||
public:
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]]
|
||||
std::fs::path getPath() const { return this->m_value; }
|
||||
|
||||
private:
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
using Callback = std::function<bool(const std::string &, nlohmann::json &)>;
|
||||
|
||||
struct Entry {
|
||||
std::string name;
|
||||
bool requiresRestart;
|
||||
Callback callback;
|
||||
std::string unlocalizedName;
|
||||
std::unique_ptr<Widgets::Widget> widget;
|
||||
};
|
||||
|
||||
struct SubCategory {
|
||||
std::string unlocalizedName;
|
||||
std::vector<Entry> entries;
|
||||
};
|
||||
|
||||
struct Category {
|
||||
std::string name;
|
||||
size_t slot = 0;
|
||||
|
||||
bool operator<(const Category &other) const {
|
||||
return name < other.name;
|
||||
}
|
||||
|
||||
explicit operator const std::string &() const {
|
||||
return name;
|
||||
}
|
||||
std::string unlocalizedName;
|
||||
std::string unlocalizedDescription;
|
||||
std::vector<SubCategory> subCategories;
|
||||
};
|
||||
|
||||
void load();
|
||||
void store();
|
||||
void clear();
|
||||
|
||||
std::map<Category, std::vector<Entry>> &getEntries();
|
||||
std::map<std::string, std::string> &getCategoryDescriptions();
|
||||
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
|
||||
std::vector<Category> &getSettings();
|
||||
nlohmann::json& getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue);
|
||||
nlohmann::json &getSettingsData();
|
||||
|
||||
Widgets::Widget* add(const std::string &unlocalizedCategory, const std::string &unlocalizedSubCategory, const std::string &unlocalizedName, std::unique_ptr<Widgets::Widget> &&widget);
|
||||
}
|
||||
|
||||
template<std::derived_from<Widgets::Widget> T>
|
||||
Widgets::Widget::Interface& add(const std::string &unlocalizedCategory, const std::string &unlocalizedSubCategory, const std::string &unlocalizedName, auto && ... args) {
|
||||
return impl::add(
|
||||
unlocalizedCategory,
|
||||
unlocalizedSubCategory,
|
||||
unlocalizedName,
|
||||
std::make_unique<T>(std::forward<decltype(args)>(args)...)
|
||||
)->getInterface();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a new integer setting entry
|
||||
* @param unlocalizedCategory The category of the setting
|
||||
* @param unlocalizedName The name of the setting
|
||||
* @param defaultValue The default value of the setting
|
||||
* @param callback The callback that will be called when the settings item in the preferences window is rendered
|
||||
* @param requiresRestart Whether the setting requires a restart to take effect
|
||||
*/
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const impl::Callback &callback, bool requiresRestart = false);
|
||||
|
||||
/**
|
||||
* @brief Adds a new string setting entry
|
||||
* @param unlocalizedCategory The category of the setting
|
||||
* @param unlocalizedName The name of the setting
|
||||
* @param defaultValue The default value of the setting
|
||||
* @param callback The callback that will be called when the settings item in the preferences window is rendered
|
||||
* @param requiresRestart Whether the setting requires a restart to take effect
|
||||
*/
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const impl::Callback &callback, bool requiresRestart = false);
|
||||
|
||||
/**
|
||||
* @brief Adds a new string list setting entry
|
||||
* @param unlocalizedCategory The category of the setting
|
||||
* @param unlocalizedName The name of the setting
|
||||
* @param defaultValue The default value of the setting
|
||||
* @param callback The callback that will be called when the settings item in the preferences window is rendered
|
||||
* @param requiresRestart Whether the setting requires a restart to take effect
|
||||
*/
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const impl::Callback &callback, bool requiresRestart = false);
|
||||
|
||||
/**
|
||||
* @brief Adds a description to a given category
|
||||
* @param unlocalizedCategory The name of the category
|
||||
* @param unlocalizedCategoryDescription The description of the category
|
||||
*/
|
||||
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription);
|
||||
|
||||
/**
|
||||
* @brief Writes a integer value to the settings file
|
||||
* @param unlocalizedCategory The category of the setting
|
||||
* @param unlocalizedName The name of the setting
|
||||
* @param value The value to write
|
||||
*/
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value);
|
||||
|
||||
/**
|
||||
* @brief Writes a string value to the settings file
|
||||
* @param unlocalizedCategory The category of the setting
|
||||
* @param unlocalizedName The name of the setting
|
||||
* @param value The value to write
|
||||
*/
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value);
|
||||
|
||||
/**
|
||||
* @brief Writes a string list value to the settings file
|
||||
* @param unlocalizedCategory The category of the setting
|
||||
* @param unlocalizedName The name of the setting
|
||||
* @param value The value to write
|
||||
*/
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value);
|
||||
|
||||
/**
|
||||
* @brief Reads an integer value from the settings file
|
||||
* @param unlocalizedCategory The category of the setting
|
||||
* @param unlocalizedName The name of the setting
|
||||
* @param defaultValue The default value of the setting
|
||||
* @return The value of the setting
|
||||
*/
|
||||
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue);
|
||||
|
||||
/**
|
||||
* @brief Reads a string value from the settings file
|
||||
* @param unlocalizedCategory The category of the setting
|
||||
* @param unlocalizedName The name of the setting
|
||||
* @param defaultValue The default value of the setting
|
||||
* @return The value of the setting
|
||||
*/
|
||||
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue);
|
||||
|
||||
/**
|
||||
* @brief Reads a string list value from the settings file
|
||||
* @param unlocalizedCategory The category of the setting
|
||||
* @param unlocalizedName The name of the setting
|
||||
* @param defaultValue The default value of the setting
|
||||
* @return The value of the setting
|
||||
*/
|
||||
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue = {});
|
||||
void setCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedDescription);
|
||||
|
||||
nlohmann::json read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue);
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &value);
|
||||
}
|
||||
|
||||
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
|
||||
#if defined(OS_WEB)
|
||||
#include <jthread.hpp>
|
||||
#include <emscripten.h>
|
||||
@ -26,23 +27,14 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::map<Category, std::vector<Entry>> &getEntries() {
|
||||
static std::map<Category, std::vector<Entry>> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> &getCategoryDescriptions() {
|
||||
static std::map<std::string, std::string> descriptions;
|
||||
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
|
||||
nlohmann::json& getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue) {
|
||||
auto &settings = getSettingsData();
|
||||
|
||||
if (!settings.contains(unlocalizedCategory)) return {};
|
||||
if (!settings[unlocalizedCategory].contains(unlocalizedName)) return {};
|
||||
if (!settings.contains(unlocalizedCategory))
|
||||
settings[unlocalizedCategory] = {};
|
||||
|
||||
if (!settings[unlocalizedCategory].contains(unlocalizedName))
|
||||
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
|
||||
return settings[unlocalizedCategory][unlocalizedName];
|
||||
}
|
||||
@ -119,135 +111,258 @@ namespace hex {
|
||||
}
|
||||
#endif
|
||||
|
||||
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
|
||||
auto &entries = getEntries();
|
||||
const size_t curSlot = entries.size();
|
||||
auto found = entries.find(Category { unlocalizedCategory });
|
||||
|
||||
if (found == entries.end()) {
|
||||
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
|
||||
return iter;
|
||||
template<typename T>
|
||||
static T* insertOrGetEntry(std::vector<T> &vector, const std::string &unlocalizedName) {
|
||||
T *foundEntry = nullptr;
|
||||
for (auto &entry : vector) {
|
||||
if (entry.unlocalizedName == unlocalizedName) {
|
||||
foundEntry = &entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
if (foundEntry == nullptr) {
|
||||
if (unlocalizedName.empty())
|
||||
foundEntry = &*vector.emplace(vector.begin(), unlocalizedName);
|
||||
else
|
||||
foundEntry = &vector.emplace_back(unlocalizedName);
|
||||
}
|
||||
|
||||
return foundEntry;
|
||||
}
|
||||
|
||||
std::vector<Category> &getSettings() {
|
||||
static std::vector<impl::Category> categories;
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
Widgets::Widget* add(const std::string &unlocalizedCategory, const std::string &unlocalizedSubCategory, const std::string &unlocalizedName, std::unique_ptr<Widgets::Widget> &&widget) {
|
||||
auto category = impl::insertOrGetEntry(impl::getSettings(), unlocalizedCategory);
|
||||
auto subCategory = impl::insertOrGetEntry(category->subCategories, unlocalizedSubCategory);
|
||||
auto entry = impl::insertOrGetEntry(subCategory->entries, unlocalizedName);
|
||||
|
||||
entry->widget = std::move(widget);
|
||||
entry->widget->load(getSetting(unlocalizedCategory, unlocalizedName, entry->widget->store()));
|
||||
|
||||
return entry->widget.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const impl::Callback &callback, bool requiresRestart) {
|
||||
log::debug("Registered new integer setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
||||
void setCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedDescription) {
|
||||
auto category = impl::insertOrGetEntry(impl::getSettings(), unlocalizedCategory);
|
||||
|
||||
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
||||
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_number())
|
||||
json[unlocalizedCategory][unlocalizedName] = int(defaultValue);
|
||||
category->unlocalizedDescription = unlocalizedDescription;
|
||||
}
|
||||
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const impl::Callback &callback, bool requiresRestart) {
|
||||
log::debug("Registered new string setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
||||
nlohmann::json read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue) {
|
||||
auto setting = impl::getSetting(unlocalizedCategory, unlocalizedName, defaultValue);
|
||||
|
||||
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
||||
if (setting.is_number() && defaultValue.is_boolean())
|
||||
setting = setting.get<int>() != 0;
|
||||
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_string())
|
||||
json[unlocalizedCategory][unlocalizedName] = std::string(defaultValue);
|
||||
return setting;
|
||||
}
|
||||
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const impl::Callback &callback, bool requiresRestart) {
|
||||
log::debug("Registered new string array setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
||||
|
||||
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
||||
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_array())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &value) {
|
||||
impl::getSetting(unlocalizedCategory, unlocalizedName, value) = value;
|
||||
}
|
||||
|
||||
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription) {
|
||||
impl::getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
|
||||
}
|
||||
namespace Widgets {
|
||||
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value) {
|
||||
auto &json = impl::getSettingsData();
|
||||
bool Checkbox::draw(const std::string &name) {
|
||||
return ImGui::Checkbox(name.c_str(), &this->m_value);
|
||||
}
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
void Checkbox::load(const nlohmann::json &data) {
|
||||
if (data.is_number()) {
|
||||
this->m_value = data.get<int>() != 0;
|
||||
} else if (data.is_boolean()) {
|
||||
this->m_value = data.get<bool>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for checkbox!");
|
||||
}
|
||||
}
|
||||
|
||||
json[unlocalizedCategory][unlocalizedName] = value;
|
||||
}
|
||||
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value) {
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
|
||||
json[unlocalizedCategory][unlocalizedName] = value;
|
||||
}
|
||||
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value) {
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
|
||||
json[unlocalizedCategory][unlocalizedName] = value;
|
||||
}
|
||||
nlohmann::json Checkbox::store() {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
|
||||
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue) {
|
||||
auto &json = impl::getSettingsData();
|
||||
bool SliderInteger::draw(const std::string &name) {
|
||||
return ImGui::SliderInt(name.c_str(), &this->m_value, this->m_min, this->m_max);
|
||||
}
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
return defaultValue;
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName))
|
||||
return defaultValue;
|
||||
void SliderInteger::load(const nlohmann::json &data) {
|
||||
if (data.is_number_integer()) {
|
||||
this->m_value = data.get<int>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for slider!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!json[unlocalizedCategory][unlocalizedName].is_number())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
nlohmann::json SliderInteger::store() {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
return json[unlocalizedCategory][unlocalizedName].get<i64>();
|
||||
}
|
||||
|
||||
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue) {
|
||||
auto &json = impl::getSettingsData();
|
||||
bool SliderFloat::draw(const std::string &name) {
|
||||
return ImGui::SliderFloat(name.c_str(), &this->m_value, this->m_min, this->m_max);
|
||||
}
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
return defaultValue;
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName))
|
||||
return defaultValue;
|
||||
void SliderFloat::load(const nlohmann::json &data) {
|
||||
if (data.is_number()) {
|
||||
this->m_value = data.get<float>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for slider!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!json[unlocalizedCategory][unlocalizedName].is_string())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
nlohmann::json SliderFloat::store() {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
return json[unlocalizedCategory][unlocalizedName].get<std::string>();
|
||||
}
|
||||
|
||||
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue) {
|
||||
auto &json = impl::getSettingsData();
|
||||
ColorPicker::ColorPicker(ImColor defaultColor) {
|
||||
this->m_value = {
|
||||
defaultColor.Value.x,
|
||||
defaultColor.Value.y,
|
||||
defaultColor.Value.z,
|
||||
defaultColor.Value.w
|
||||
};
|
||||
}
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
return defaultValue;
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName))
|
||||
return defaultValue;
|
||||
bool ColorPicker::draw(const std::string &name) {
|
||||
return ImGui::ColorEdit4(name.c_str(), this->m_value.data(), ImGuiColorEditFlags_NoInputs);
|
||||
}
|
||||
|
||||
if (!json[unlocalizedCategory][unlocalizedName].is_array())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
void ColorPicker::load(const nlohmann::json &data) {
|
||||
if (data.is_number()) {
|
||||
ImColor color(data.get<u32>());
|
||||
this->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!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!json[unlocalizedCategory][unlocalizedName].array().empty() && !json[unlocalizedCategory][unlocalizedName][0].is_string())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
nlohmann::json ColorPicker::store() {
|
||||
ImColor color(this->m_value[0], this->m_value[1], this->m_value[2], this->m_value[3]);
|
||||
|
||||
return ImU32(color);
|
||||
}
|
||||
|
||||
ImColor ColorPicker::getColor() const {
|
||||
return { this->m_value[0], this->m_value[1], this->m_value[2], this->m_value[3] };
|
||||
}
|
||||
|
||||
|
||||
bool DropDown::draw(const std::string &name) {
|
||||
const char *preview = "";
|
||||
if (size_t(this->m_value) < this->m_items.size())
|
||||
preview = this->m_items[this->m_value].c_str();
|
||||
|
||||
bool changed = false;
|
||||
if (ImGui::BeginCombo(name.c_str(), LangEntry(preview))) {
|
||||
|
||||
int index = 0;
|
||||
for (const auto &item : this->m_items) {
|
||||
bool selected = (index == this->m_value);
|
||||
|
||||
if (ImGui::Selectable(LangEntry(item), selected)) {
|
||||
this->m_value = index;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
|
||||
index += 1;
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void DropDown::load(const nlohmann::json &data) {
|
||||
this->m_value = 0;
|
||||
|
||||
int index = 0;
|
||||
for (const auto &item : this->m_settingsValues) {
|
||||
if (item == data) {
|
||||
this->m_value = index;
|
||||
break;
|
||||
}
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json DropDown::store() {
|
||||
if (size_t(this->m_value) >= this->m_items.size())
|
||||
return nullptr;
|
||||
|
||||
return this->m_settingsValues[this->m_value];
|
||||
}
|
||||
|
||||
const nlohmann::json& DropDown::getValue() const {
|
||||
return this->m_settingsValues[this->m_value];
|
||||
}
|
||||
|
||||
|
||||
bool TextBox::draw(const std::string &name) {
|
||||
return ImGui::InputText(name.c_str(), this->m_value);
|
||||
}
|
||||
|
||||
void TextBox::load(const nlohmann::json &data) {
|
||||
if (data.is_string()) {
|
||||
this->m_value = data.get<std::string>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for text box!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json TextBox::store() {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
|
||||
bool FilePicker::draw(const std::string &name) {
|
||||
bool changed = false;
|
||||
if (ImGui::InputText("##font_path", this->m_value)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::IconButton(ICON_VS_FOLDER_OPENED, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||
return fs::openFileBrowser(fs::DialogMode::Open, { { "TTF Font", "ttf" }, { "OTF Font", "otf" } },
|
||||
[&](const std::fs::path &path) {
|
||||
this->m_value = wolv::util::toUTF8String(path);
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::TextFormatted("{}", name);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void FilePicker::load(const nlohmann::json &data) {
|
||||
if (data.is_string()) {
|
||||
this->m_value = data.get<std::string>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for file picker!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json FilePicker::store() {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
return json[unlocalizedCategory][unlocalizedName].get<std::vector<std::string>>();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ namespace hex::init {
|
||||
ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data());
|
||||
|
||||
// Check if there is a telemetry uuid
|
||||
std::string uuid = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", "");
|
||||
std::string uuid = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", "").get<std::string>();
|
||||
if(uuid.empty()) {
|
||||
// Generate a new uuid
|
||||
uuid = wolv::hash::generateUUID();
|
||||
@ -182,7 +182,7 @@ namespace hex::init {
|
||||
|
||||
// Load font related settings
|
||||
{
|
||||
std::fs::path fontFile = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_path", "");
|
||||
std::fs::path fontFile = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_path", "").get<std::string>();
|
||||
if (!fontFile.empty()) {
|
||||
if (!wolv::io::fs::exists(fontFile) || !wolv::io::fs::isRegularFile(fontFile)) {
|
||||
log::warn("Custom font file {} not found! Falling back to default font.", wolv::util::toUTF8String(fontFile));
|
||||
@ -210,7 +210,7 @@ namespace hex::init {
|
||||
// If a custom font has been loaded now, also load the font size
|
||||
float fontSize = defaultFontSize;
|
||||
if (!fontFile.empty()) {
|
||||
fontSize = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_size", 13) * ImHexApi::System::getGlobalScale();
|
||||
fontSize = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_size", 13).get<int>() * ImHexApi::System::getGlobalScale();
|
||||
}
|
||||
|
||||
ImHexApi::System::impl::setFontSize(fontSize);
|
||||
@ -310,7 +310,7 @@ namespace hex::init {
|
||||
IM_DELETE(fonts);
|
||||
|
||||
// Disable unicode support in settings
|
||||
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.load_all_unicode_chars", false);
|
||||
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.font.load_all_unicode_chars", false);
|
||||
|
||||
// Try to load the font atlas again
|
||||
return loadFontsImpl(false);
|
||||
@ -331,7 +331,7 @@ namespace hex::init {
|
||||
// Check if unicode support is enabled in the settings and that the user doesn't use the No GPU version on Windows
|
||||
// The Mesa3D software renderer on Windows identifies itself as "VMware, Inc."
|
||||
bool shouldLoadUnicode =
|
||||
ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.load_all_unicode_chars", false) &&
|
||||
ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.font.load_all_unicode_chars", false) &&
|
||||
ImHexApi::System::getGPUVendor() != "VMware, Inc.";
|
||||
|
||||
return loadFontsImpl(shouldLoadUnicode);
|
||||
@ -361,7 +361,7 @@ namespace hex::init {
|
||||
ImHexApi::System::getCustomFontPath().clear();
|
||||
ImHexApi::Messaging::impl::getHandlers().clear();
|
||||
|
||||
ContentRegistry::Settings::impl::getEntries().clear();
|
||||
ContentRegistry::Settings::impl::getSettings().clear();
|
||||
ContentRegistry::Settings::impl::getSettingsData().clear();
|
||||
|
||||
ContentRegistry::CommandPaletteCommands::impl::getEntries().clear();
|
||||
@ -567,33 +567,11 @@ namespace hex::init {
|
||||
}
|
||||
|
||||
bool configureUIScale() {
|
||||
float interfaceScaling;
|
||||
switch (ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling", 0)) {
|
||||
default:
|
||||
case 0:
|
||||
interfaceScaling = ImHexApi::System::getNativeScale();
|
||||
break;
|
||||
case 1:
|
||||
interfaceScaling = 0.5F;
|
||||
break;
|
||||
case 2:
|
||||
interfaceScaling = 1.0F;
|
||||
break;
|
||||
case 3:
|
||||
interfaceScaling = 1.5F;
|
||||
break;
|
||||
case 4:
|
||||
interfaceScaling = 2.0F;
|
||||
break;
|
||||
case 5:
|
||||
interfaceScaling = 3.0F;
|
||||
break;
|
||||
case 6:
|
||||
interfaceScaling = 4.0F;
|
||||
break;
|
||||
}
|
||||
int interfaceScaling = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling", 0).get<float>() * 10;
|
||||
if (interfaceScaling == 0)
|
||||
interfaceScaling = ImHexApi::System::getNativeScale();
|
||||
|
||||
ImHexApi::System::impl::setGlobalScale(interfaceScaling);
|
||||
ImHexApi::System::impl::setGlobalScale(interfaceScaling / 10.0F);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -608,7 +586,7 @@ namespace hex::init {
|
||||
return true;
|
||||
}
|
||||
|
||||
// run all exit taks, and print to console
|
||||
// Run all exit tasks, and print to console
|
||||
void runExitTasks() {
|
||||
for (const auto &[name, task, async] : init::getExitTasks()) {
|
||||
task();
|
||||
|
@ -1037,7 +1037,7 @@ namespace hex {
|
||||
io.FontGlobalScale = 1.0F;
|
||||
|
||||
if (glfwGetPrimaryMonitor() != nullptr) {
|
||||
bool multiWindowEnabled = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", 0) != 0;
|
||||
bool multiWindowEnabled = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", false);
|
||||
|
||||
if (multiWindowEnabled)
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
|
@ -14,7 +14,7 @@ namespace hex::plugin::builtin {
|
||||
PopupTelemetryRequest()
|
||||
: hex::Popup<PopupTelemetryRequest>("hex.builtin.common.question", false) {
|
||||
// Check if there is a telemetry uuid
|
||||
this->m_uuid = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", "");
|
||||
this->m_uuid = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", "").get<std::string>();
|
||||
if(this->m_uuid.empty()) {
|
||||
// Generate a new uuid
|
||||
this->m_uuid = wolv::hash::generateUUID();
|
||||
|
@ -516,7 +516,7 @@
|
||||
"hex.builtin.setting.general": "Allgemein",
|
||||
"hex.builtin.setting.general.auto_load_patterns": "Automatisches Laden unterstützter Pattern",
|
||||
"hex.builtin.setting.general.server_contact": "Update checks und Statistiken zulassen",
|
||||
"hex.builtin.setting.general.load_all_unicode_chars": "Alle Unicode Zeichen laden",
|
||||
"hex.builtin.setting.font.load_all_unicode_chars": "Alle Unicode Zeichen laden",
|
||||
"hex.builtin.setting.general.network_interface": "",
|
||||
"hex.builtin.setting.general.save_recent_providers": "",
|
||||
"hex.builtin.setting.general.show_tips": "Tipps beim Start anzeigen",
|
||||
|
@ -516,13 +516,17 @@
|
||||
"hex.builtin.setting.folders.description": "Specify additional search paths for patterns, scripts, Yara rules and more",
|
||||
"hex.builtin.setting.folders.remove_folder": "Remove currently selected folder from list",
|
||||
"hex.builtin.setting.font": "Font",
|
||||
"hex.builtin.setting.font.glyphs": "Glyphs",
|
||||
"hex.builtin.setting.font.custom_font": "Custom Font",
|
||||
"hex.builtin.setting.font.font_path": "Custom Font Path",
|
||||
"hex.builtin.setting.font.font_size": "Font Size",
|
||||
"hex.builtin.setting.font.font_size.tooltip": "The font size can only be adjusted when a custom font has been selected above.\n\nThis is because ImHex uses a pixel-perfect bitmap font by default. Scaling it by any non-integer factor will only cause it to become blurry.",
|
||||
"hex.builtin.setting.general": "General",
|
||||
"hex.builtin.setting.general.patterns": "Patterns",
|
||||
"hex.builtin.setting.general.network": "Network",
|
||||
"hex.builtin.setting.general.auto_load_patterns": "Auto-load supported pattern",
|
||||
"hex.builtin.setting.general.server_contact": "Enable update checks and usage statistics",
|
||||
"hex.builtin.setting.general.load_all_unicode_chars": "Load all unicode characters",
|
||||
"hex.builtin.setting.font.load_all_unicode_chars": "Load all unicode characters",
|
||||
"hex.builtin.setting.general.network_interface": "Enable network interface",
|
||||
"hex.builtin.setting.general.save_recent_providers": "Save recently used providers",
|
||||
"hex.builtin.setting.general.show_tips": "Show tips on startup",
|
||||
@ -533,7 +537,7 @@
|
||||
"hex.builtin.setting.hex_editor.bytes_per_row": "Bytes per row",
|
||||
"hex.builtin.setting.hex_editor.char_padding": "Extra character cell padding",
|
||||
"hex.builtin.setting.hex_editor.highlight_color": "Selection highlight color",
|
||||
"hex.builtin.setting.hex_editor.sync_scrolling": "Synchronize editor position",
|
||||
"hex.builtin.setting.hex_editor.sync_scrolling": "Synchronize editor scroll position",
|
||||
"hex.builtin.setting.imhex": "ImHex",
|
||||
"hex.builtin.setting.imhex.recent_files": "Recent Files",
|
||||
"hex.builtin.setting.interface": "Interface",
|
||||
|
@ -516,7 +516,7 @@
|
||||
"hex.builtin.setting.general": "General",
|
||||
"hex.builtin.setting.general.auto_load_patterns": "Cargar automáticamente patterns soportados",
|
||||
"hex.builtin.setting.general.server_contact": "",
|
||||
"hex.builtin.setting.general.load_all_unicode_chars": "Cargar todos los caracteres unicode",
|
||||
"hex.builtin.setting.font.load_all_unicode_chars": "Cargar todos los caracteres unicode",
|
||||
"hex.builtin.setting.general.network_interface": "",
|
||||
"hex.builtin.setting.general.save_recent_providers": "Guardar proveedores recientemente utilizados",
|
||||
"hex.builtin.setting.general.show_tips": "Mostrar consejos al inicio",
|
||||
|
@ -516,7 +516,7 @@
|
||||
"hex.builtin.setting.general": "Generali",
|
||||
"hex.builtin.setting.general.auto_load_patterns": "Auto-caricamento del pattern supportato",
|
||||
"hex.builtin.setting.general.server_contact": "",
|
||||
"hex.builtin.setting.general.load_all_unicode_chars": "",
|
||||
"hex.builtin.setting.font.load_all_unicode_chars": "",
|
||||
"hex.builtin.setting.general.network_interface": "",
|
||||
"hex.builtin.setting.general.save_recent_providers": "",
|
||||
"hex.builtin.setting.general.show_tips": "Mostra consigli all'avvio",
|
||||
|
@ -516,7 +516,7 @@
|
||||
"hex.builtin.setting.general": "基本",
|
||||
"hex.builtin.setting.general.auto_load_patterns": "対応するパターンを自動で読み込む",
|
||||
"hex.builtin.setting.general.server_contact": "",
|
||||
"hex.builtin.setting.general.load_all_unicode_chars": "",
|
||||
"hex.builtin.setting.font.load_all_unicode_chars": "",
|
||||
"hex.builtin.setting.general.network_interface": "",
|
||||
"hex.builtin.setting.general.save_recent_providers": "",
|
||||
"hex.builtin.setting.general.show_tips": "起動時に豆知識を表示",
|
||||
|
@ -516,7 +516,7 @@
|
||||
"hex.builtin.setting.general": "일반",
|
||||
"hex.builtin.setting.general.auto_load_patterns": "지원하는 패턴 자동으로 로드",
|
||||
"hex.builtin.setting.general.server_contact": "",
|
||||
"hex.builtin.setting.general.load_all_unicode_chars": "",
|
||||
"hex.builtin.setting.font.load_all_unicode_chars": "",
|
||||
"hex.builtin.setting.general.network_interface": "",
|
||||
"hex.builtin.setting.general.save_recent_providers": "",
|
||||
"hex.builtin.setting.general.show_tips": "시작 시 팁 표시",
|
||||
|
@ -516,7 +516,7 @@
|
||||
"hex.builtin.setting.general": "General",
|
||||
"hex.builtin.setting.general.auto_load_patterns": "Padrão compatível com carregamento automático",
|
||||
"hex.builtin.setting.general.server_contact": "",
|
||||
"hex.builtin.setting.general.load_all_unicode_chars": "",
|
||||
"hex.builtin.setting.font.load_all_unicode_chars": "",
|
||||
"hex.builtin.setting.general.network_interface": "",
|
||||
"hex.builtin.setting.general.save_recent_providers": "",
|
||||
"hex.builtin.setting.general.show_tips": "Mostrar dicas na inicialização",
|
||||
|
@ -516,7 +516,7 @@
|
||||
"hex.builtin.setting.general": "通用",
|
||||
"hex.builtin.setting.general.auto_load_patterns": "自动加载支持的模式",
|
||||
"hex.builtin.setting.general.server_contact": "启用更新检查和使用统计",
|
||||
"hex.builtin.setting.general.load_all_unicode_chars": "加载所有 Unicode 字符",
|
||||
"hex.builtin.setting.font.load_all_unicode_chars": "加载所有 Unicode 字符",
|
||||
"hex.builtin.setting.general.network_interface": "启动网络",
|
||||
"hex.builtin.setting.general.save_recent_providers": "保存最近使用的提供者",
|
||||
"hex.builtin.setting.general.show_tips": "在启动时显示每日提示",
|
||||
|
@ -516,7 +516,7 @@
|
||||
"hex.builtin.setting.general": "一般",
|
||||
"hex.builtin.setting.general.auto_load_patterns": "自動載入支援的模式",
|
||||
"hex.builtin.setting.general.server_contact": "啟用檢查更新和使用統計",
|
||||
"hex.builtin.setting.general.load_all_unicode_chars": "載入所有 unicode 字元",
|
||||
"hex.builtin.setting.font.load_all_unicode_chars": "載入所有 unicode 字元",
|
||||
"hex.builtin.setting.general.network_interface": "啟用網路介面",
|
||||
"hex.builtin.setting.general.save_recent_providers": "儲存近期使用過的提供者",
|
||||
"hex.builtin.setting.general.show_tips": "啟動時顯示提示",
|
||||
|
@ -54,7 +54,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
void registerBackgroundServices() {
|
||||
EventManager::subscribe<EventSettingsChanged>([]{
|
||||
networkInterfaceServiceEnabled = bool(ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.network_interface", 0));
|
||||
networkInterfaceServiceEnabled = bool(ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.network_interface", false));
|
||||
});
|
||||
|
||||
ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.network_interface"_lang, handleNetworkInterfaceService);
|
||||
|
@ -27,7 +27,7 @@ namespace hex::plugin::builtin::recent {
|
||||
void registerEventHandlers() {
|
||||
// Save every opened provider as a "recent" shortcut
|
||||
(void)EventManager::subscribe<EventProviderOpened>([](prv::Provider *provider) {
|
||||
if (ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.save_recent_providers", 1) == 1) {
|
||||
if (ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.save_recent_providers", true)) {
|
||||
auto fileName = hex::format("{:%y%m%d_%H%M%S}.json", fmt::gmtime(std::chrono::system_clock::now()));
|
||||
|
||||
// Do not save to recents if the provider is part of a project
|
||||
@ -59,7 +59,7 @@ namespace hex::plugin::builtin::recent {
|
||||
|
||||
// Save opened projects as a "recent" shortcut
|
||||
(void)EventManager::subscribe<EventProjectOpened>([] {
|
||||
if (ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.save_recent_providers", 1) == 1) {
|
||||
if (ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.save_recent_providers", true)) {
|
||||
auto fileName = hex::format("{:%y%m%d_%H%M%S}.json", fmt::gmtime(std::chrono::system_clock::now()));
|
||||
|
||||
auto projectFileName = ProjectFile::getPath().filename();
|
||||
|
@ -1,12 +1,10 @@
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/api/theme_manager.hpp>
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/http_requests.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
@ -14,230 +12,234 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <ui/pattern_drawer.hpp>
|
||||
|
||||
#include <wolv/utils/guards.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<std::fs::path> userFolders;
|
||||
|
||||
void loadUserFoldersFromSetting(const std::vector<std::string> &paths) {
|
||||
userFolders.clear();
|
||||
for (const auto &path : paths) {
|
||||
userFolders.emplace_back(
|
||||
reinterpret_cast<const char8_t*>(path.data()),
|
||||
reinterpret_cast<const char8_t*>(path.data() + path.size())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
Values of this setting:
|
||||
0 - do not check for updates on startup
|
||||
1 - check for updates on startup
|
||||
2 - default value - ask the user if he wants to check for updates. This value should only be encountered on the first startup.
|
||||
*/
|
||||
class ServerContactWidget : public ContentRegistry::Settings::Widgets::Widget {
|
||||
public:
|
||||
bool draw(const std::string &name) override {
|
||||
bool enabled = this->m_value == 1;
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
this->m_value = enabled ? 1 : 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void load(const nlohmann::json &data) override {
|
||||
if (data.is_number())
|
||||
this->m_value = data.get<int>();
|
||||
}
|
||||
|
||||
nlohmann::json store() override {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_value = 2;
|
||||
};
|
||||
|
||||
class FPSWidget : public ContentRegistry::Settings::Widgets::Widget {
|
||||
public:
|
||||
bool draw(const std::string &name) override {
|
||||
auto format = [this] -> std::string {
|
||||
if (this->m_value > 200)
|
||||
return "hex.builtin.setting.interface.fps.unlocked"_lang;
|
||||
else if (this->m_value < 15)
|
||||
return "hex.builtin.setting.interface.fps.native"_lang;
|
||||
else
|
||||
return "%d FPS";
|
||||
}();
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &this->m_value, 14, 201, format.c_str(), ImGuiSliderFlags_AlwaysClamp)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void load(const nlohmann::json &data) override {
|
||||
if (data.is_number())
|
||||
this->m_value = data.get<int>();
|
||||
}
|
||||
|
||||
nlohmann::json store() override {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_value = 60;
|
||||
};
|
||||
|
||||
class UserFolderWidget : public ContentRegistry::Settings::Widgets::Widget {
|
||||
public:
|
||||
bool draw(const std::string &) override {
|
||||
bool result = false;
|
||||
|
||||
if (!ImGui::BeginListBox("", ImVec2(-38, -10))) {
|
||||
return false;
|
||||
} else {
|
||||
for (size_t n = 0; n < this->m_paths.size(); n++) {
|
||||
const bool isSelected = (this->m_itemIndex == n);
|
||||
if (ImGui::Selectable(wolv::util::toUTF8String(this->m_paths[n]).c_str(), isSelected)) {
|
||||
this->m_itemIndex = n;
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginGroup();
|
||||
|
||||
if (ImGui::IconButton(ICON_VS_NEW_FOLDER, ImGui::GetStyleColorVec4(ImGuiCol_Text), ImVec2(30, 30))) {
|
||||
fs::openFileBrowser(fs::DialogMode::Folder, {}, [&](const std::fs::path &path) {
|
||||
if (std::find(this->m_paths.begin(), this->m_paths.end(), path) == this->m_paths.end()) {
|
||||
this->m_paths.emplace_back(path);
|
||||
ImHexApi::System::setAdditionalFolderPaths(this->m_paths);
|
||||
|
||||
result = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
ImGui::InfoTooltip("hex.builtin.setting.folders.add_folder"_lang);
|
||||
|
||||
if (ImGui::IconButton(ICON_VS_REMOVE_CLOSE, ImGui::GetStyleColorVec4(ImGuiCol_Text), ImVec2(30, 30))) {
|
||||
if (!this->m_paths.empty()) {
|
||||
this->m_paths.erase(std::next(this->m_paths.begin(), this->m_itemIndex));
|
||||
ImHexApi::System::setAdditionalFolderPaths(this->m_paths);
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
ImGui::InfoTooltip("hex.builtin.setting.folders.remove_folder"_lang);
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void load(const nlohmann::json &data) override {
|
||||
if (data.is_array()) {
|
||||
std::vector<std::string> pathStrings = data;
|
||||
|
||||
for (const auto &pathString : pathStrings) {
|
||||
this->m_paths.emplace_back(pathString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json store() override {
|
||||
std::vector<std::string> pathStrings;
|
||||
|
||||
for (const auto &path : this->m_paths) {
|
||||
pathStrings.push_back(wolv::util::toUTF8String(path));
|
||||
}
|
||||
|
||||
return pathStrings;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_itemIndex = 0;
|
||||
std::vector<std::fs::path> m_paths;
|
||||
};
|
||||
|
||||
class ScalingWidget : public ContentRegistry::Settings::Widgets::Widget {
|
||||
public:
|
||||
bool draw(const std::string &name) override {
|
||||
auto format = [this] -> std::string {
|
||||
if (this->m_value == 0)
|
||||
return "hex.builtin.setting.interface.scaling.native"_lang;
|
||||
else
|
||||
return "x%.1f";
|
||||
}();
|
||||
|
||||
if (ImGui::SliderFloat(name.data(), &this->m_value, 0, 10, format.c_str(), ImGuiSliderFlags_AlwaysClamp)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void load(const nlohmann::json &data) override {
|
||||
if (data.is_number())
|
||||
this->m_value = data.get<float>();
|
||||
}
|
||||
|
||||
nlohmann::json store() override {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
float m_value = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void registerSettings() {
|
||||
|
||||
/* General */
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.show_tips", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
namespace Widgets = ContentRegistry::Settings::Widgets;
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.sync_pattern_source", 0, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.load_all_unicode_chars", 0, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.save_recent_providers", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.network_interface", 0, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
/*
|
||||
Values of this setting :
|
||||
0 - do not check for updates on startup
|
||||
1 - check for updates on startup
|
||||
2 - default value - ask the user if he wants to check for updates. This value should only be encountered on the first startup.
|
||||
*/
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 2, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting) == 1;
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting) == 1;
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.general", "", "hex.builtin.setting.general.show_tips", true);
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.general", "", "hex.builtin.setting.general.save_recent_providers", true);
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.general", "hex.builtin.setting.general.patterns", "hex.builtin.setting.general.auto_load_patterns", true);
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.general", "hex.builtin.setting.general.patterns", "hex.builtin.setting.general.sync_pattern_source", false);
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.network_interface", false);
|
||||
ContentRegistry::Settings::add<ServerContactWidget>("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.server_contact");
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.upload_crash_logs", true);
|
||||
|
||||
/* Interface */
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", "Dark", [](auto name, nlohmann::json &setting) {
|
||||
static auto selection = static_cast<std::string>(setting);
|
||||
auto themeNames = ThemeManager::getThemeNames();
|
||||
std::vector<nlohmann::json> themeJsons = { };
|
||||
for (const auto &themeName : themeNames)
|
||||
themeJsons.emplace_back(themeName);
|
||||
|
||||
const auto themeNames = ThemeManager::getThemeNames();
|
||||
bool changed = false;
|
||||
themeNames.emplace(themeNames.begin(), ThemeManager::NativeTheme);
|
||||
themeJsons.emplace(themeJsons.begin(), ThemeManager::NativeTheme);
|
||||
|
||||
if (ImGui::BeginCombo(name.data(), selection.c_str())) {
|
||||
if (ImGui::Selectable(ThemeManager::NativeTheme, selection == ThemeManager::NativeTheme)) {
|
||||
selection = ThemeManager::NativeTheme;
|
||||
setting = selection;
|
||||
ImHexApi::System::enableSystemThemeDetection(true);
|
||||
changed = true;
|
||||
}
|
||||
ContentRegistry::Settings::add<Widgets::DropDown>("hex.builtin.setting.interface", "", "hex.builtin.setting.interface.color",
|
||||
themeNames,
|
||||
themeJsons).setChangedCallback([](auto &widget) {
|
||||
auto dropDown = static_cast<Widgets::DropDown *>(&widget);
|
||||
|
||||
for (const auto &themeName : themeNames) {
|
||||
if (ImGui::Selectable(themeName.c_str(), selection == themeName)) {
|
||||
selection = themeName;
|
||||
setting = selection;
|
||||
ImHexApi::System::enableSystemThemeDetection(false);
|
||||
ThemeManager::changeTheme(selection);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (dropDown->getValue() == ThemeManager::NativeTheme)
|
||||
ImHexApi::System::enableSystemThemeDetection(true);
|
||||
else {
|
||||
ImHexApi::System::enableSystemThemeDetection(false);
|
||||
ThemeManager::changeTheme(dropDown->getValue());
|
||||
}
|
||||
});
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ContentRegistry::Settings::add<ScalingWidget>("hex.builtin.setting.interface", "", "hex.builtin.setting.interface.scaling").requiresRestart();
|
||||
|
||||
return changed;
|
||||
});
|
||||
std::vector<std::string> languageNames;
|
||||
std::vector<nlohmann::json> languageCodes;
|
||||
|
||||
ContentRegistry::Settings::add(
|
||||
"hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling", 0, [](auto name, nlohmann::json &setting) {
|
||||
static int selection = static_cast<int>(setting);
|
||||
for (auto &[languageCode, languageName] : LangEntry::getSupportedLanguages()) {
|
||||
languageNames.emplace_back(languageName);
|
||||
languageCodes.emplace_back(languageCode);
|
||||
}
|
||||
|
||||
const char *scaling[] = {
|
||||
"hex.builtin.setting.interface.scaling.native"_lang,
|
||||
"hex.builtin.setting.interface.scaling.x0_5"_lang,
|
||||
"hex.builtin.setting.interface.scaling.x1_0"_lang,
|
||||
"hex.builtin.setting.interface.scaling.x1_5"_lang,
|
||||
"hex.builtin.setting.interface.scaling.x2_0"_lang,
|
||||
};
|
||||
ContentRegistry::Settings::add<Widgets::DropDown>("hex.builtin.setting.interface", "", "hex.builtin.setting.interface.language", languageNames, languageCodes);
|
||||
|
||||
if (ImGui::Combo(name.data(), &selection, scaling, IM_ARRAYSIZE(scaling))) {
|
||||
setting = selection;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
true);
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.language", "en-US", [](auto name, nlohmann::json &setting) {
|
||||
auto &languages = LangEntry::getSupportedLanguages();
|
||||
if (!languages.contains(setting.get<std::string>()))
|
||||
setting = "en-US";
|
||||
|
||||
bool changed = false;
|
||||
if (ImGui::BeginCombo(name.data(), languages.at(setting.get<std::string>()).c_str())) {
|
||||
for (auto &[languageCode, languageName] : languages) {
|
||||
if (ImGui::Selectable(languageName.c_str(), setting == languageCode)) {
|
||||
setting = languageCode;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
return changed;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.wiki_explain_language", "en", [](auto name, nlohmann::json &setting) {
|
||||
static auto lang = std::string(setting);
|
||||
|
||||
if (ImGui::InputText(name.data(), lang, ImGuiInputTextFlags_CharsNoBlank)) {
|
||||
// Remove trailing null bytes
|
||||
setting = std::string(lang.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.fps", 60, [](auto name, nlohmann::json &setting) {
|
||||
static int fps = static_cast<int>(setting);
|
||||
|
||||
auto format = [] -> std::string {
|
||||
if (fps > 200)
|
||||
return "hex.builtin.setting.interface.fps.unlocked"_lang;
|
||||
else if (fps < 15)
|
||||
return "hex.builtin.setting.interface.fps.native"_lang;
|
||||
else
|
||||
return "%d FPS";
|
||||
}();
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &fps, 14, 201, format.c_str(), ImGuiSliderFlags_AlwaysClamp)) {
|
||||
setting = fps;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
ContentRegistry::Settings::add<Widgets::TextBox>("hex.builtin.setting.interface", "", "hex.builtin.setting.interface.wiki_explain_language", "en");
|
||||
ContentRegistry::Settings::add<FPSWidget>("hex.builtin.setting.interface", "", "hex.builtin.setting.interface.fps");
|
||||
|
||||
#if defined (OS_LINUX)
|
||||
constexpr static auto MultiWindowSupportEnabledDefault = 0;
|
||||
@ -245,245 +247,64 @@ namespace hex::plugin::builtin {
|
||||
constexpr static auto MultiWindowSupportEnabledDefault = 1;
|
||||
#endif
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", MultiWindowSupportEnabledDefault, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.interface", "", "hex.builtin.setting.interface.multi_windows", MultiWindowSupportEnabledDefault).requiresRestart();
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.interface", "", "hex.builtin.setting.interface.restore_window_pos", false);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}, true);
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.highlight_color", 0x60C08080, [](auto name, nlohmann::json &setting) {
|
||||
static auto color = static_cast<color_t>(setting);
|
||||
|
||||
std::array<float, 4> colorArray = {
|
||||
((color >> 0) & 0x000000FF) / float(0xFF),
|
||||
((color >> 8) & 0x000000FF) / float(0xFF),
|
||||
((color >> 16) & 0x000000FF) / float(0xFF),
|
||||
((color >> 24) & 0x000000FF) / float(0xFF)
|
||||
};
|
||||
|
||||
if (ImGui::ColorEdit4(name.data(), colorArray.data(), ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoDragDrop | ImGuiColorEditFlags_NoInputs)) {
|
||||
color =
|
||||
(color_t(colorArray[0] * 0xFF) << 0) |
|
||||
(color_t(colorArray[1] * 0xFF) << 8) |
|
||||
(color_t(colorArray[2] * 0xFF) << 16) |
|
||||
(color_t(colorArray[3] * 0xFF) << 24);
|
||||
|
||||
setting = color;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.sync_scrolling", 0, [](auto name, nlohmann::json &setting) {
|
||||
static bool syncScrolling = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &syncScrolling)) {
|
||||
setting = static_cast<int>(syncScrolling);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.byte_padding", 0, [](auto name, nlohmann::json &setting) {
|
||||
static int padding = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &padding, 0, 50)) {
|
||||
setting = padding;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.char_padding", 0, [](auto name, nlohmann::json &setting) {
|
||||
static int padding = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &padding, 0, 50)) {
|
||||
setting = padding;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.restore_window_pos", 0, [](auto name, nlohmann::json &setting) {
|
||||
static bool restoreWindowPos = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &restoreWindowPos)) {
|
||||
setting = static_cast<int>(restoreWindowPos);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
ContentRegistry::Settings::add<Widgets::ColorPicker>("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.highlight_color", ImColor(0x80, 0x80, 0xC0, 0x60));
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.sync_scrolling", false);
|
||||
ContentRegistry::Settings::add<Widgets::SliderInteger>("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.byte_padding", 0, 0, 50);
|
||||
ContentRegistry::Settings::add<Widgets::SliderInteger>("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.char_padding", 0, 0, 50);
|
||||
|
||||
|
||||
/* Fonts */
|
||||
|
||||
static std::string fontPath;
|
||||
ContentRegistry::Settings::add(
|
||||
"hex.builtin.setting.font", "hex.builtin.setting.font.font_path", "", [](auto name, nlohmann::json &setting) {
|
||||
fontPath = static_cast<std::string>(setting);
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.font", "hex.builtin.setting.font.glyphs", "hex.builtin.setting.font.load_all_unicode_chars", false);
|
||||
auto fontPathSetting = ContentRegistry::Settings::add<Widgets::FilePicker>("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_path").requiresRestart();
|
||||
ContentRegistry::Settings::add<Widgets::SliderInteger>("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_size", 13, 0, 100)
|
||||
.requiresRestart()
|
||||
.setEnabledCallback([fontPathSetting]{
|
||||
auto &filePicker = static_cast<Widgets::FilePicker &>(fontPathSetting.getWidget());
|
||||
|
||||
if (ImGui::InputText("##font_path", fontPath)) {
|
||||
setting = fontPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::IconButton(ICON_VS_FOLDER_OPENED, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||
return fs::openFileBrowser(fs::DialogMode::Open, { { "TTF Font", "ttf" }, { "OTF Font", "otf" } },
|
||||
[&](const std::fs::path &path) {
|
||||
fontPath = wolv::util::toUTF8String(path);
|
||||
setting = fontPath;
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::TextFormatted("{}", name);
|
||||
|
||||
return false;
|
||||
},
|
||||
true);
|
||||
|
||||
ContentRegistry::Settings::add(
|
||||
"hex.builtin.setting.font", "hex.builtin.setting.font.font_size", 13, [](auto name, nlohmann::json &setting) {
|
||||
static int fontSize = static_cast<int>(setting);
|
||||
|
||||
ImGui::BeginDisabled(fontPath.empty());
|
||||
ON_SCOPE_EXIT { ImGui::EndDisabled(); };
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &fontSize, 0, 100, "%d", ImGuiSliderFlags_NoInput)) {
|
||||
setting = fontSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fontPath.empty() && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
|
||||
ImGui::SetNextWindowSize(scaled(ImVec2(300, 0)));
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextFormattedWrapped("{}", "hex.builtin.setting.font.font_size.tooltip"_lang);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
true);
|
||||
return !filePicker.getPath().empty();
|
||||
});
|
||||
|
||||
|
||||
/* Folders */
|
||||
|
||||
static const std::string dirsSetting { "hex.builtin.setting.folders" };
|
||||
|
||||
ContentRegistry::Settings::addCategoryDescription(dirsSetting, "hex.builtin.setting.folders.description");
|
||||
|
||||
ContentRegistry::Settings::add(dirsSetting, dirsSetting, std::vector<std::string> {}, [](auto name, nlohmann::json &setting) {
|
||||
hex::unused(name);
|
||||
|
||||
static size_t currentItemIndex = [&setting] {loadUserFoldersFromSetting(setting); return 0; }();
|
||||
|
||||
auto saveToSetting = [&setting] {
|
||||
std::vector<std::string> folderStrings;
|
||||
for (const auto &folder : userFolders) {
|
||||
auto utfString = folder.u8string();
|
||||
// JSON stores char8_t as array, char8_t is not supported as of now
|
||||
folderStrings.emplace_back(reinterpret_cast<const char *>(&utfString.front()), reinterpret_cast<const char *>(std::next(&utfString.back())));
|
||||
}
|
||||
setting = folderStrings;
|
||||
ImHexApi::System::setAdditionalFolderPaths(userFolders);
|
||||
};
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (!ImGui::BeginListBox("", ImVec2(-38, -FLT_MIN))) {
|
||||
return false;
|
||||
} else {
|
||||
for (size_t n = 0; n < userFolders.size(); n++) {
|
||||
const bool isSelected = (currentItemIndex == n);
|
||||
if (ImGui::Selectable(wolv::util::toUTF8String(userFolders.at(n)).c_str(), isSelected)) { currentItemIndex = n; }
|
||||
if (isSelected) { ImGui::SetItemDefaultFocus(); }
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginGroup();
|
||||
|
||||
if (ImGui::IconButton(ICON_VS_NEW_FOLDER, ImGui::GetCustomColorVec4(ImGuiCustomCol_DescButton), ImVec2(30, 30))) {
|
||||
fs::openFileBrowser(fs::DialogMode::Folder, {}, [&](const std::fs::path &path) {
|
||||
if (std::find(userFolders.begin(), userFolders.end(), path) == userFolders.end()) {
|
||||
userFolders.emplace_back(path);
|
||||
saveToSetting();
|
||||
result = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
ImGui::InfoTooltip("hex.builtin.setting.folders.add_folder"_lang);
|
||||
|
||||
if (ImGui::IconButton(ICON_VS_REMOVE_CLOSE, ImGui::GetCustomColorVec4(ImGuiCustomCol_DescButton), ImVec2(30, 30))) {
|
||||
if (!userFolders.empty()) {
|
||||
userFolders.erase(std::next(userFolders.begin(), currentItemIndex));
|
||||
saveToSetting();
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
ImGui::InfoTooltip("hex.builtin.setting.folders.remove_folder"_lang);
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
return result;
|
||||
});
|
||||
ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.folders", "hex.builtin.setting.folders.description");
|
||||
ContentRegistry::Settings::add<UserFolderWidget>("hex.builtin.setting.folders", "", "hex.builtin.setting.folders.description");
|
||||
|
||||
/* Proxy */
|
||||
|
||||
static const std::string proxySetting { "hex.builtin.setting.proxy" };
|
||||
HttpRequest::setProxy(ContentRegistry::Settings::read("hex.builtin.setting.proxy", "hex.builtin.setting.proxy.url", "").get<std::string>());
|
||||
|
||||
HttpRequest::setProxy(ContentRegistry::Settings::read(proxySetting, "hex.builtin.setting.proxy.url", ""));
|
||||
ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.proxy", "hex.builtin.setting.proxy.description");
|
||||
|
||||
ContentRegistry::Settings::addCategoryDescription(proxySetting, "hex.builtin.setting.proxy.description");
|
||||
auto proxyEnabledSetting = ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.proxy", "", "hex.builtin.setting.proxy.enable", false).setChangedCallback([](Widgets::Widget &widget) {
|
||||
auto checkBox = static_cast<Widgets::Checkbox *>(&widget);
|
||||
|
||||
ContentRegistry::Settings::add(
|
||||
proxySetting, "hex.builtin.setting.proxy.url", "", [](auto name, nlohmann::json &setting) {
|
||||
static std::string proxyUrl = static_cast<std::string>(setting);
|
||||
static bool enableProxy = !proxyUrl.empty();
|
||||
if (checkBox->isChecked()) {
|
||||
HttpRequest::setProxy(ContentRegistry::Settings::read("hex.builtin.setting.proxy", "hex.builtin.setting.proxy.url", "").get<std::string>());
|
||||
} else {
|
||||
HttpRequest::setProxy("");
|
||||
}
|
||||
});
|
||||
|
||||
bool result = false;
|
||||
ContentRegistry::Settings::add<Widgets::TextBox>("hex.builtin.setting.proxy", "", "hex.builtin.setting.proxy.url", "")
|
||||
.setEnabledCallback([proxyEnabledSetting] {
|
||||
auto &checkBox = static_cast<Widgets::Checkbox &>(proxyEnabledSetting.getWidget());
|
||||
|
||||
if (ImGui::Checkbox("hex.builtin.setting.proxy.enable"_lang, &enableProxy)) {
|
||||
setting = enableProxy ? proxyUrl : "";
|
||||
HttpRequest::setProxy(enableProxy ? proxyUrl : "");
|
||||
result = true;
|
||||
}
|
||||
return checkBox.isChecked();
|
||||
})
|
||||
.setChangedCallback([](Widgets::Widget &widget) {
|
||||
auto textBox = static_cast<Widgets::TextBox *>(&widget);
|
||||
|
||||
ImGui::BeginDisabled(!enableProxy);
|
||||
if (ImGui::InputText("##proxy_url", proxyUrl)) {
|
||||
setting = proxyUrl;
|
||||
HttpRequest::setProxy(proxyUrl);
|
||||
result = true;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::InfoTooltip("hex.builtin.setting.proxy.url.tooltip"_lang);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::TextFormatted("{}", name);
|
||||
return result;
|
||||
},
|
||||
false);
|
||||
HttpRequest::setProxy(textBox->getValue());
|
||||
});
|
||||
}
|
||||
|
||||
static void loadThemeSettings() {
|
||||
auto theme = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", ThemeManager::NativeTheme);
|
||||
auto theme = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", ThemeManager::NativeTheme).get<std::string>();
|
||||
|
||||
if (theme == ThemeManager::NativeTheme)
|
||||
ImHexApi::System::enableSystemThemeDetection(true);
|
||||
@ -493,16 +314,20 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
static void loadFoldersSettings() {
|
||||
auto directories = ContentRegistry::Settings::read("hex.builtin.setting.folders", "hex.builtin.setting.folders", std::vector<std::string> { });
|
||||
static void loadFolderSettings() {
|
||||
auto folderPathStrings = ContentRegistry::Settings::read("hex.builtin.setting.folders", "hex.builtin.setting.folders", std::vector<std::string> { });
|
||||
|
||||
loadUserFoldersFromSetting(directories);
|
||||
ImHexApi::System::setAdditionalFolderPaths(userFolders);
|
||||
std::vector<std::fs::path> paths;
|
||||
for (const auto &pathString : folderPathStrings) {
|
||||
paths.emplace_back(pathString);
|
||||
}
|
||||
|
||||
ImHexApi::System::setAdditionalFolderPaths(paths);
|
||||
}
|
||||
|
||||
void loadSettings() {
|
||||
loadThemeSettings();
|
||||
loadFoldersSettings();
|
||||
loadFolderSettings();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -656,7 +656,7 @@ namespace hex::plugin::builtin {
|
||||
}*/
|
||||
|
||||
std::string getWikipediaApiUrl() {
|
||||
auto setting = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.wiki_explain_language", "en");
|
||||
std::string setting = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.wiki_explain_language", "en");
|
||||
return "https://" + setting + ".wikipedia.org/w/api.php?format=json&action=query&prop=extracts&explaintext&redirects=10&formatversion=2";
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
// Load settings
|
||||
this->m_showPopup = bool(ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.achievement_popup", 1));
|
||||
this->m_showPopup = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.achievement_popup", true);
|
||||
}
|
||||
|
||||
ViewAchievements::~ViewAchievements() {
|
||||
@ -381,7 +381,7 @@ namespace hex::plugin::builtin {
|
||||
ImGui::BeginGroup();
|
||||
{
|
||||
if (ImGui::Checkbox("Show popup", &this->m_showPopup))
|
||||
ContentRegistry::Settings::write("hex.builtin.setting.interface", "hex.builtin.setting.interface.achievement_popup", i64(this->m_showPopup));
|
||||
ContentRegistry::Settings::write("hex.builtin.setting.interface", "hex.builtin.setting.interface.achievement_popup", this->m_showPopup);
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
|
||||
|
@ -1044,13 +1044,15 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventSettingsChanged>(this, [this] {
|
||||
this->m_syncPatternSourceCode = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.sync_pattern_source", 0) == 1;
|
||||
this->m_autoLoadPatterns = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", 1) == 1;
|
||||
this->m_syncPatternSourceCode = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.sync_pattern_source", false);
|
||||
this->m_autoLoadPatterns = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", true);
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderOpened>(this, [this](prv::Provider *provider) {
|
||||
this->m_shouldAnalyze.get(provider) = true;
|
||||
this->m_envVarEntries->push_back({ 0, "", 0, EnvVarType::Integer });
|
||||
|
||||
this->m_debuggerDrawer.get(provider) = std::make_unique<ui::PatternDrawer>();
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderChanged>(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) {
|
||||
@ -1069,10 +1071,6 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderOpened>(this, [this](prv::Provider *provider) {
|
||||
this->m_debuggerDrawer.get(provider) = std::make_unique<ui::PatternDrawer>();
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderClosed>(this, [this](prv::Provider *) {
|
||||
if (this->m_syncPatternSourceCode && ImHexApi::Provider::getProviders().empty()) {
|
||||
this->m_textEditor.SetText("");
|
||||
|
@ -36,66 +36,76 @@ namespace hex::plugin::builtin {
|
||||
|
||||
if (ImGui::BeginPopupModal(View::toWindowName("hex.builtin.view.settings.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoResize)) {
|
||||
if (ImGui::BeginTabBar("settings")) {
|
||||
auto &entries = ContentRegistry::Settings::impl::getEntries();
|
||||
|
||||
// Sort the categories by slot
|
||||
auto sortedCategories = [&entries] {
|
||||
std::vector<std::decay_t<decltype(entries)>::const_iterator> sortedCategories;
|
||||
|
||||
for (auto it = entries.cbegin(); it != entries.cend(); it++) {
|
||||
sortedCategories.emplace_back(it);
|
||||
}
|
||||
|
||||
std::sort(sortedCategories.begin(), sortedCategories.end(), [](auto &item0, auto &item1) {
|
||||
return item0->first.slot < item1->first.slot;
|
||||
});
|
||||
|
||||
return sortedCategories;
|
||||
}();
|
||||
|
||||
// Get the description of the current category
|
||||
const auto &descriptions = ContentRegistry::Settings::impl::getCategoryDescriptions();
|
||||
auto &categories = ContentRegistry::Settings::impl::getSettings();
|
||||
|
||||
// Draw all categories
|
||||
for (auto &iter : sortedCategories) {
|
||||
auto &[category, settings] = *iter;
|
||||
for (auto &category : categories) {
|
||||
|
||||
// Skip empty categories
|
||||
if (category.subCategories.empty())
|
||||
continue;
|
||||
|
||||
// For each category, create a new tab
|
||||
if (ImGui::BeginTabItem(LangEntry(category.name))) {
|
||||
const std::string &categoryDesc = descriptions.contains(category.name) ? descriptions.at(category.name) : category.name;
|
||||
|
||||
if (ImGui::BeginTabItem(LangEntry(category.unlocalizedName))) {
|
||||
// Draw the category description
|
||||
LangEntry descriptionEntry(categoryDesc);
|
||||
ImGui::TextFormattedWrapped("{}", descriptionEntry);
|
||||
ImGui::InfoTooltip(descriptionEntry);
|
||||
ImGui::Separator();
|
||||
if (!category.unlocalizedDescription.empty()) {
|
||||
ImGui::TextFormattedWrapped("{}", LangEntry(category.unlocalizedDescription));
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
bool firstSubCategory = true;
|
||||
|
||||
// Draw all settings of that category
|
||||
for (auto &[name, requiresRestart, callback] : settings) {
|
||||
// Get the current value of the setting
|
||||
auto &setting = ContentRegistry::Settings::impl::getSettingsData()[category.name][name];
|
||||
for (auto &subCategory : category.subCategories) {
|
||||
|
||||
// Execute the settings drawing callback
|
||||
if (callback(LangEntry(name), setting)) {
|
||||
// Handle a setting being changed
|
||||
// Skip empty subcategories
|
||||
if (subCategory.entries.empty())
|
||||
continue;
|
||||
|
||||
// Print a debug message
|
||||
log::debug("Setting [{}]: {} was changed to {}", category.name, name, [&] -> std::string {
|
||||
if (setting.is_number())
|
||||
return std::to_string(setting.get<int>());
|
||||
else if (setting.is_string())
|
||||
return setting.get<std::string>();
|
||||
else
|
||||
return "";
|
||||
}());
|
||||
if (!subCategory.unlocalizedName.empty())
|
||||
ImGui::Header(LangEntry(subCategory.unlocalizedName), firstSubCategory);
|
||||
|
||||
// Post an event
|
||||
EventManager::post<EventSettingsChanged>();
|
||||
firstSubCategory = false;
|
||||
|
||||
// Request a restart if the setting requires it
|
||||
if (requiresRestart)
|
||||
this->m_restartRequested = true;
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, scaled({5, 5}));
|
||||
if (ImGui::BeginTable("##subCategory", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_SizingStretchSame)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
for (auto &setting : subCategory.entries) {
|
||||
ImGui::BeginDisabled(!setting.widget->isEnabled());
|
||||
bool settingChanged = setting.widget->draw(LangEntry(setting.unlocalizedName));
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (auto tooltip = setting.widget->getTooltip(); tooltip.has_value() && ImGui::IsItemHovered())
|
||||
ImGui::InfoTooltip(LangEntry(tooltip.value()));
|
||||
|
||||
auto &widget = setting.widget;
|
||||
|
||||
// Handle a setting being changed
|
||||
if (settingChanged) {
|
||||
auto newValue = widget->store();
|
||||
|
||||
// Write new value to settings
|
||||
ContentRegistry::Settings::write(category.unlocalizedName, setting.unlocalizedName, newValue);
|
||||
|
||||
// Print a debug message
|
||||
log::debug("Setting [{} / {}]: Value was changed to {}", category.unlocalizedName, setting.unlocalizedName, nlohmann::to_string(newValue));
|
||||
|
||||
// Signal that the setting was changed
|
||||
EventManager::post<EventSettingsChanged>();
|
||||
widget->onChanged();
|
||||
|
||||
// Request a restart if the setting requires it
|
||||
if (widget->doesRequireRestart())
|
||||
this->m_restartRequested = true;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
|
@ -58,7 +58,7 @@ namespace hex::plugin::builtin {
|
||||
m_restoreCallback(restoreCallback),
|
||||
m_deleteCallback(deleteCallback) {
|
||||
|
||||
this->m_reportError = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", 1);
|
||||
this->m_reportError = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", true);
|
||||
}
|
||||
|
||||
void drawContent() override {
|
||||
@ -104,7 +104,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", i64(this->m_reportError));
|
||||
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", this->m_reportError);
|
||||
|
||||
this->close();
|
||||
}
|
||||
@ -394,7 +394,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
(void)EventManager::subscribe<EventSettingsChanged>([]() {
|
||||
{
|
||||
auto theme = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", ThemeManager::NativeTheme);
|
||||
auto theme = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", ThemeManager::NativeTheme).get<std::string>();
|
||||
|
||||
if (theme != ThemeManager::NativeTheme) {
|
||||
static std::string lastTheme;
|
||||
@ -407,14 +407,14 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
{
|
||||
auto language = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.language", "en-US");
|
||||
auto language = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.language", "en-US").get<std::string>();
|
||||
|
||||
if (language != LangEntry::getSelectedLanguage())
|
||||
LangEntry::loadLanguage(language);
|
||||
}
|
||||
|
||||
{
|
||||
auto targetFps = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.fps", 14);
|
||||
auto targetFps = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.fps", 14).get<int>();
|
||||
|
||||
ImHexApi::System::setTargetFPS(targetFps);
|
||||
}
|
||||
@ -532,7 +532,7 @@ namespace hex::plugin::builtin {
|
||||
auto chosenTip = chosenCategory[random()%chosenCategory.size()];
|
||||
s_tipOfTheDay = chosenTip.get<std::string>();
|
||||
|
||||
bool showTipOfTheDay = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.show_tips", 1);
|
||||
bool showTipOfTheDay = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.show_tips", true);
|
||||
if (showTipOfTheDay)
|
||||
PopupTipOfTheDay::open();
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
registerPatternLanguageVisualizers();
|
||||
registerPatternLanguageInlineVisualizers();
|
||||
registerCommandPaletteCommands();
|
||||
registerThemes();
|
||||
registerSettings();
|
||||
loadSettings();
|
||||
registerDataProcessorNodes();
|
||||
@ -91,7 +92,6 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
registerViews();
|
||||
registerThemeHandlers();
|
||||
registerStyleHandlers();
|
||||
registerThemes();
|
||||
registerBackgroundServices();
|
||||
registerNetworkEndpoints();
|
||||
registerFileHandlers();
|
||||
|
@ -75,9 +75,9 @@ namespace hex::plugin::builtin::ui {
|
||||
|
||||
EventManager::subscribe<EventSettingsChanged>(this, [this] {
|
||||
this->m_selectionColor = ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.highlight_color", 0x60C08080);
|
||||
this->m_syncScrolling = ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.sync_scrolling", 0);
|
||||
this->m_byteCellPadding = ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.byte_padding", 0);
|
||||
this->m_characterCellPadding = ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.char_padding", 0);
|
||||
this->m_syncScrolling = ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.sync_scrolling", false);
|
||||
this->m_byteCellPadding = ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.byte_padding", false);
|
||||
this->m_characterCellPadding = ContentRegistry::Settings::read("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.char_padding", false);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -21,13 +21,13 @@ namespace hex::plugin::windows {
|
||||
RegCreateKeyExA(HKEY_CURRENT_USER, ImHexContextMenuKey, 0x00, nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr, &imHexRootKey, nullptr);
|
||||
RegSetValueA(imHexRootKey, nullptr, REG_SZ, "Open with ImHex", 0x00);
|
||||
|
||||
// Add Icon key to use first icon embedded in exe
|
||||
// Add 'Icon' key to use first icon embedded in exe
|
||||
std::array<char, MAX_PATH> imHexPath = { 0 };
|
||||
GetModuleFileNameA(nullptr, imHexPath.data(), imHexPath.size());
|
||||
auto iconValue = hex::format(R"("{}",0)", imHexPath.data());
|
||||
RegSetKeyValueA(imHexRootKey, nullptr, "Icon", REG_SZ, iconValue.c_str(), iconValue.size() + 1);
|
||||
|
||||
// Add command key to pass file path as first argument to ImHex
|
||||
// Add 'command' key to pass the right-clicked file path as first argument to ImHex
|
||||
auto commandValue = hex::format(R"("{}" "%1")", imHexPath.data());
|
||||
RegSetValueA(imHexRootKey, "command", REG_SZ, commandValue.c_str(), commandValue.size() + 1);
|
||||
RegCloseKey(imHexRootKey);
|
||||
@ -51,24 +51,19 @@ namespace hex::plugin::windows {
|
||||
|
||||
/* General */
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.context_menu_entry", 0, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = hasImHexContextMenuEntry();
|
||||
namespace Widgets = ContentRegistry::Settings::Widgets;
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.general", "", "hex.builtin.setting.general.context_menu_entry", false)
|
||||
.setChangedCallback([](auto &widget) {
|
||||
auto checked = static_cast<Widgets::Checkbox &>(widget).isChecked();
|
||||
|
||||
if (enabled)
|
||||
addImHexContextMenuEntry();
|
||||
else
|
||||
removeImHexContextMenuEntry();
|
||||
if (checked)
|
||||
addImHexContextMenuEntry();
|
||||
else
|
||||
removeImHexContextMenuEntry();
|
||||
|
||||
enabled = hasImHexContextMenuEntry();
|
||||
setting = enabled;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
widget.load(hasImHexContextMenuEntry());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -22,7 +22,7 @@ namespace hex::plugin::windows {
|
||||
static void detectSystemTheme() {
|
||||
// Setup system theme change detector
|
||||
EventManager::subscribe<EventOSThemeChanged>([] {
|
||||
bool themeFollowSystem = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", ThemeManager::NativeTheme) == ThemeManager::NativeTheme;
|
||||
bool themeFollowSystem = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", ThemeManager::NativeTheme).get<std::string>() == ThemeManager::NativeTheme;
|
||||
if (!themeFollowSystem)
|
||||
return;
|
||||
|
||||
@ -43,7 +43,7 @@ static void detectSystemTheme() {
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventWindowInitialized>([=] {
|
||||
bool themeFollowSystem = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", ThemeManager::NativeTheme) == ThemeManager::NativeTheme;
|
||||
bool themeFollowSystem = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", ThemeManager::NativeTheme).get<std::string>() == ThemeManager::NativeTheme;
|
||||
|
||||
if (themeFollowSystem)
|
||||
EventManager::post<EventOSThemeChanged>();
|
||||
@ -51,7 +51,7 @@ static void detectSystemTheme() {
|
||||
}
|
||||
|
||||
static void checkBorderlessWindowOverride() {
|
||||
bool borderlessWindowForced = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.force_borderless_window_mode", 0) != 0;
|
||||
bool borderlessWindowForced = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.force_borderless_window_mode", false);
|
||||
|
||||
if (borderlessWindowForced)
|
||||
ImHexApi::System::impl::setBorderlessWindowMode(true);
|
||||
|
Loading…
x
Reference in New Issue
Block a user