1
0
mirror of synced 2024-11-28 09:30:51 +01:00

impr: Rework setting change listeners

This commit is contained in:
WerWolv 2024-02-18 11:29:18 +01:00
parent c1aac6c85e
commit 01c934f53a
14 changed files with 152 additions and 56 deletions

View File

@ -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 */

View File

@ -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);

View File

@ -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) {

View File

@ -71,7 +71,8 @@ namespace hex {
this->registerEventHandlers();
ContentRegistry::Settings::impl::store();
EventSettingsChanged::post();
ContentRegistry::Settings::impl::load();
EventWindowInitialized::post();
EventImHexStartupFinished::post();
}

View File

@ -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);

View File

@ -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([] {

View File

@ -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);
}

View File

@ -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));
});
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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

View File

@ -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);
};

View File

@ -78,7 +78,7 @@ namespace hex::ui {
}
HexEditor::~HexEditor() {
EventSettingsChanged::unsubscribe(this);
}
constexpr static u16 getByteColumnSeparatorCount(u16 columnCount) {

View File

@ -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([] {