impr: Rework setting change listeners
This commit is contained in:
parent
c1aac6c85e
commit
01c934f53a
@ -279,6 +279,8 @@ namespace hex {
|
||||
Widgets::Widget* add(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedSubCategory, const UnlocalizedString &unlocalizedName, std::unique_ptr<Widgets::Widget> &&widget);
|
||||
|
||||
void printSettingReadError(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json::exception &e);
|
||||
|
||||
void runOnChangeHandlers(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &value);
|
||||
}
|
||||
|
||||
template<std::derived_from<Widgets::Widget> T>
|
||||
@ -293,6 +295,28 @@ namespace hex {
|
||||
|
||||
void setCategoryDescription(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedDescription);
|
||||
|
||||
class SettingsValue {
|
||||
public:
|
||||
SettingsValue(nlohmann::json value) : m_value(std::move(value)) {}
|
||||
|
||||
template<typename T>
|
||||
T get(std::common_type_t<T> defaultValue) const {
|
||||
try {
|
||||
auto result = m_value;
|
||||
if (result.is_number() && std::same_as<T, bool>)
|
||||
result = m_value.get<int>() != 0;
|
||||
if (m_value.is_null())
|
||||
result = defaultValue;
|
||||
|
||||
return result.get<T>();
|
||||
} catch (const nlohmann::json::exception &e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
private:
|
||||
nlohmann::json m_value;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] T read(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const std::common_type_t<T> &defaultValue) {
|
||||
auto setting = impl::getSetting(unlocalizedCategory, unlocalizedName, defaultValue);
|
||||
@ -314,8 +338,12 @@ namespace hex {
|
||||
template<typename T>
|
||||
void write(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const std::common_type_t<T> &value) {
|
||||
impl::getSetting(unlocalizedCategory, unlocalizedName, value) = value;
|
||||
impl::runOnChangeHandlers(unlocalizedCategory, unlocalizedName, value);
|
||||
}
|
||||
|
||||
using OnChangeCallback = std::function<void(const SettingsValue &)>;
|
||||
u64 onChange(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const OnChangeCallback &callback);
|
||||
|
||||
}
|
||||
|
||||
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
|
||||
|
@ -215,7 +215,6 @@ namespace hex {
|
||||
EVENT_DEF(EventHighlightingChanged);
|
||||
EVENT_DEF(EventWindowClosing, GLFWwindow *);
|
||||
EVENT_DEF(EventRegionSelected, ImHexApi::HexEditor::ProviderRegion);
|
||||
EVENT_DEF(EventSettingsChanged);
|
||||
EVENT_DEF(EventAbnormalTermination, int);
|
||||
EVENT_DEF(EventThemeChanged);
|
||||
EVENT_DEF(EventOSThemeChanged);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/data_processor/node.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <jthread.hpp>
|
||||
|
||||
@ -29,6 +30,13 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
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;
|
||||
@ -89,6 +97,14 @@ namespace hex {
|
||||
|
||||
if (!loaded)
|
||||
store();
|
||||
|
||||
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
|
||||
for (const auto &[name, callbacks] : rest) {
|
||||
for (const auto &[id, callback] : callbacks) {
|
||||
callback(getSetting(category, name, {}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void store() {
|
||||
@ -160,6 +176,19 @@ namespace hex {
|
||||
hex::log::error("Failed to read setting {}/{}: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -169,6 +198,43 @@ namespace hex {
|
||||
category->unlocalizedDescription = unlocalizedDescription;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -71,7 +71,8 @@ namespace hex {
|
||||
this->registerEventHandlers();
|
||||
|
||||
ContentRegistry::Settings::impl::store();
|
||||
EventSettingsChanged::post();
|
||||
ContentRegistry::Settings::impl::load();
|
||||
|
||||
EventWindowInitialized::post();
|
||||
EventImHexStartupFinished::post();
|
||||
}
|
||||
|
@ -86,9 +86,12 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
void registerBackgroundServices() {
|
||||
EventSettingsChanged::subscribe([]{
|
||||
networkInterfaceServiceEnabled = ContentRegistry::Settings::read<bool>("hex.builtin.setting.general", "hex.builtin.setting.general.network_interface", false);
|
||||
autoBackupTime = ContentRegistry::Settings::read<int>("hex.builtin.setting.general", "hex.builtin.setting.general.auto_backup_time", 0) * 30;
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.network_interface", [](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
networkInterfaceServiceEnabled = value.get<bool>(false);
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.auto_backup_time", [](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
autoBackupTime = value.get<int>(0) * 30;
|
||||
});
|
||||
|
||||
ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.network_interface", handleNetworkInterfaceService);
|
||||
|
@ -286,8 +286,8 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
static bool alwaysShowProviderTabs = false;
|
||||
EventSettingsChanged::subscribe([] {
|
||||
alwaysShowProviderTabs = ContentRegistry::Settings::read<bool>("hex.builtin.setting.interface", "hex.builtin.setting.interface.always_show_provider_tabs", false);
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.always_show_provider_tabs", [](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
alwaysShowProviderTabs = value.get<bool>(false);
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addToolbarItem([] {
|
||||
|
@ -47,9 +47,8 @@ namespace hex::plugin::builtin {
|
||||
m_selectedProvider = nullptr;
|
||||
});
|
||||
|
||||
EventSettingsChanged::subscribe(this, [this] {
|
||||
auto filterValues = ContentRegistry::Settings::read<std::vector<std::string>>("hex.builtin.setting.data_inspector", "hex.builtin.setting.data_inspector.hidden_rows", { });
|
||||
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.data_inspector", "hex.builtin.setting.data_inspector.hidden_rows", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
auto filterValues = value.get<std::vector<std::string>>({});
|
||||
m_hiddenValues = std::set(filterValues.begin(), filterValues.end());
|
||||
});
|
||||
}
|
||||
@ -57,7 +56,6 @@ namespace hex::plugin::builtin {
|
||||
ViewDataInspector::~ViewDataInspector() {
|
||||
EventRegionSelected::unsubscribe(this);
|
||||
EventProviderClosed::unsubscribe(this);
|
||||
EventSettingsChanged::unsubscribe(this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -462,7 +462,6 @@ namespace hex::plugin::builtin {
|
||||
EventProviderChanged::unsubscribe(this);
|
||||
EventProviderOpened::unsubscribe(this);
|
||||
EventHighlightingChanged::unsubscribe(this);
|
||||
EventSettingsChanged::unsubscribe(this);
|
||||
|
||||
ContentRegistry::Settings::write<int>("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.bytes_per_row", m_hexEditor.getBytesPerRow());
|
||||
}
|
||||
@ -878,11 +877,17 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
m_hexEditor.setBytesPerRow(ContentRegistry::Settings::read<int>("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.bytes_per_row", m_hexEditor.getBytesPerRow()));
|
||||
EventSettingsChanged::subscribe(this, [this] {
|
||||
m_hexEditor.setSelectionColor(ContentRegistry::Settings::read<int>("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.highlight_color", 0x60C08080));
|
||||
m_hexEditor.enableSyncScrolling(ContentRegistry::Settings::read<bool>("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.sync_scrolling", false));
|
||||
m_hexEditor.setByteCellPadding(ContentRegistry::Settings::read<int>("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.byte_padding", 0));
|
||||
m_hexEditor.setCharacterCellPadding(ContentRegistry::Settings::read<int>("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.char_padding", 0));
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.hex_editor", "hex.builtin.setting.highlight_color", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
m_hexEditor.setSelectionColor(value.get<int>(0x60C08080));
|
||||
});
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.sync_scrolling", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
m_hexEditor.enableSyncScrolling(value.get<bool>(false));
|
||||
});
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.byte_padding", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
m_hexEditor.setByteCellPadding(value.get<int>(0));
|
||||
});
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.char_padding", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
m_hexEditor.setCharacterCellPadding(value.get<int>(0));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -12,12 +12,15 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ViewPatternData::ViewPatternData() : View::Window("hex.builtin.view.pattern_data.name", ICON_VS_DATABASE) {
|
||||
// Handle tree style setting changes
|
||||
EventSettingsChanged::subscribe(this, [this] {
|
||||
m_treeStyle = ui::PatternDrawer::TreeStyle(ContentRegistry::Settings::read<int>("hex.builtin.setting.interface", "hex.builtin.setting.interface.pattern_tree_style", 0));
|
||||
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.pattern_tree_style", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
m_treeStyle = ui::PatternDrawer::TreeStyle(value.get<int>(0));
|
||||
for (auto &drawer : m_patternDrawer.all())
|
||||
drawer->setTreeStyle(m_treeStyle);
|
||||
});
|
||||
|
||||
m_rowColoring = ContentRegistry::Settings::read<int>("hex.builtin.setting.interface", "hex.builtin.setting.interface.pattern_data_row_bg", false);
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.pattern_data_row_bg", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
m_rowColoring = bool(value.get<int>(false));
|
||||
for (auto &drawer : m_patternDrawer.all())
|
||||
drawer->enableRowColoring(m_rowColoring);
|
||||
});
|
||||
@ -48,7 +51,6 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
ViewPatternData::~ViewPatternData() {
|
||||
EventSettingsChanged::unsubscribe(this);
|
||||
EventPatternEvaluating::unsubscribe(this);
|
||||
EventPatternExecuted::unsubscribe(this);
|
||||
}
|
||||
|
@ -1657,9 +1657,11 @@ namespace hex::plugin::builtin {
|
||||
m_hasUnevaluatedChanges = true;
|
||||
});
|
||||
|
||||
EventSettingsChanged::subscribe(this, [this] {
|
||||
m_sourceCode.enableSync(ContentRegistry::Settings::read<bool>("hex.builtin.setting.general", "hex.builtin.setting.general.sync_pattern_source", false));
|
||||
m_autoLoadPatterns = ContentRegistry::Settings::read<bool>("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", true);
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.sync_pattern_source", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
m_sourceCode.enableSync(value.get<bool>(false));
|
||||
});
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", [this](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
m_autoLoadPatterns = value.get<bool>(true);
|
||||
});
|
||||
|
||||
EventProviderOpened::subscribe(this, [this](prv::Provider *provider) {
|
||||
|
@ -101,7 +101,6 @@ namespace hex::plugin::builtin {
|
||||
log::debug("Setting [{} / {}]: Value was changed to {}", category.unlocalizedName.get(), setting.unlocalizedName.get(), nlohmann::to_string(newValue));
|
||||
|
||||
// Signal that the setting was changed
|
||||
EventSettingsChanged::post();
|
||||
widget->onChanged();
|
||||
|
||||
// Request a restart if the setting requires it
|
||||
|
@ -443,18 +443,16 @@ namespace hex::plugin::builtin {
|
||||
recent::registerEventHandlers();
|
||||
recent::updateRecentEntries();
|
||||
|
||||
(void)EventFrameBegin::subscribe(drawWelcomeScreen);
|
||||
EventFrameBegin::subscribe(drawWelcomeScreen);
|
||||
|
||||
// Sets a background when they are no views
|
||||
(void)EventFrameBegin::subscribe([]{
|
||||
EventFrameBegin::subscribe([]{
|
||||
if (ImHexApi::Provider::isValid() && !isAnyViewOpen())
|
||||
drawNoViewsBackground();
|
||||
});
|
||||
|
||||
(void)EventSettingsChanged::subscribe([] {
|
||||
{
|
||||
auto theme = ContentRegistry::Settings::read<std::string>("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", ThemeManager::NativeTheme);
|
||||
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", [](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
auto theme = value.get<std::string>("Dark");
|
||||
if (theme != ThemeManager::NativeTheme) {
|
||||
static std::string lastTheme;
|
||||
|
||||
@ -463,25 +461,20 @@ namespace hex::plugin::builtin {
|
||||
lastTheme = theme;
|
||||
}
|
||||
}
|
||||
|
||||
s_simplifiedWelcomeScreen = ContentRegistry::Settings::read<bool>("hex.builtin.setting.interface", "hex.builtin.setting.interface.simplified_welcome_screen", false);
|
||||
}
|
||||
|
||||
{
|
||||
auto language = ContentRegistry::Settings::read<std::string>("hex.builtin.setting.interface", "hex.builtin.setting.interface.language", "en-US");
|
||||
|
||||
});
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.simplified_welcome_screen", [](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
s_simplifiedWelcomeScreen = value.get<bool>(false);
|
||||
});
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.language", [](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
auto language = value.get<std::string>("en-US");
|
||||
if (language != LocalizationManager::getSelectedLanguage())
|
||||
LocalizationManager::loadLanguage(language);
|
||||
}
|
||||
|
||||
{
|
||||
auto targetFps = ContentRegistry::Settings::read<int>("hex.builtin.setting.interface", "hex.builtin.setting.interface.fps", 14);
|
||||
|
||||
ImHexApi::System::setTargetFPS(static_cast<float>(targetFps));
|
||||
}
|
||||
});
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.fps", [](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
ImHexApi::System::setTargetFPS(static_cast<float>(value.get<int>(14)));
|
||||
});
|
||||
|
||||
(void)RequestChangeTheme::subscribe([](const std::string &theme) {
|
||||
RequestChangeTheme::subscribe([](const std::string &theme) {
|
||||
auto changeTexture = [&](const std::string &path) {
|
||||
return ImGuiExt::Texture(romfs::get(path).span(), ImGuiExt::Texture::Filter::Linear);
|
||||
};
|
||||
|
@ -78,7 +78,7 @@ namespace hex::ui {
|
||||
}
|
||||
|
||||
HexEditor::~HexEditor() {
|
||||
EventSettingsChanged::unsubscribe(this);
|
||||
|
||||
}
|
||||
|
||||
constexpr static u16 getByteColumnSeparatorCount(u16 columnCount) {
|
||||
|
@ -16,8 +16,8 @@ namespace hex::plugin::windows {
|
||||
void addFooterItems() {
|
||||
|
||||
static bool showResourceUsage = true;
|
||||
EventSettingsChanged::subscribe([]{
|
||||
showResourceUsage = ContentRegistry::Settings::read<bool>("hex.builtin.setting.interface", "hex.builtin.setting.interface.show_resource_usage", true);
|
||||
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.show_resource_usage", [](const ContentRegistry::Settings::SettingsValue &value) {
|
||||
showResourceUsage = value.get<bool>(false);
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addFooterItem([] {
|
||||
|
Loading…
Reference in New Issue
Block a user