From bcbcb1f23c6c8b4cbdd8b0ad1bd0b8bca9741def Mon Sep 17 00:00:00 2001 From: Nik Date: Sat, 10 Feb 2024 23:31:05 +0100 Subject: [PATCH] impr: Various web build improvements, API cleanup (#1541) --- dist/web/source/style.css | 1 + dist/web/source/wasm-config.js | 6 +- .../include/hex/api/achievement_manager.hpp | 26 +- .../include/hex/api/content_registry.hpp | 77 +-- lib/libimhex/include/hex/api/imhex_api.hpp | 50 +- .../include/hex/api/layout_manager.hpp | 11 + .../include/hex/api/plugin_manager.hpp | 13 +- .../include/hex/api/project_file_manager.hpp | 12 +- lib/libimhex/include/hex/api/task_manager.hpp | 2 +- .../include/hex/api/theme_manager.hpp | 4 +- .../source/api/achievement_manager.cpp | 85 +-- lib/libimhex/source/api/content_registry.cpp | 510 +++++++++--------- lib/libimhex/source/api/imhex_api.cpp | 160 +++--- lib/libimhex/source/api/layout_manager.cpp | 23 + .../source/api/localization_manager.cpp | 8 +- lib/libimhex/source/api/plugin_manager.cpp | 44 +- .../source/api/project_file_manager.cpp | 12 +- lib/libimhex/source/api/task_manager.cpp | 2 +- lib/libimhex/source/api/theme_manager.cpp | 4 +- .../source/subcommands/subcommands.cpp | 8 +- main/gui/CMakeLists.txt | 5 +- main/gui/include/init/run.hpp | 12 + main/gui/source/init/run/common.cpp | 48 ++ main/gui/source/init/run/native.cpp | 46 ++ main/gui/source/init/run/web.cpp | 81 +++ main/gui/source/main.cpp | 154 +----- main/gui/source/window/window.cpp | 48 +- .../include/content/views/view_tools.hpp | 3 +- plugins/builtin/romfs/lang/de_DE.json | 1 + plugins/builtin/romfs/lang/en_US.json | 1 + plugins/builtin/source/content/events.cpp | 2 +- plugins/builtin/source/content/init_tasks.cpp | 4 +- plugins/builtin/source/content/project.cpp | 3 +- plugins/builtin/source/content/providers.cpp | 2 +- .../source/content/settings_entries.cpp | 294 +++++----- plugins/builtin/source/content/ui_items.cpp | 2 +- plugins/builtin/source/content/views.cpp | 16 + .../content/views/view_achievements.cpp | 4 +- .../source/content/views/view_hex_editor.cpp | 2 +- .../source/content/views/view_tools.cpp | 32 +- .../builtin/source/content/welcome_screen.cpp | 2 +- .../source/content/window_decoration.cpp | 2 +- .../source/content/views/view_diff.cpp | 2 +- 43 files changed, 977 insertions(+), 847 deletions(-) create mode 100644 main/gui/include/init/run.hpp create mode 100644 main/gui/source/init/run/common.cpp create mode 100644 main/gui/source/init/run/native.cpp create mode 100644 main/gui/source/init/run/web.cpp diff --git a/dist/web/source/style.css b/dist/web/source/style.css index 05048d6d9..98a4442a3 100644 --- a/dist/web/source/style.css +++ b/dist/web/source/style.css @@ -17,6 +17,7 @@ body { margin-right: auto; display: none; border: 0 none; + image-rendering: smooth; } h1, h2, h5 { diff --git a/dist/web/source/wasm-config.js b/dist/web/source/wasm-config.js index 641584ec2..8da1a88e0 100644 --- a/dist/web/source/wasm-config.js +++ b/dist/web/source/wasm-config.js @@ -2,7 +2,7 @@ let wasmSize = null; // See comment in dist/web/Dockerfile about imhex.wasm.size fetch("imhex.wasm.size").then(async (resp) => { wasmSize = parseInt((await resp.text()).trim()); - console.log(`wasm size was found to be ${wasmSize} bytes`); + console.log(`Real WASM binary size is ${wasmSize} bytes`); }); // Monkeypatch WebAssembly to have a progress bar @@ -49,9 +49,9 @@ function monkeyPatch(progressFun) { monkeyPatch((file, done) => { if (!wasmSize) return; if (done > wasmSize) { - console.log(`Warning: downloaded size ${done} is larger than wasm size ${wasmSize}`); + console.warn(`Downloaded binary size ${done} is larger than expected WASM size ${wasmSize}`); return; - }; + } const percent = ((done / wasmSize) * 100).toFixed(0); const mibNow = (done / 1024**2).toFixed(1); diff --git a/lib/libimhex/include/hex/api/achievement_manager.hpp b/lib/libimhex/include/hex/api/achievement_manager.hpp index 43ef577af..3fb80ce19 100644 --- a/lib/libimhex/include/hex/api/achievement_manager.hpp +++ b/lib/libimhex/include/hex/api/achievement_manager.hpp @@ -331,18 +331,7 @@ namespace hex { static Achievement& addAchievement(auto && ... args) { auto newAchievement = std::make_unique(std::forward(args)...); - const auto &category = newAchievement->getUnlocalizedCategory(); - const auto &name = newAchievement->getUnlocalizedName(); - - auto [categoryIter, categoryInserted] = getAchievements().insert({ category, std::unordered_map>{} }); - auto &[categoryKey, achievements] = *categoryIter; - - auto [achievementIter, achievementInserted] = achievements.insert({ name, std::move(newAchievement) }); - auto &[achievementKey, achievement] = *achievementIter; - - achievementAdded(); - - return *achievement; + return addAchievementImpl(std::move(newAchievement)); } /** @@ -371,7 +360,7 @@ namespace hex { * @brief Returns all registered achievements * @return All achievements */ - static std::unordered_map>>& getAchievements(); + static const std::unordered_map>>& getAchievements(); /** * @brief Returns all achievement start nodes @@ -379,14 +368,14 @@ namespace hex { * @param rebuild Whether to rebuild the list of start nodes * @return All achievement start nodes */ - static std::unordered_map>& getAchievementStartNodes(bool rebuild = true); + static const std::unordered_map>& getAchievementStartNodes(bool rebuild = true); /** * @brief Returns all achievement nodes * @param rebuild Whether to rebuild the list of nodes * @return All achievement nodes */ - static std::unordered_map>& getAchievementNodes(bool rebuild = true); + static const std::unordered_map>& getAchievementNodes(bool rebuild = true); /** * @brief Loads the progress of all achievements from the achievements save file @@ -398,11 +387,6 @@ namespace hex { */ static void storeProgress(); - /** - * @brief Removes all registered achievements from the tree - */ - static void clear(); - /** * @brief Removes all temporary achievements from the tree */ @@ -416,6 +400,8 @@ namespace hex { private: static void achievementAdded(); + + static Achievement& addAchievementImpl(std::unique_ptr &&newAchievement); }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index b6eaaf3f3..174a77cab 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -272,9 +272,9 @@ namespace hex { void store(); void clear(); - std::vector &getSettings(); + const std::vector& getSettings(); nlohmann::json& getSetting(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &defaultValue); - nlohmann::json &getSettingsData(); + const nlohmann::json& getSettingsData(); Widgets::Widget* add(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedSubCategory, const UnlocalizedString &unlocalizedName, std::unique_ptr &&widget); @@ -352,8 +352,8 @@ namespace hex { DisplayCallback displayCallback; }; - std::vector &getEntries(); - std::vector &getHandlers(); + const std::vector& getEntries(); + const std::vector& getHandlers(); } @@ -408,10 +408,10 @@ namespace hex { VisualizerFunctionCallback callback; }; - std::map &getVisualizers(); - std::map &getInlineVisualizers(); - std::map &getPragmas(); - std::vector &getFunctions(); + const std::map& getVisualizers(); + const std::map& getInlineVisualizers(); + const std::map& getPragmas(); + const std::vector& getFunctions(); } @@ -504,7 +504,7 @@ namespace hex { namespace impl { void add(std::unique_ptr &&view); - std::map> &getEntries(); + const std::map>& getEntries(); } @@ -535,12 +535,11 @@ namespace hex { using Callback = std::function; struct Entry { - std::string name; + UnlocalizedString unlocalizedName; Callback function; - bool detached; }; - std::vector &getEntries(); + const std::vector& getEntries(); } @@ -576,7 +575,7 @@ namespace hex { std::optional editingFunction; }; - std::vector &getEntries(); + const std::vector& getEntries(); } @@ -627,7 +626,7 @@ namespace hex { void add(const Entry &entry); - std::vector &getEntries(); + const std::vector& getEntries(); } @@ -670,8 +669,8 @@ namespace hex { namespace impl { - std::map &getLanguages(); - std::map> &getLanguageDefinitions(); + const std::map& getLanguages(); + const std::map>& getLanguageDefinitions(); } @@ -725,14 +724,16 @@ namespace hex { constexpr static auto SeparatorValue = "$SEPARATOR$"; constexpr static auto SubMenuValue = "$SUBMENU$"; - std::multimap &getMainMenuItems(); - std::multimap &getMenuItems(); + const std::multimap& getMainMenuItems(); - std::vector &getWelcomeScreenEntries(); - std::vector &getFooterItems(); - std::vector &getToolbarItems(); - std::vector &getSidebarItems(); - std::vector &getTitleBarButtons(); + const std::multimap& getMenuItems(); + std::multimap& getMenuItemsMutable(); + + const std::vector& getWelcomeScreenEntries(); + const std::vector& getFooterItems(); + const std::vector& getToolbarItems(); + const std::vector& getSidebarItems(); + const std::vector& getTitlebarButtons(); } @@ -901,10 +902,10 @@ namespace hex { void addProviderName(const UnlocalizedString &unlocalizedName); - using ProviderCreationFunction = prv::Provider*(*)(); + using ProviderCreationFunction = std::unique_ptr(*)(); void add(const std::string &typeName, ProviderCreationFunction creationFunction); - std::vector &getEntries(); + const std::vector& getEntries(); } @@ -917,8 +918,8 @@ namespace hex { void add(bool addToList = true) { auto typeName = T().getTypeName(); - impl::add(typeName, [] -> prv::Provider* { - return new T(); + impl::add(typeName, [] -> std::unique_ptr { + return std::make_unique(); }); if (addToList) @@ -938,7 +939,7 @@ namespace hex { Callback callback; }; - std::vector &getEntries(); + const std::vector& getEntries(); } @@ -963,7 +964,7 @@ namespace hex { Callback callback; }; - std::vector &getEntries(); + const std::vector& getEntries(); } @@ -1019,8 +1020,8 @@ namespace hex { void addDataVisualizer(std::shared_ptr &&visualizer); - std::vector> &getVisualizers(); - std::vector> &getMiniMapVisualizers(); + const std::vector>& getVisualizers(); + const std::vector>& getMiniMapVisualizers(); } @@ -1082,7 +1083,7 @@ namespace hex { namespace impl { - std::vector> &getAlgorithms(); + const std::vector>& getAlgorithms(); void addAlgorithm(std::unique_ptr &&hash); @@ -1119,7 +1120,7 @@ namespace hex { [[nodiscard]] Hash *getType() { return m_type; } [[nodiscard]] const Hash *getType() const { return m_type; } - [[nodiscard]] const std::string &getName() const { return m_name; } + [[nodiscard]] const std::string& getName() const { return m_name; } const std::vector& get(const Region& region, prv::Provider *provider) { if (m_cache.empty()) { @@ -1147,7 +1148,7 @@ namespace hex { [[nodiscard]] virtual nlohmann::json store() const = 0; virtual void load(const nlohmann::json &json) = 0; - [[nodiscard]] const UnlocalizedString &getUnlocalizedName() const { + [[nodiscard]] const UnlocalizedString& getUnlocalizedName() const { return m_unlocalizedName; } @@ -1162,7 +1163,7 @@ namespace hex { namespace impl { - std::vector> &getHashes(); + const std::vector>& getHashes(); void add(std::unique_ptr &&hash); @@ -1199,7 +1200,7 @@ namespace hex { namespace impl { using NetworkCallback = std::function; - std::map &getNetworkEndpoints(); + const std::map& getNetworkEndpoints(); } void registerNetworkEndpoint(const std::string &endpoint, const impl::NetworkCallback &callback); @@ -1216,7 +1217,7 @@ namespace hex { bool enabled; }; - std::map &getExperiments(); + const std::map& getExperiments(); } void addExperiment( @@ -1240,7 +1241,7 @@ namespace hex { Callback callback; }; - std::vector& getGenerators(); + const std::vector& getGenerators(); } diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index d85e52363..3ba0b9de6 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -35,8 +35,8 @@ namespace hex { Highlighting() = default; Highlighting(Region region, color_t color); - [[nodiscard]] const Region &getRegion() const { return m_region; } - [[nodiscard]] const color_t &getColor() const { return m_color; } + [[nodiscard]] const Region& getRegion() const { return m_region; } + [[nodiscard]] const color_t& getColor() const { return m_color; } private: Region m_region = {}; @@ -48,9 +48,9 @@ namespace hex { Tooltip() = default; Tooltip(Region region, std::string value, color_t color); - [[nodiscard]] const Region &getRegion() const { return m_region; } - [[nodiscard]] const color_t &getColor() const { return m_color; } - [[nodiscard]] const std::string &getValue() const { return m_value; } + [[nodiscard]] const Region& getRegion() const { return m_region; } + [[nodiscard]] const color_t& getColor() const { return m_color; } + [[nodiscard]] const std::string& getValue() const { return m_value; } private: Region m_region = {}; @@ -70,12 +70,12 @@ namespace hex { using HighlightingFunction = std::function(u64, const u8*, size_t, bool)>; - std::map &getBackgroundHighlights(); - std::map &getBackgroundHighlightingFunctions(); - std::map &getForegroundHighlights(); - std::map &getForegroundHighlightingFunctions(); - std::map &getTooltips(); - std::map &getTooltipFunctions(); + const std::map& getBackgroundHighlights(); + const std::map& getBackgroundHighlightingFunctions(); + const std::map& getForegroundHighlights(); + const std::map& getForegroundHighlightingFunctions(); + const std::map& getTooltips(); + const std::map& getTooltipFunctions(); void setCurrentSelection(const std::optional ®ion); } @@ -279,7 +279,7 @@ namespace hex { * @brief Gets a list of all currently loaded data providers * @return The currently loaded data providers */ - const std::vector &getProviders(); + std::vector getProviders(); /** * @brief Sets the currently selected data provider @@ -323,7 +323,7 @@ namespace hex { * @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation) * @param select Whether to select the provider after adding it */ - void add(prv::Provider *provider, bool skipLoadInterface = false, bool select = true); + void add(std::unique_ptr &&provider, bool skipLoadInterface = false, bool select = true); /** * @brief Creates a new provider and adds it to the list of providers @@ -332,7 +332,7 @@ namespace hex { */ template T> void add(auto &&...args) { - add(new T(std::forward(args)...)); + add(std::make_unique(std::forward(args)...)); } /** @@ -497,7 +497,14 @@ namespace hex { * @brief Gets the init arguments passed to ImHex from the splash screen * @return Init arguments */ - std::map &getInitArguments(); + const std::map& getInitArguments(); + + /** + * @brief Gets a init arguments passed to ImHex from the splash screen + * @param key The key of the init argument + * @return Init argument + */ + std::string getInitArgument(const std::string &key); /** * @brief Sets if ImHex should follow the system theme @@ -516,7 +523,7 @@ namespace hex { * @brief Gets the currently set additional folder paths * @return The currently set additional folder paths */ - std::vector &getAdditionalFolderPaths(); + const std::vector& getAdditionalFolderPaths(); /** * @brief Sets the additional folder paths @@ -529,7 +536,7 @@ namespace hex { * @brief Gets the current GPU vendor * @return The current GPU vendor */ - const std::string &getGPUVendor(); + const std::string& getGPUVendor(); /** * @brief Checks if ImHex is running in portable mode @@ -633,11 +640,12 @@ namespace hex { namespace Messaging { namespace impl { + using MessagingHandler = std::function &)>; - std::map &getHandlers(); - + const std::map& getHandlers(); void runHandler(const std::string &eventName, const std::vector &args); + } /** @@ -661,7 +669,7 @@ namespace hex { namespace impl { - std::vector& getFonts(); + const std::vector& getFonts(); void setCustomFontPath(const std::fs::path &path); void setFontSize(float size); @@ -687,7 +695,7 @@ namespace hex { * @brief Gets the current custom font path * @return The current custom font path */ - std::filesystem::path &getCustomFontPath(); + const std::filesystem::path& getCustomFontPath(); /** * @brief Gets the current font size diff --git a/lib/libimhex/include/hex/api/layout_manager.hpp b/lib/libimhex/include/hex/api/layout_manager.hpp index 78e761a80..68f837df7 100644 --- a/lib/libimhex/include/hex/api/layout_manager.hpp +++ b/lib/libimhex/include/hex/api/layout_manager.hpp @@ -4,6 +4,8 @@ #include +struct ImGuiTextBuffer; + namespace hex { class LayoutManager { @@ -13,6 +15,9 @@ namespace hex { std::fs::path path; }; + using LoadCallback = std::function; + using StoreCallback = std::function; + /** * @brief Save the current layout * @param name Name of the layout @@ -76,6 +81,12 @@ namespace hex { */ static void closeAllViews(); + static void registerLoadCallback(const LoadCallback &callback); + static void registerStoreCallback(const StoreCallback &callback); + + static void onStore(ImGuiTextBuffer *buffer); + static void onLoad(std::string_view line); + private: LayoutManager() = default; }; diff --git a/lib/libimhex/include/hex/api/plugin_manager.hpp b/lib/libimhex/include/hex/api/plugin_manager.hpp index b3d9939d5..a4528436f 100644 --- a/lib/libimhex/include/hex/api/plugin_manager.hpp +++ b/lib/libimhex/include/hex/api/plugin_manager.hpp @@ -6,7 +6,9 @@ #include #include + #include +#include struct ImGuiContext; @@ -109,11 +111,16 @@ namespace hex { static void addPlugin(const std::string &name, PluginFunctions functions); - static std::list &getPlugins(); - static std::vector &getPluginPaths(); - static std::vector &getPluginLoadPaths(); + static const std::list& getPlugins(); + static const std::vector& getPluginPaths(); + static const std::vector& getPluginLoadPaths(); static bool isPluginLoaded(const std::fs::path &path); + + private: + static std::list& getPluginsMutable(); + + static AutoReset> s_pluginPaths, s_pluginLoadPaths; }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/api/project_file_manager.hpp b/lib/libimhex/include/hex/api/project_file_manager.hpp index 2d476db90..614a978f7 100644 --- a/lib/libimhex/include/hex/api/project_file_manager.hpp +++ b/lib/libimhex/include/hex/api/project_file_manager.hpp @@ -93,30 +93,26 @@ namespace hex { * * @param handler The handler to register */ - static void registerHandler(const Handler &handler) { - getHandlers().push_back(handler); - } + static void registerHandler(const Handler &handler); /** * @brief Register a handler for storing and loading per-provider data from a project file * * @param handler The handler to register */ - static void registerPerProviderHandler(const ProviderHandler &handler) { - getProviderHandlers().push_back(handler); - } + static void registerPerProviderHandler(const ProviderHandler &handler); /** * @brief Get the list of registered handlers * @return List of registered handlers */ - static std::vector& getHandlers(); + static const std::vector& getHandlers(); /** * @brief Get the list of registered per-provider handlers * @return List of registered per-provider handlers */ - static std::vector& getProviderHandlers(); + static const std::vector& getProviderHandlers(); private: ProjectFile() = default; diff --git a/lib/libimhex/include/hex/api/task_manager.hpp b/lib/libimhex/include/hex/api/task_manager.hpp index 4afe54a7c..eedf45627 100644 --- a/lib/libimhex/include/hex/api/task_manager.hpp +++ b/lib/libimhex/include/hex/api/task_manager.hpp @@ -176,7 +176,7 @@ namespace hex { static size_t getRunningTaskCount(); static size_t getRunningBackgroundTaskCount(); - static std::list> &getRunningTasks(); + static const std::list>& getRunningTasks(); static void runDeferredCalls(); private: diff --git a/lib/libimhex/include/hex/api/theme_manager.hpp b/lib/libimhex/include/hex/api/theme_manager.hpp index 64413ed24..9d88e6c85 100644 --- a/lib/libimhex/include/hex/api/theme_manager.hpp +++ b/lib/libimhex/include/hex/api/theme_manager.hpp @@ -78,8 +78,8 @@ namespace hex { StyleMap styleMap; }; - static std::map& getThemeHandlers(); - static std::map& getStyleHandlers(); + static const std::map& getThemeHandlers(); + static const std::map& getStyleHandlers(); private: ThemeManager() = default; diff --git a/lib/libimhex/source/api/achievement_manager.cpp b/lib/libimhex/source/api/achievement_manager.cpp index 464fc8c9d..431a7338b 100644 --- a/lib/libimhex/source/api/achievement_manager.cpp +++ b/lib/libimhex/source/api/achievement_manager.cpp @@ -7,41 +7,43 @@ namespace hex { - std::unordered_map>> &AchievementManager::getAchievements() { - static AutoReset>>> achievements; - - return achievements; + static AutoReset>>> s_achievements; + const std::unordered_map>> &AchievementManager::getAchievements() { + return *s_achievements; } - std::unordered_map>& AchievementManager::getAchievementNodes(bool rebuild) { - static AutoReset>> nodeCategoryStorage; + static AutoReset>> s_nodeCategoryStorage; + std::unordered_map>& getAchievementNodesMutable(bool rebuild) { + if (!s_nodeCategoryStorage->empty() || !rebuild) + return s_nodeCategoryStorage; - if (!nodeCategoryStorage->empty() || !rebuild) - return nodeCategoryStorage; - - nodeCategoryStorage->clear(); + s_nodeCategoryStorage->clear(); // Add all achievements to the node storage - for (auto &[categoryName, achievements] : getAchievements()) { - auto &nodes = (*nodeCategoryStorage)[categoryName]; + for (auto &[categoryName, achievements] : AchievementManager::getAchievements()) { + auto &nodes = (*s_nodeCategoryStorage)[categoryName]; for (auto &[achievementName, achievement] : achievements) { nodes.emplace_back(achievement.get()); } } - return nodeCategoryStorage; + return s_nodeCategoryStorage; } - std::unordered_map>& AchievementManager::getAchievementStartNodes(bool rebuild) { - static AutoReset>> startNodes; + const std::unordered_map>& AchievementManager::getAchievementNodes(bool rebuild) { + return getAchievementNodesMutable(rebuild); + } - if (!startNodes->empty() || !rebuild) - return startNodes; + static AutoReset>> s_startNodes; + const std::unordered_map>& AchievementManager::getAchievementStartNodes(bool rebuild) { - auto &nodeCategoryStorage = getAchievementNodes(); + if (!s_startNodes->empty() || !rebuild) + return s_startNodes; - startNodes->clear(); + auto &nodeCategoryStorage = getAchievementNodesMutable(rebuild); + + s_startNodes->clear(); // Add all parents and children to the nodes for (auto &[categoryName, achievements] : nodeCategoryStorage) { @@ -76,17 +78,17 @@ namespace hex { for (auto &[categoryName, achievements] : nodeCategoryStorage) { for (auto &achievementNode : achievements) { if (!achievementNode.hasParents()) { - (*startNodes)[categoryName].emplace_back(&achievementNode); + (*s_startNodes)[categoryName].emplace_back(&achievementNode); } for (const auto &parent : achievementNode.parents) { if (parent->achievement->getUnlocalizedCategory() != achievementNode.achievement->getUnlocalizedCategory()) - (*startNodes)[categoryName].emplace_back(&achievementNode); + (*s_startNodes)[categoryName].emplace_back(&achievementNode); } } } - return startNodes; + return s_startNodes; } void AchievementManager::unlockAchievement(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName) { @@ -104,8 +106,11 @@ namespace hex { return; } - const auto &nodes = getAchievementNodes()[categoryName]; - for (const auto &node : nodes) { + const auto &nodes = getAchievementNodes(); + if (!nodes.contains(categoryName)) + return; + + for (const auto &node : nodes.at(categoryName)) { auto &achievement = node.achievement; if (achievement->getUnlocalizedCategory() != unlocalizedCategory) { @@ -134,14 +139,8 @@ namespace hex { } } - void AchievementManager::clear() { - getAchievements().clear(); - getAchievementStartNodes(false).clear(); - getAchievementNodes(false).clear(); - } - void AchievementManager::clearTemporary() { - auto &categories = getAchievements(); + auto &categories = *s_achievements; for (auto &[categoryName, achievements] : categories) { std::erase_if(achievements, [](auto &data) { auto &[achievementName, achievement] = data; @@ -154,8 +153,8 @@ namespace hex { return achievements.empty(); }); - getAchievementStartNodes(false).clear(); - getAchievementNodes(false).clear(); + s_startNodes->clear(); + s_nodeCategoryStorage->clear(); } std::pair AchievementManager::getProgress() { @@ -175,10 +174,26 @@ namespace hex { } void AchievementManager::achievementAdded() { - getAchievementStartNodes(false).clear(); - getAchievementNodes(false).clear(); + s_startNodes->clear(); + s_nodeCategoryStorage->clear(); } + Achievement &AchievementManager::addAchievementImpl(std::unique_ptr &&newAchievement) { + const auto &category = newAchievement->getUnlocalizedCategory(); + const auto &name = newAchievement->getUnlocalizedName(); + + auto [categoryIter, categoryInserted] = s_achievements->insert({ category, std::unordered_map>{} }); + auto &[categoryKey, achievements] = *categoryIter; + + auto [achievementIter, achievementInserted] = achievements.insert({ name, std::move(newAchievement) }); + auto &[achievementKey, achievement] = *achievementIter; + + achievementAdded(); + + return *achievement; + } + + constexpr static auto AchievementsFile = "achievements.json"; void AchievementManager::loadProgress() { diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index 4e35f5405..9efcdcfb6 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -28,8 +28,13 @@ namespace hex { namespace impl { + static AutoReset s_settings; + const nlohmann::json& getSettingsData() { + return s_settings; + } + nlohmann::json& getSetting(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &defaultValue) { - auto &settings = getSettingsData(); + auto &settings = *s_settings; if (!settings.contains(unlocalizedCategory)) settings[unlocalizedCategory] = {}; @@ -40,12 +45,6 @@ namespace hex { return settings[unlocalizedCategory][unlocalizedName]; } - nlohmann::json &getSettingsData() { - static AutoReset settings; - - return settings; - } - #if defined(OS_WEB) void load() { char *data = (char *) MAIN_THREAD_EM_ASM_INT({ @@ -56,12 +55,12 @@ namespace hex { if (data == nullptr) { store(); } else { - getSettingsData() = nlohmann::json::parse(data); + s_settings = nlohmann::json::parse(data); } } void store() { - auto data = getSettingsData().dump(); + auto data = s_settings->dump(); MAIN_THREAD_EM_ASM({ localStorage.setItem("config", UTF8ToString($0)); }, data.c_str()); @@ -72,14 +71,16 @@ namespace hex { localStorage.removeItem("config"); }); } + #else + void load() { bool loaded = false; for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) { wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read); if (file.isValid()) { - getSettingsData() = nlohmann::json::parse(file.readString()); + s_settings = nlohmann::json::parse(file.readString()); loaded = true; break; } @@ -139,14 +140,13 @@ namespace hex { return foundEntry; } - std::vector &getSettings() { - static AutoReset> categories; - - return categories; + static AutoReset> s_categories; + const std::vector& getSettings() { + return *s_categories; } Widgets::Widget* add(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedSubCategory, const UnlocalizedString &unlocalizedName, std::unique_ptr &&widget) { - const auto category = insertOrGetEntry(getSettings(), unlocalizedCategory); + const auto category = insertOrGetEntry(*s_categories, unlocalizedCategory); const auto subCategory = insertOrGetEntry(category->subCategories, unlocalizedSubCategory); const auto entry = insertOrGetEntry(subCategory->entries, unlocalizedName); @@ -163,7 +163,7 @@ namespace hex { } void setCategoryDescription(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedDescription) { - const auto category = insertOrGetEntry(impl::getSettings(), unlocalizedCategory); + const auto category = insertOrGetEntry(*impl::s_categories, unlocalizedCategory); category->unlocalizedDescription = unlocalizedDescription; } @@ -386,32 +386,30 @@ namespace hex { namespace ContentRegistry::CommandPaletteCommands { + namespace impl { + + static AutoReset> s_entries; + const std::vector& getEntries() { + return *s_entries; + } + + static AutoReset> s_handlers; + const std::vector& getHandlers() { + return *s_handlers; + } + + } + void add(Type type, const std::string &command, const UnlocalizedString &unlocalizedDescription, const impl::DisplayCallback &displayCallback, const impl::ExecuteCallback &executeCallback) { log::debug("Registered new command palette command: {}", command); - impl::getEntries().push_back(impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback }); + impl::s_entries->push_back(impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback }); } void addHandler(Type type, const std::string &command, const impl::QueryCallback &queryCallback, const impl::DisplayCallback &displayCallback) { log::debug("Registered new command palette command handler: {}", command); - impl::getHandlers().push_back(impl::Handler { type, command, queryCallback, displayCallback }); - } - - namespace impl { - - std::vector &getEntries() { - static AutoReset> commands; - - return commands; - } - - std::vector &getHandlers() { - static AutoReset> commands; - - return commands; - } - + impl::s_handlers->push_back(impl::Handler { type, command, queryCallback, displayCallback }); } } @@ -419,6 +417,30 @@ namespace hex { namespace ContentRegistry::PatternLanguage { + namespace impl { + + static AutoReset> s_visualizers; + const std::map& getVisualizers() { + return *s_visualizers; + } + + static AutoReset> s_inlineVisualizers; + const std::map& getInlineVisualizers() { + return *s_inlineVisualizers; + } + + static AutoReset> s_pragmas; + const std::map& getPragmas() { + return *s_pragmas; + } + + static AutoReset> s_functions; + const std::vector& getFunctions() { + return *s_functions; + } + + } + static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) { std::string functionName; for (auto &scope : ns) @@ -476,13 +498,13 @@ namespace hex { void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) { log::debug("Registered new pattern language pragma: {}", name); - impl::getPragmas()[name] = handler; + (*impl::s_pragmas)[name] = handler; } void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) { log::debug("Registered new pattern language function: {}", getFunctionName(ns, name)); - impl::getFunctions().push_back({ + impl::s_functions->push_back({ ns, name, parameterCount, func, false @@ -492,7 +514,7 @@ namespace hex { void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) { log::debug("Registered new dangerous pattern language function: {}", getFunctionName(ns, name)); - impl::getFunctions().push_back({ + impl::s_functions->push_back({ ns, name, parameterCount, func, true @@ -502,44 +524,14 @@ namespace hex { void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) { log::debug("Registered new pattern visualizer function: {}", name); - impl::getVisualizers()[name] = impl::Visualizer { parameterCount, function }; + (*impl::s_visualizers)[name] = impl::Visualizer { parameterCount, function }; } void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) { log::debug("Registered new inline pattern visualizer function: {}", name); - impl::getInlineVisualizers()[name] = impl::Visualizer { parameterCount, function }; + (*impl::s_inlineVisualizers)[name] = impl::Visualizer { parameterCount, function }; } - - namespace impl { - - std::map &getVisualizers() { - static AutoReset> visualizers; - - return visualizers; - } - - std::map &getInlineVisualizers() { - static AutoReset> visualizers; - - return visualizers; - } - - std::map &getPragmas() { - static AutoReset> pragmas; - - return pragmas; - } - - std::vector &getFunctions() { - static AutoReset> functions; - - return functions; - } - - } - - } @@ -547,22 +539,21 @@ namespace hex { namespace impl { - std::map> &getEntries() { - static AutoReset>> views; - - return views; + static AutoReset>> s_views; + const std::map>& getEntries() { + return *s_views; } - } - - void impl::add(std::unique_ptr &&view) { + void add(std::unique_ptr &&view) { log::debug("Registered new view: {}", view->getUnlocalizedName().get()); - getEntries().insert({ view->getUnlocalizedName(), std::move(view) }); + s_views->insert({ view->getUnlocalizedName(), std::move(view) }); + } + } View* getViewByName(const UnlocalizedString &unlocalizedName) { - auto &views = impl::getEntries(); + auto &views = *impl::s_views; if (views.contains(unlocalizedName)) return views[unlocalizedName].get(); @@ -574,77 +565,87 @@ namespace hex { namespace ContentRegistry::Tools { + namespace impl { + + static AutoReset> s_tools; + const std::vector& getEntries() { + return *s_tools; + } + + } + void add(const UnlocalizedString &unlocalizedName, const impl::Callback &function) { log::debug("Registered new tool: {}", unlocalizedName.get()); - impl::getEntries().emplace_back(impl::Entry { unlocalizedName, function, false }); - } - - namespace impl { - - std::vector &getEntries() { - static AutoReset> tools; - - return tools; - } - + impl::s_tools->emplace_back(impl::Entry { unlocalizedName, function }); } } namespace ContentRegistry::DataInspector { + namespace impl { + + static AutoReset> s_entries; + const std::vector& getEntries() { + return *s_entries; + } + + } + void add(const UnlocalizedString &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional editingFunction) { log::debug("Registered new data inspector format: {}", unlocalizedName.get()); - impl::getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) }); + impl::s_entries->push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) }); } void add(const UnlocalizedString &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional editingFunction) { log::debug("Registered new data inspector format: {}", unlocalizedName.get()); - impl::getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) }); + impl::s_entries->push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) }); } - namespace impl { - - std::vector &getEntries() { - static AutoReset> entries; - - return entries; - } - - } - - } namespace ContentRegistry::DataProcessorNode { - void impl::add(const Entry &entry) { - log::debug("Registered new data processor node type: [{}]: {}", entry.unlocalizedCategory.get(), entry.unlocalizedName.get()); + namespace impl { + + static AutoReset> s_nodes; + const std::vector& getEntries() { + return *s_nodes; + } + + void add(const Entry &entry) { + log::debug("Registered new data processor node type: [{}]: {}", entry.unlocalizedCategory.get(), entry.unlocalizedName.get()); + + s_nodes->push_back(entry); + } - getEntries().push_back(entry); } void addSeparator() { - impl::getEntries().push_back({ "", "", [] { return nullptr; } }); - } - - namespace impl { - - std::vector &getEntries() { - static AutoReset> nodes; - - return nodes; - } - + impl::s_nodes->push_back({ "", "", [] { return nullptr; } }); } } namespace ContentRegistry::Language { + namespace impl { + + static AutoReset> s_languages; + const std::map& getLanguages() { + return *s_languages; + } + + static AutoReset>> s_definitions; + const std::map>& getLanguageDefinitions() { + return *s_definitions; + } + + } + void addLocalization(const nlohmann::json &data) { if (!data.is_object()) return; @@ -671,7 +672,7 @@ namespace hex { LocalizationManager::impl::setFallbackLanguage(code.get()); } - impl::getLanguages().insert({ code.get(), hex::format("{} ({})", language.get(), country.get()) }); + impl::s_languages->insert({ code.get(), hex::format("{} ({})", language.get(), country.get()) }); std::map translationDefinitions; for (auto &[key, value] : translations.items()) { @@ -683,34 +684,60 @@ namespace hex { translationDefinitions[key] = value.get(); } - impl::getLanguageDefinitions()[code.get()].emplace_back(std::move(translationDefinitions)); + (*impl::s_definitions)[code.get()].emplace_back(std::move(translationDefinitions)); } - namespace impl { - - std::map &getLanguages() { - static AutoReset> languages; - - return languages; - } - - std::map> &getLanguageDefinitions() { - static AutoReset>> definitions; - - return definitions; - } - - } - - } namespace ContentRegistry::Interface { + namespace impl { + + static AutoReset> s_mainMenuItems; + const std::multimap& getMainMenuItems() { + return *s_mainMenuItems; + } + + static AutoReset> s_menuItems; + const std::multimap& getMenuItems() { + return *s_menuItems; + } + + std::multimap& getMenuItemsMutable() { + return *s_menuItems; + } + + static AutoReset> s_welcomeScreenEntries; + const std::vector& getWelcomeScreenEntries() { + return *s_welcomeScreenEntries; + } + + static AutoReset> s_footerItems; + const std::vector& getFooterItems() { + return *s_footerItems; + } + + static AutoReset> s_toolbarItems; + const std::vector& getToolbarItems() { + return *s_toolbarItems; + } + + static AutoReset> s_sidebarItems; + const std::vector& getSidebarItems() { + return *s_sidebarItems; + } + + static AutoReset> s_titlebarButtons; + const std::vector& getTitlebarButtons() { + return *s_titlebarButtons; + } + + } + void registerMainMenuItem(const UnlocalizedString &unlocalizedName, u32 priority) { log::debug("Registered new main menu item: {}", unlocalizedName.get()); - impl::getMainMenuItems().insert({ priority, { unlocalizedName } }); + impl::s_mainMenuItems->insert({ priority, { unlocalizedName } }); } void addMenuItem(const std::vector &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, const impl::SelectedCallback &selectedCallback, View *view) { @@ -732,7 +759,7 @@ namespace hex { if (coloredIcon.color == 0x00) coloredIcon.color = ImGuiCustomCol_ToolbarGray; - impl::getMenuItems().insert({ + impl::s_menuItems->insert({ priority, impl::MenuItem { unlocalizedMainMenuNames, coloredIcon, std::make_unique(shortcut), view, function, enabledCallback, selectedCallback, -1 } }); @@ -752,28 +779,28 @@ namespace hex { log::debug("Added new menu item sub menu to menu {} with priority {}", unlocalizedMainMenuNames[0].get(), priority); unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue); - impl::getMenuItems().insert({ + impl::s_menuItems->insert({ priority, impl::MenuItem { unlocalizedMainMenuNames, icon, std::make_unique(), nullptr, function, enabledCallback, []{ return false; }, -1 } }); } void addMenuItemSeparator(std::vector unlocalizedMainMenuNames, u32 priority) { unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue); - impl::getMenuItems().insert({ + impl::s_menuItems->insert({ priority, impl::MenuItem { unlocalizedMainMenuNames, "", std::make_unique(), nullptr, []{}, []{ return true; }, []{ return false; }, -1 } }); } void addWelcomeScreenEntry(const impl::DrawCallback &function) { - impl::getWelcomeScreenEntries().push_back(function); + impl::s_welcomeScreenEntries->push_back(function); } void addFooterItem(const impl::DrawCallback &function) { - impl::getFooterItems().push_back(function); + impl::s_footerItems->push_back(function); } void addToolbarItem(const impl::DrawCallback &function) { - impl::getToolbarItems().push_back(function); + impl::s_toolbarItems->push_back(function); } void addMenuItemToToolbar(const UnlocalizedString& unlocalizedName, ImGuiCustomCol color) { @@ -781,7 +808,7 @@ namespace hex { return a.second.toolbarIndex < b.second.toolbarIndex; })->second.toolbarIndex; - for (auto &[priority, menuItem] : impl::getMenuItems()) { + for (auto &[priority, menuItem] : *impl::s_menuItems) { if (menuItem.unlocalizedNames.back() == unlocalizedName) { menuItem.toolbarIndex = maxIndex + 1; menuItem.icon.color = color; @@ -792,52 +819,11 @@ namespace hex { void addSidebarItem(const std::string &icon, const impl::DrawCallback &function, const impl::EnabledCallback &enabledCallback) { - impl::getSidebarItems().push_back({ icon, function, enabledCallback }); + impl::s_sidebarItems->push_back({ icon, function, enabledCallback }); } void addTitleBarButton(const std::string &icon, const UnlocalizedString &unlocalizedTooltip, const impl::ClickCallback &function) { - impl::getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function }); - } - - namespace impl { - - std::multimap &getMainMenuItems() { - static AutoReset> items; - - return items; - } - std::multimap &getMenuItems() { - static AutoReset> items; - - return items; - } - - std::vector &getWelcomeScreenEntries() { - static AutoReset> entries; - - return entries; - } - std::vector &getFooterItems() { - static AutoReset> items; - - return items; - } - std::vector &getToolbarItems() { - static AutoReset> items; - - return items; - } - std::vector &getSidebarItems() { - static AutoReset> items; - - return items; - } - std::vector &getTitleBarButtons() { - static AutoReset> buttons; - - return buttons; - } - + impl::s_titlebarButtons->push_back({ icon, unlocalizedTooltip, function }); } } @@ -850,25 +836,24 @@ namespace hex { (void)RequestCreateProvider::subscribe([expectedName = typeName, creationFunction](const std::string &name, bool skipLoadInterface, bool selectProvider, prv::Provider **provider) { if (name != expectedName) return; - prv::Provider *newProvider = creationFunction(); + auto newProvider = creationFunction(); - ImHexApi::Provider::add(newProvider, skipLoadInterface, selectProvider); - - if (provider != nullptr) - *provider = newProvider; + if (provider != nullptr) { + *provider = newProvider.get(); + ImHexApi::Provider::add(std::move(newProvider), skipLoadInterface, selectProvider); + } }); } - std::vector &getEntries() { - static AutoReset> providerNames; - - return providerNames; + static AutoReset> s_providerNames; + const std::vector& getEntries() { + return *s_providerNames; } void addProviderName(const UnlocalizedString &unlocalizedName) { log::debug("Registered new provider: {}", unlocalizedName.get()); - getEntries().push_back(unlocalizedName); + s_providerNames->push_back(unlocalizedName); } } @@ -878,41 +863,39 @@ namespace hex { namespace ContentRegistry::DataFormatter { + namespace impl { + + static AutoReset> s_entries; + const std::vector& getEntries() { + return *s_entries; + } + + } + void add(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) { log::debug("Registered new data formatter: {}", unlocalizedName.get()); - impl::getEntries().push_back({ unlocalizedName, callback }); - } - - namespace impl { - - std::vector &getEntries() { - static AutoReset> entries; - - return entries; - } - + impl::s_entries->push_back({ unlocalizedName, callback }); } } namespace ContentRegistry::FileHandler { + namespace impl { + + static AutoReset> s_entries; + const std::vector& getEntries() { + return *s_entries; + } + + } + void add(const std::vector &extensions, const impl::Callback &callback) { for (const auto &extension : extensions) log::debug("Registered new data handler for extensions: {}", extension); - impl::getEntries().push_back({ extensions, callback }); - } - - namespace impl { - - std::vector &getEntries() { - static AutoReset> entries; - - return entries; - } - + impl::s_entries->push_back({ extensions, callback }); } } @@ -985,23 +968,21 @@ namespace hex { namespace impl { + static AutoReset>> s_visualizers; + const std::vector>& getVisualizers() { + return *s_visualizers; + } + + static AutoReset>> s_miniMapVisualizers; + const std::vector>& getMiniMapVisualizers() { + return *s_miniMapVisualizers; + } + void addDataVisualizer(std::shared_ptr &&visualizer) { - getVisualizers().emplace_back(std::move(visualizer)); + s_visualizers->emplace_back(std::move(visualizer)); } - std::vector> &getVisualizers() { - static AutoReset>> visualizers; - - return visualizers; - } - - std::vector> &getMiniMapVisualizers() { - static AutoReset>> visualizers; - - return visualizers; - } - } std::shared_ptr getVisualizerByName(const UnlocalizedString &unlocalizedName) { @@ -1014,7 +995,7 @@ namespace hex { } void addMiniMapVisualizer(UnlocalizedString unlocalizedName, MiniMapVisualizer::Callback callback) { - impl::getMiniMapVisualizers().emplace_back(std::make_shared(std::move(unlocalizedName), std::move(callback))); + impl::s_miniMapVisualizers->emplace_back(std::make_shared(std::move(unlocalizedName), std::move(callback))); } } @@ -1023,14 +1004,13 @@ namespace hex { namespace impl { - std::vector>& getAlgorithms() { - static AutoReset>> algorithms; - - return algorithms; + static AutoReset>> s_algorithms; + const std::vector>& getAlgorithms() { + return *s_algorithms; } void addAlgorithm(std::unique_ptr &&hash) { - getAlgorithms().emplace_back(std::move(hash)); + s_algorithms->emplace_back(std::move(hash)); } } @@ -1041,14 +1021,13 @@ namespace hex { namespace impl { - std::vector> &getHashes() { - static AutoReset>> hashes; - - return hashes; + static AutoReset>> s_hashes; + const std::vector>& getHashes() { + return *s_hashes; } void add(std::unique_ptr &&hash) { - getHashes().emplace_back(std::move(hash)); + s_hashes->emplace_back(std::move(hash)); } } @@ -1073,11 +1052,11 @@ namespace hex { Service& operator=(const Service&) = delete; Service& operator=(Service &&) = default; - [[nodiscard]] const std::string &getName() const { + [[nodiscard]] const std::string& getName() const { return m_name; } - [[nodiscard]] const std::jthread &getThread() const { + [[nodiscard]] const std::jthread& getThread() const { return m_thread; } @@ -1086,15 +1065,13 @@ namespace hex { std::jthread m_thread; }; - std::vector &getServices() { - static AutoReset> services; - - return services; + static AutoReset> s_services; + const std::vector& getServices() { + return *s_services; } void stopServices() { - auto &services = getServices(); - services.clear(); + s_services->clear(); } } @@ -1102,7 +1079,7 @@ namespace hex { void registerService(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) { log::debug("Registered new background service: {}", unlocalizedName.get()); - impl::getServices().emplace_back( + impl::s_services->emplace_back( unlocalizedName, std::jthread([callback = auto(callback)](const std::stop_token &stopToken){ while (!stopToken.stop_requested()) { @@ -1119,10 +1096,9 @@ namespace hex { namespace impl { - std::map &getNetworkEndpoints() { - static AutoReset> endpoints; - - return endpoints; + static AutoReset> s_endpoints; + const std::map& getNetworkEndpoints() { + return *s_endpoints; } } @@ -1130,7 +1106,7 @@ namespace hex { void registerNetworkEndpoint(const std::string &endpoint, const impl::NetworkCallback &callback) { log::debug("Registered new network endpoint: {}", endpoint); - impl::getNetworkEndpoints().insert({ endpoint, callback }); + impl::s_endpoints->insert({ endpoint, callback }); } } @@ -1139,16 +1115,15 @@ namespace hex { namespace impl { - std::map &getExperiments() { - static AutoReset> experiments; - - return experiments; + static AutoReset> s_experiments; + const std::map& getExperiments() { + return *s_experiments; } } void addExperiment(const std::string &experimentName, const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) { - auto &experiments = impl::getExperiments(); + auto &experiments = *impl::s_experiments; if (experiments.contains(experimentName)) { log::error("Experiment with name '{}' already exists!", experimentName); @@ -1163,7 +1138,7 @@ namespace hex { } void enableExperiement(const std::string &experimentName, bool enabled) { - auto &experiments = impl::getExperiments(); + auto &experiments = *impl::s_experiments; if (!experiments.contains(experimentName)) { log::error("Experiment with name '{}' does not exist!", experimentName); @@ -1174,7 +1149,7 @@ namespace hex { } [[nodiscard]] bool isExperimentEnabled(const std::string &experimentName) { - auto &experiments = impl::getExperiments(); + auto &experiments = *impl::s_experiments; if (!experiments.contains(experimentName)) { log::error("Experiment with name '{}' does not exist!", experimentName); @@ -1190,16 +1165,15 @@ namespace hex { namespace impl { - std::vector &getGenerators() { - static AutoReset> generators; - - return generators; + static AutoReset> s_generators; + const std::vector& getGenerators() { + return *s_generators; } } void addReportProvider(impl::Callback callback) { - impl::getGenerators().push_back(impl::ReportGenerator { std::move(callback ) }); + impl::s_generators->push_back(impl::ReportGenerator { std::move(callback ) }); } } diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index 09390d788..b75aefa5f 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -37,34 +37,34 @@ namespace hex { namespace impl { - std::map &getBackgroundHighlights() { - static AutoReset> backgroundHighlights; - return backgroundHighlights; + static AutoReset> s_backgroundHighlights; + const std::map& getBackgroundHighlights() { + return *s_backgroundHighlights; } - std::map &getBackgroundHighlightingFunctions() { - static AutoReset> backgroundHighlightingFunctions; - return backgroundHighlightingFunctions; + static AutoReset> s_backgroundHighlightingFunctions; + const std::map& getBackgroundHighlightingFunctions() { + return *s_backgroundHighlightingFunctions; } - std::map &getForegroundHighlights() { - static AutoReset> foregroundHighlights; - return foregroundHighlights; + static AutoReset> s_foregroundHighlights; + const std::map& getForegroundHighlights() { + return *s_foregroundHighlights; } - std::map &getForegroundHighlightingFunctions() { - static AutoReset> foregroundHighlightingFunctions; - return foregroundHighlightingFunctions; + static AutoReset> s_foregroundHighlightingFunctions; + const std::map& getForegroundHighlightingFunctions() { + return *s_foregroundHighlightingFunctions; } - std::map &getTooltips() { - static AutoReset> tooltips; - return tooltips; + static AutoReset> s_tooltips; + const std::map& getTooltips() { + return *s_tooltips; } - std::map &getTooltipFunctions() { - static AutoReset> tooltipFunctions; - return tooltipFunctions; + static AutoReset> s_tooltipFunctions; + const std::map& getTooltipFunctions() { + return *s_tooltipFunctions; } static AutoReset> s_currentSelection; @@ -79,8 +79,8 @@ namespace hex { id++; - impl::getBackgroundHighlights().insert({ - id, Highlighting {region, color} + impl::s_backgroundHighlights->insert({ + id, Highlighting { region, color } }); EventHighlightingChanged::post(); @@ -89,7 +89,7 @@ namespace hex { } void removeBackgroundHighlight(u32 id) { - impl::getBackgroundHighlights().erase(id); + impl::s_backgroundHighlights->erase(id); EventHighlightingChanged::post(); } @@ -99,7 +99,7 @@ namespace hex { id++; - impl::getBackgroundHighlightingFunctions().insert({ id, function }); + impl::s_backgroundHighlightingFunctions->insert({ id, function }); EventHighlightingChanged::post(); @@ -107,7 +107,7 @@ namespace hex { } void removeBackgroundHighlightingProvider(u32 id) { - impl::getBackgroundHighlightingFunctions().erase(id); + impl::s_backgroundHighlightingFunctions->erase(id); EventHighlightingChanged::post(); } @@ -117,8 +117,8 @@ namespace hex { id++; - impl::getForegroundHighlights().insert({ - id, Highlighting {region, color} + impl::s_foregroundHighlights->insert({ + id, Highlighting { region, color } }); EventHighlightingChanged::post(); @@ -127,7 +127,7 @@ namespace hex { } void removeForegroundHighlight(u32 id) { - impl::getForegroundHighlights().erase(id); + impl::s_foregroundHighlights->erase(id); EventHighlightingChanged::post(); } @@ -137,7 +137,7 @@ namespace hex { id++; - impl::getForegroundHighlightingFunctions().insert({ id, function }); + impl::s_foregroundHighlightingFunctions->insert({ id, function }); EventHighlightingChanged::post(); @@ -145,7 +145,7 @@ namespace hex { } void removeForegroundHighlightingProvider(u32 id) { - impl::getForegroundHighlightingFunctions().erase(id); + impl::s_foregroundHighlightingFunctions->erase(id); EventHighlightingChanged::post(); } @@ -153,25 +153,25 @@ namespace hex { static u32 tooltipId = 0; u32 addTooltip(Region region, std::string value, color_t color) { tooltipId++; - impl::getTooltips().insert({ tooltipId, { region, std::move(value), color } }); + impl::s_tooltips->insert({ tooltipId, { region, std::move(value), color } }); return tooltipId; } void removeTooltip(u32 id) { - impl::getTooltips().erase(id); + impl::s_tooltips->erase(id); } static u32 tooltipFunctionId; u32 addTooltipProvider(TooltipFunction function) { tooltipFunctionId++; - impl::getTooltipFunctions().insert({ tooltipFunctionId, std::move(function) }); + impl::s_tooltipFunctions->insert({ tooltipFunctionId, std::move(function) }); return tooltipFunctionId; } void removeTooltipProvider(u32 id) { - impl::getTooltipFunctions().erase(id); + impl::s_tooltipFunctions->erase(id); } bool isSelectionValid() { @@ -228,7 +228,7 @@ namespace hex { namespace ImHexApi::Provider { static i64 s_currentProvider = -1; - static AutoReset> s_providers; + static AutoReset>> s_providers; namespace impl { @@ -247,11 +247,16 @@ namespace hex { if (!ImHexApi::Provider::isValid()) return nullptr; - return (*s_providers)[s_currentProvider]; + return (*s_providers)[s_currentProvider].get(); } - const std::vector &getProviders() { - return s_providers; + std::vector getProviders() { + std::vector result; + result.reserve(s_providers->size()); + for (const auto &provider : *s_providers) + result.push_back(provider.get()); + + return result; } void setCurrentProvider(u32 index) { @@ -288,15 +293,15 @@ namespace hex { }); } - void add(prv::Provider *provider, bool skipLoadInterface, bool select) { + void add(std::unique_ptr &&provider, bool skipLoadInterface, bool select) { if (TaskManager::getRunningTaskCount() > 0) return; if (skipLoadInterface) provider->skipLoadInterface(); - s_providers->push_back(provider); - EventProviderCreated::post(provider); + EventProviderCreated::post(provider.get()); + s_providers->emplace_back(std::move(provider)); if (select || s_providers->size() == 1) setCurrentProvider(s_providers->size() - 1); @@ -318,7 +323,10 @@ namespace hex { return; } - const auto it = std::ranges::find(*s_providers, provider); + const auto it = std::ranges::find_if(*s_providers, [provider](const auto &p) { + return p.get() == provider; + }); + if (it == s_providers->end()) return; @@ -328,7 +336,7 @@ namespace hex { setCurrentProvider(0); if (s_providers->size() > 1) - EventProviderChanged::post(s_providers->at(0), s_providers->at(1)); + EventProviderChanged::post(s_providers->at(0).get(), s_providers->at(1).get()); } else if (std::distance(s_providers->begin(), it) == s_currentProvider) { // If the current provider is being closed, select the one that's before it @@ -337,7 +345,9 @@ namespace hex { else { // If any other provider is being closed, find the current provider in the list again and select it again const auto currentProvider = get(); - const auto currentIt = std::ranges::find(*s_providers, currentProvider); + const auto currentIt = std::ranges::find_if(*s_providers, [currentProvider](const auto &p) { + return p.get() == currentProvider; + }); if (currentIt != s_providers->end()) { auto newIndex = std::distance(s_providers->begin(), currentIt); @@ -353,21 +363,20 @@ namespace hex { } } - s_providers->erase(it); - if (s_currentProvider >= i64(s_providers->size())) - setCurrentProvider(0); - - if (s_providers->empty()) - EventProviderChanged::post(provider, nullptr); - provider->close(); EventProviderClosed::post(provider); RequestUpdateWindowTitle::post(); - TaskManager::runWhenTasksFinished([provider] { + TaskManager::runWhenTasksFinished([it, provider] { EventProviderDeleted::post(provider); std::erase(impl::s_closingProviders, provider); - delete provider; + + s_providers->erase(it); + if (s_currentProvider >= i64(s_providers->size())) + setCurrentProvider(0); + + if (s_providers->empty()) + EventProviderChanged::post(provider, nullptr); }); } @@ -449,11 +458,12 @@ namespace hex { s_portableVersion = enabled; } + static AutoReset> s_initArguments; void addInitArgument(const std::string &key, const std::string &value) { static std::mutex initArgumentsMutex; std::scoped_lock lock(initArgumentsMutex); - getInitArguments()[key] = value; + (*s_initArguments)[key] = value; } static double s_lastFrameTime; @@ -538,12 +548,18 @@ namespace hex { return impl::s_initialWindowProperties; } - std::map &getInitArguments() { - static AutoReset> initArgs; - - return initArgs; + const std::map& getInitArguments() { + return *impl::s_initArguments; } + std::string getInitArgument(const std::string &key) { + if (impl::s_initArguments->contains(key)) + return impl::s_initArguments->at(key); + else + return ""; + } + + static bool s_systemThemeDetection; void enableSystemThemeDetection(bool enabled) { @@ -557,13 +573,13 @@ namespace hex { } - std::vector &getAdditionalFolderPaths() { - static AutoReset> additionalFolderPaths; - return additionalFolderPaths; + static AutoReset> s_additionalFolderPaths; + const std::vector& getAdditionalFolderPaths() { + return *s_additionalFolderPaths; } void setAdditionalFolderPaths(const std::vector &paths) { - getAdditionalFolderPaths() = paths; + s_additionalFolderPaths = paths; } @@ -742,14 +758,13 @@ namespace hex { namespace impl { - std::map &getHandlers() { - static AutoReset> handlers; - - return handlers; + static AutoReset> s_handlers; + const std::map& getHandlers() { + return *s_handlers; } void runHandler(const std::string &eventName, const std::vector &args) { - const auto& handlers = impl::getHandlers(); + const auto& handlers = getHandlers(); const auto matchHandler = handlers.find(eventName); if (matchHandler == handlers.end()) { @@ -765,7 +780,7 @@ namespace hex { void registerHandler(const std::string &eventName, const impl::MessagingHandler &handler) { log::debug("Registered new forward event handler: {}", eventName); - impl::getHandlers().insert({ eventName, handler }); + impl::s_handlers->insert({ eventName, handler }); } } @@ -774,10 +789,9 @@ namespace hex { namespace impl { - std::vector& getFonts() { - static AutoReset> fonts; - - return fonts; + static AutoReset> s_fonts; + const std::vector& getFonts() { + return *s_fonts; } static AutoReset s_customFontPath; @@ -845,7 +859,7 @@ namespace hex { return; } - impl::getFonts().emplace_back(Font { + impl::s_fonts->emplace_back(Font { wolv::util::toUTF8String(path.filename()), fontFile.readVector(), glyphRanges, @@ -855,7 +869,7 @@ namespace hex { } void loadFont(const std::string &name, const std::span &data, const std::vector &glyphRanges, Offset offset, u32 flags) { - impl::getFonts().emplace_back(Font { + impl::s_fonts->emplace_back(Font { name, { data.begin(), data.end() }, glyphRanges, @@ -864,7 +878,7 @@ namespace hex { }); } - std::fs::path &getCustomFontPath() { + const std::fs::path& getCustomFontPath() { return impl::s_customFontPath; } diff --git a/lib/libimhex/source/api/layout_manager.cpp b/lib/libimhex/source/api/layout_manager.cpp index 1d44848d4..eb15b8171 100644 --- a/lib/libimhex/source/api/layout_manager.cpp +++ b/lib/libimhex/source/api/layout_manager.cpp @@ -17,6 +17,9 @@ namespace hex { AutoReset> s_layoutStringToLoad; AutoReset> s_layouts; + AutoReset> s_loadCallbacks; + AutoReset> s_storeCallbacks; + bool s_layoutLocked = false; } @@ -130,4 +133,24 @@ namespace hex { s_layoutLocked = locked; } + void LayoutManager::registerLoadCallback(const LoadCallback &callback) { + s_loadCallbacks->push_back(callback); + } + + void LayoutManager::registerStoreCallback(const StoreCallback &callback) { + s_storeCallbacks->push_back(callback); + } + + void LayoutManager::onLoad(std::string_view line) { + for (const auto &callback : *s_loadCallbacks) + callback(line); + } + + void LayoutManager::onStore(ImGuiTextBuffer *buffer) { + for (const auto &callback : *s_storeCallbacks) + callback(buffer); + } + + + } diff --git a/lib/libimhex/source/api/localization_manager.cpp b/lib/libimhex/source/api/localization_manager.cpp index 01cfc6450..2d9b05764 100644 --- a/lib/libimhex/source/api/localization_manager.cpp +++ b/lib/libimhex/source/api/localization_manager.cpp @@ -49,12 +49,12 @@ namespace hex { s_currStrings->clear(); - for (auto &definition : definitions[language]) + for (const auto &definition : definitions.at(language)) s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end()); const auto& fallbackLanguage = getFallbackLanguage(); - if (language != fallbackLanguage) { - for (auto &definition : definitions[fallbackLanguage]) + if (language != fallbackLanguage && definitions.contains(fallbackLanguage)) { + for (const auto &definition : definitions.at(fallbackLanguage)) s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end()); } @@ -70,7 +70,7 @@ namespace hex { return ""; std::string localizedString; - for (const auto &definition : languageDefinitions[language]) { + for (const auto &definition : languageDefinitions.at(language)) { if (definition.getEntries().contains(unlocalizedString)) { localizedString = definition.getEntries().at(unlocalizedString); break; diff --git a/lib/libimhex/source/api/plugin_manager.cpp b/lib/libimhex/source/api/plugin_manager.cpp index 01d626277..545420aef 100644 --- a/lib/libimhex/source/api/plugin_manager.cpp +++ b/lib/libimhex/source/api/plugin_manager.cpp @@ -228,9 +228,6 @@ namespace hex { return m_addedManually; } - - - void *Plugin::getPluginFunction(const std::string &symbol) const { #if defined(OS_WINDOWS) return reinterpret_cast(GetProcAddress(HMODULE(m_handle), symbol.c_str())); @@ -239,8 +236,11 @@ namespace hex { #endif } + + AutoReset> PluginManager::s_pluginPaths, PluginManager::s_pluginLoadPaths; + void PluginManager::addLoadPath(const std::fs::path& path) { - getPluginLoadPaths().emplace_back(path); + s_pluginLoadPaths->emplace_back(path); } @@ -257,13 +257,13 @@ namespace hex { if (!wolv::io::fs::exists(pluginFolder)) return false; - getPluginPaths().push_back(pluginFolder); + s_pluginPaths->push_back(pluginFolder); // Load library plugins first for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) { if (pluginPath.is_regular_file() && pluginPath.path().extension() == ".hexpluglib") { if (!isPluginLoaded(pluginPath.path())) { - getPlugins().emplace_back(pluginPath.path()); + getPluginsMutable().emplace_back(pluginPath.path()); } } } @@ -272,12 +272,12 @@ namespace hex { for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) { if (pluginPath.is_regular_file() && pluginPath.path().extension() == ".hexplug") { if (!isPluginLoaded(pluginPath.path())) { - getPlugins().emplace_back(pluginPath.path()); + getPluginsMutable().emplace_back(pluginPath.path()); } } } - std::erase_if(getPlugins(), [](const Plugin &plugin) { + std::erase_if(getPluginsMutable(), [](const Plugin &plugin) { return !plugin.isValid(); }); @@ -292,10 +292,10 @@ namespace hex { } void PluginManager::unload() { - getPluginPaths().clear(); + s_pluginPaths->clear(); // Unload plugins in reverse order - auto &plugins = getPlugins(); + auto &plugins = getPluginsMutable(); std::list savedPlugins; while (!plugins.empty()) { @@ -304,29 +304,29 @@ namespace hex { plugins.pop_back(); } - getPlugins() = std::move(savedPlugins); + getPluginsMutable() = std::move(savedPlugins); } void PluginManager::addPlugin(const std::string &name, hex::PluginFunctions functions) { - getPlugins().emplace_back(name, functions); + getPluginsMutable().emplace_back(name, functions); } - std::list &PluginManager::getPlugins() { - static std::list plugins; + const std::list& PluginManager::getPlugins() { + return getPluginsMutable(); + } + + std::list& PluginManager::getPluginsMutable() { + static std::list plugins; return plugins; } - std::vector &PluginManager::getPluginPaths() { - static AutoReset> pluginPaths; - - return pluginPaths; + const std::vector& PluginManager::getPluginPaths() { + return s_pluginPaths; } - std::vector &PluginManager::getPluginLoadPaths() { - static AutoReset> pluginPaths; - - return pluginPaths; + const std::vector& PluginManager::getPluginLoadPaths() { + return s_pluginLoadPaths; } bool PluginManager::isPluginLoaded(const std::fs::path &path) { diff --git a/lib/libimhex/source/api/project_file_manager.cpp b/lib/libimhex/source/api/project_file_manager.cpp index 70eeacbb3..6ef6c2bae 100644 --- a/lib/libimhex/source/api/project_file_manager.cpp +++ b/lib/libimhex/source/api/project_file_manager.cpp @@ -51,11 +51,19 @@ namespace hex { s_currProjectPath = path; } - std::vector &ProjectFile::getHandlers() { + void ProjectFile::registerHandler(const Handler &handler) { + s_handlers->push_back(handler); + } + + void ProjectFile::registerPerProviderHandler(const ProviderHandler &handler) { + s_providerHandlers->push_back(handler); + } + + const std::vector& ProjectFile::getHandlers() { return s_handlers; } - std::vector &ProjectFile::getProviderHandlers() { + const std::vector& ProjectFile::getProviderHandlers() { return s_providerHandlers; } diff --git a/lib/libimhex/source/api/task_manager.cpp b/lib/libimhex/source/api/task_manager.cpp index 41c344bfd..a9c5ba5c2 100644 --- a/lib/libimhex/source/api/task_manager.cpp +++ b/lib/libimhex/source/api/task_manager.cpp @@ -335,7 +335,7 @@ namespace hex { } - std::list> &TaskManager::getRunningTasks() { + const std::list>& TaskManager::getRunningTasks() { return s_tasks; } diff --git a/lib/libimhex/source/api/theme_manager.cpp b/lib/libimhex/source/api/theme_manager.cpp index cc6cac653..35029fb83 100644 --- a/lib/libimhex/source/api/theme_manager.cpp +++ b/lib/libimhex/source/api/theme_manager.cpp @@ -219,11 +219,11 @@ namespace hex { } - std::map &ThemeManager::getThemeHandlers() { + const std::map &ThemeManager::getThemeHandlers() { return s_themeHandlers; } - std::map &ThemeManager::getStyleHandlers() { + const std::map &ThemeManager::getStyleHandlers() { return s_styleHandlers; } diff --git a/lib/libimhex/source/subcommands/subcommands.cpp b/lib/libimhex/source/subcommands/subcommands.cpp index f7809f410..2336222cc 100644 --- a/lib/libimhex/source/subcommands/subcommands.cpp +++ b/lib/libimhex/source/subcommands/subcommands.cpp @@ -107,17 +107,17 @@ namespace hex::subcommands { void registerSubCommand(const std::string &cmdName, const ForwardCommandHandler &handler) { log::debug("Registered new forward command handler: {}", cmdName); - ImHexApi::Messaging::impl::getHandlers().insert({ hex::format("command/{}", cmdName), [handler](const std::vector &eventData){ - std::string str(reinterpret_cast(eventData.data()), eventData.size()); + ImHexApi::Messaging::registerHandler(hex::format("command/{}", cmdName), [handler](const std::vector &eventData){ + std::string string(reinterpret_cast(eventData.data()), eventData.size()); std::vector args; - for (const auto &arg_view : std::views::split(str, '\0')) { + for (const auto &arg_view : std::views::split(string, char(0x00))) { std::string arg(arg_view.data(), arg_view.size()); args.push_back(arg); } handler(args); - }}); + }); } } diff --git a/main/gui/CMakeLists.txt b/main/gui/CMakeLists.txt index 1640cb24a..d46759e06 100644 --- a/main/gui/CMakeLists.txt +++ b/main/gui/CMakeLists.txt @@ -17,10 +17,13 @@ add_executable(main ${APPLICATION_TYPE} source/messaging/win.cpp source/messaging/web.cpp - source/init/splash_window.cpp source/init/tasks.cpp + source/init/run/common.cpp + source/init/run/native.cpp + source/init/run/web.cpp + ${IMHEX_ICON} ) diff --git a/main/gui/include/init/run.hpp b/main/gui/include/init/run.hpp new file mode 100644 index 000000000..b6dcbc62c --- /dev/null +++ b/main/gui/include/init/run.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace hex::init { + + void handleFileOpenRequest(); + + std::unique_ptr initializeImHex(); + void deinitializeImHex(); + +} diff --git a/main/gui/source/init/run/common.cpp b/main/gui/source/init/run/common.cpp new file mode 100644 index 000000000..e08de028e --- /dev/null +++ b/main/gui/source/init/run/common.cpp @@ -0,0 +1,48 @@ +#include +#include +#include + +#include +#include + +namespace hex::init { + + /** + * @brief Handles a file open request by opening the file specified by OS-specific means + */ + void handleFileOpenRequest() { + if (auto path = hex::getInitialFilePath(); path.has_value()) { + RequestOpenFile::post(path.value()); + } + } + + /** + * @brief Displays ImHex's splash screen and runs all initialization tasks. The splash screen will be displayed until all tasks have finished. + */ + [[maybe_unused]] + std::unique_ptr initializeImHex() { + auto splashWindow = std::make_unique(); + + log::info("Using '{}' GPU", ImHexApi::System::getGPUVendor()); + + // Add initialization tasks to run + TaskManager::init(); + for (const auto &[name, task, async] : init::getInitTasks()) + splashWindow->addStartupTask(name, task, async); + + splashWindow->startStartupTasks(); + + return splashWindow; + } + + + /** + * @brief Deinitializes ImHex by running all exit tasks + */ + void deinitializeImHex() { + // Run exit tasks + init::runExitTasks(); + + } + +} \ No newline at end of file diff --git a/main/gui/source/init/run/native.cpp b/main/gui/source/init/run/native.cpp new file mode 100644 index 000000000..eb261a3fd --- /dev/null +++ b/main/gui/source/init/run/native.cpp @@ -0,0 +1,46 @@ +#if !defined(OS_WEB) + + #include + #include + + #include + #include + + namespace hex::init { + + int runImHex() { + + bool shouldRestart = false; + do { + // Register an event handler that will make ImHex restart when requested + shouldRestart = false; + RequestRestartImHex::subscribe([&] { + shouldRestart = true; + }); + + { + auto splashWindow = initializeImHex(); + // Draw the splash window while tasks are running + if (!splashWindow->loop()) + ImHexApi::System::impl::addInitArgument("tasks-failed"); + + handleFileOpenRequest(); + } + + // Clean up everything after the main window is closed + ON_SCOPE_EXIT { + deinitializeImHex(); + }; + + // Main window + Window window; + window.loop(); + + } while (shouldRestart); + + return EXIT_SUCCESS; + } + + } + +#endif \ No newline at end of file diff --git a/main/gui/source/init/run/web.cpp b/main/gui/source/init/run/web.cpp new file mode 100644 index 000000000..41c7c5241 --- /dev/null +++ b/main/gui/source/init/run/web.cpp @@ -0,0 +1,81 @@ +#if defined(OS_WEB) + + #include + #include + + #include + #include + #include + + #include + + #include + + namespace hex::init { + + void saveFsData() { + EM_ASM({ + FS.syncfs(function (err) { + if (!err) + return; + alert("Failed to save permanent file system: "+err); + }); + }); + } + + int runImHex() { + static std::unique_ptr splashWindow; + splashWindow = initializeImHex(); + + RequestRestartImHex::subscribe([&] { + MAIN_THREAD_EM_ASM({ + location.reload(); + }); + }); + + // Draw the splash window while tasks are running + emscripten_set_main_loop_arg([](void *arg) { + auto &splashWindow = *reinterpret_cast*>(arg); + + FrameResult frameResult = splashWindow->fullFrame(); + if (frameResult == FrameResult::Success) { + handleFileOpenRequest(); + + // Clean up everything after the main window is closed + emscripten_set_beforeunload_callback(nullptr, [](int eventType, const void *reserved, void *userData) { + hex::unused(eventType, reserved, userData); + + emscripten_cancel_main_loop(); + + try { + saveFsData(); + deinitializeImHex(); + return ""; + } catch (const std::exception &e) { + static std::string message; + message = hex::format("Failed to deinitialize ImHex!\nThis is just a message warning you of this, the application has already closed, you probably can't do anything about it.\n\nError: {}", e.what()); + return message.c_str(); + } + }); + + // Delete splash window (do it before creating the main window so glfw destroys the window) + splashWindow.reset(); + + emscripten_cancel_main_loop(); + + // Main window + static std::optional window; + window.emplace(); + + emscripten_set_main_loop([]() { + window->fullFrame(); + }, 60, 0); + } + }, &splashWindow, 60, 0); + + return -1; + } + + } + +#endif \ No newline at end of file diff --git a/main/gui/source/main.cpp b/main/gui/source/main.cpp index 5d5ec70b1..15f34f855 100644 --- a/main/gui/source/main.cpp +++ b/main/gui/source/main.cpp @@ -7,7 +7,6 @@ #include "messaging.hpp" #include "init/splash_window.hpp" -#include "init/tasks.hpp" #include #include @@ -16,20 +15,17 @@ #include "hex/subcommands/subcommands.hpp" #include -#include -#include #if defined(OS_WINDOWS) #include #include #include -#elif defined(OS_WEB) - #include - #include #endif using namespace hex; +namespace hex::init { int runImHex(); } + namespace { /** @@ -95,150 +91,6 @@ namespace { return false; } - /** - * @brief Displays ImHex's splash screen and runs all initialization tasks. The splash screen will be displayed until all tasks have finished. - */ - [[maybe_unused]] - void initializeImHex() { - init::WindowSplash splashWindow; - - log::info("Using '{}' GPU", ImHexApi::System::getGPUVendor()); - - // Add initialization tasks to run - TaskManager::init(); - for (const auto &[name, task, async] : init::getInitTasks()) - splashWindow.addStartupTask(name, task, async); - - splashWindow.startStartupTasks(); - - // Draw the splash window while tasks are running - if (!splashWindow.loop()) - ImHexApi::System::impl::addInitArgument("tasks-failed"); - } - - - /** - * @brief Deinitializes ImHex by running all exit tasks - */ - void deinitializeImHex() { - // Run exit tasks - init::runExitTasks(); - - } - - /** - * @brief Handles a file open request by opening the file specified by OS-specific means - */ - void handleFileOpenRequest() { - if (auto path = hex::getInitialFilePath(); path.has_value()) { - RequestOpenFile::post(path.value()); - } - } - - - #if defined(OS_WEB) - - using namespace hex::init; - - void saveFsData() { - EM_ASM({ - FS.syncfs(function (err) { - if (!err) - return; - alert("Failed to save permanent file system: "+err); - }); - }); - } - - int runImHex() { - auto splashWindow = new WindowSplash(); - - log::info("Using '{}' GPU", ImHexApi::System::getGPUVendor()); - - // Add initialization tasks to run - TaskManager::init(); - for (const auto &[name, task, async] : init::getInitTasks()) - splashWindow->addStartupTask(name, task, async); - - splashWindow->startStartupTasks(); - - RequestRestartImHex::subscribe([&] { - MAIN_THREAD_EM_ASM({ - location.reload(); - }); - }); - - // Draw the splash window while tasks are running - emscripten_set_main_loop_arg([](void *arg) { - auto splashWindow = reinterpret_cast(arg); - - FrameResult frameResult = splashWindow->fullFrame(); - if (frameResult == FrameResult::Success) { - handleFileOpenRequest(); - - // Clean up everything after the main window is closed - emscripten_set_beforeunload_callback(nullptr, [](int eventType, const void *reserved, void *userData) { - hex::unused(eventType, reserved, userData); - - try { - saveFsData(); - deinitializeImHex(); - return ""; - } catch (const std::exception &ex) { - std::string *msg = new std::string("Failed to deinitialize ImHex. This is just a message warning you of this, the application has already closed, you probably can't do anything about it. Message: "); - msg->append(std::string(ex.what())); - log::fatal("{}", *msg); - return msg->c_str(); - } - }); - - // Delete splash window (do it before creating the main window so glfw destroys the window) - delete splashWindow; - - emscripten_cancel_main_loop(); - - // Main window - static Window window; - emscripten_set_main_loop([]() { - window.fullFrame(); - }, 60, 0); - } - }, splashWindow, 60, 0); - - return -1; - } - - #else - - int runImHex() { - - bool shouldRestart = false; - do { - // Register an event handler that will make ImHex restart when requested - shouldRestart = false; - RequestRestartImHex::subscribe([&] { - shouldRestart = true; - }); - - initializeImHex(); - handleFileOpenRequest(); - - // Clean up everything after the main window is closed - ON_SCOPE_EXIT { - deinitializeImHex(); - }; - - // Main window - Window window; - window.loop(); - - } while (shouldRestart); - - return EXIT_SUCCESS; - } - - #endif - } /** @@ -262,5 +114,5 @@ int main(int argc, char **argv) { ImHexApi::System::impl::setPortableVersion(isPortableVersion()); - return runImHex(); + return init::runImHex(); } diff --git a/main/gui/source/window/window.cpp b/main/gui/source/window/window.cpp index 87654aea3..0a91e48bc 100644 --- a/main/gui/source/window/window.cpp +++ b/main/gui/source/window/window.cpp @@ -106,6 +106,17 @@ namespace hex { m_popupsToOpen.push_back(name); }); + + LayoutManager::registerLoadCallback([this](std::string_view line) { + int width = 0, height = 0; + sscanf(line.data(), "MainWindowSize=%d,%d", &width, &height); + + if (width > 0 && height > 0) { + TaskManager::doLater([width, height, this]{ + glfwSetWindowSize(m_window, width, height); + }); + } + }); } void Window::fullFrame() { @@ -840,39 +851,14 @@ namespace hex { handler.ReadOpenFn = [](ImGuiContext *ctx, ImGuiSettingsHandler *, const char *) -> void* { return ctx; }; - handler.ReadLineFn = [](ImGuiContext *, ImGuiSettingsHandler *handler, void *, const char *line) { - auto window = static_cast(handler->UserData); - - for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) { - std::string format = view->getUnlocalizedName().get() + "=%d"; - sscanf(line, format.c_str(), &view->getWindowOpenState()); - } - for (auto &[name, function, detached] : ContentRegistry::Tools::impl::getEntries()) { - std::string format = name + "=%d"; - sscanf(line, format.c_str(), &detached); - } - - int width = 0, height = 0; - sscanf(line, "MainWindowSize=%d,%d", &width, &height); - - if (width > 0 && height > 0) { - TaskManager::doLater([width, height, window]{ - glfwSetWindowSize(window->m_window, width, height); - }); - } + handler.ReadLineFn = [](ImGuiContext *, ImGuiSettingsHandler *, void *, const char *line) { + LayoutManager::onLoad(line); }; - handler.WriteAllFn = [](ImGuiContext *, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buf) { - buf->appendf("[%s][General]\n", handler->TypeName); - - for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) { - buf->appendf("%s=%d\n", name.c_str(), view->getWindowOpenState()); - } - for (auto &[name, function, detached] : ContentRegistry::Tools::impl::getEntries()) { - buf->appendf("%s=%d\n", name.c_str(), detached); - } - - buf->append("\n"); + handler.WriteAllFn = [](ImGuiContext *, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buffer) { + buffer->appendf("[%s][General]\n", handler->TypeName); + LayoutManager::onStore(buffer); + buffer->append("\n"); }; handler.UserData = this; diff --git a/plugins/builtin/include/content/views/view_tools.hpp b/plugins/builtin/include/content/views/view_tools.hpp index 4963d0895..1e9c91950 100644 --- a/plugins/builtin/include/content/views/view_tools.hpp +++ b/plugins/builtin/include/content/views/view_tools.hpp @@ -16,9 +16,10 @@ namespace hex::plugin::builtin { void drawAlwaysVisibleContent() override; private: - std::vector::iterator m_dragStartIterator; + std::vector::const_iterator m_dragStartIterator; std::map m_windowHeights; + std::map m_detachedTools; }; } \ No newline at end of file diff --git a/plugins/builtin/romfs/lang/de_DE.json b/plugins/builtin/romfs/lang/de_DE.json index 335fdeef1..7bb7568a5 100644 --- a/plugins/builtin/romfs/lang/de_DE.json +++ b/plugins/builtin/romfs/lang/de_DE.json @@ -483,6 +483,7 @@ "hex.builtin.setting.imhex.recent_files": "Zuletzt geƶffnete Dateien", "hex.builtin.setting.interface": "Aussehen", "hex.builtin.setting.interface.color": "Farbdesign", + "hex.builtin.setting.interface.crisp_scaling": "Gestochen scharfe Skallierung aktivieren", "hex.builtin.setting.interface.fps": "FPS Limit", "hex.builtin.setting.interface.fps.native": "Nativ", "hex.builtin.setting.interface.fps.unlocked": "Unbegrenzt", diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 940a3eed3..9991b5fbd 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -470,6 +470,7 @@ "hex.builtin.setting.interface": "Interface", "hex.builtin.setting.interface.always_show_provider_tabs": "Always show Provider Tabs", "hex.builtin.setting.interface.color": "Color theme", + "hex.builtin.setting.interface.crisp_scaling": "Enable crisp scaling", "hex.builtin.setting.interface.fps": "FPS Limit", "hex.builtin.setting.interface.fps.unlocked": "Unlocked", "hex.builtin.setting.interface.fps.native": "Native", diff --git a/plugins/builtin/source/content/events.cpp b/plugins/builtin/source/content/events.cpp index ee171a6de..daea52f48 100644 --- a/plugins/builtin/source/content/events.cpp +++ b/plugins/builtin/source/content/events.cpp @@ -47,7 +47,7 @@ namespace hex::plugin::builtin { ui::PopupQuestion::open("hex.builtin.popup.exit_application.desc"_lang, [] { imhexClosing = true; - for (const auto &provider : auto(ImHexApi::Provider::getProviders())) + for (const auto &provider : ImHexApi::Provider::getProviders()) ImHexApi::Provider::remove(provider); }, [] { } diff --git a/plugins/builtin/source/content/init_tasks.cpp b/plugins/builtin/source/content/init_tasks.cpp index 33a22dac3..50bb0605f 100644 --- a/plugins/builtin/source/content/init_tasks.cpp +++ b/plugins/builtin/source/content/init_tasks.cpp @@ -290,7 +290,7 @@ namespace hex::plugin::builtin { queryRange.push_back(0x00); // Build the font atlas with the query range - auto newFont = atlas.AddFontFromMemoryTTF(font.fontData.data(), int(font.fontData.size()), 0, &cfg, queryRange.Data); + auto newFont = atlas.AddFontFromMemoryTTF(const_cast(font.fontData.data()), int(font.fontData.size()), 0, &cfg, queryRange.Data); atlas.Build(); return newFont->Descent; @@ -300,7 +300,7 @@ namespace hex::plugin::builtin { std::memset(cfg.Name, 0x00, sizeof(cfg.Name)); std::strncpy(cfg.Name, font.name.c_str(), sizeof(cfg.Name) - 1); cfg.GlyphOffset = { font.offset.x, font.offset.y - defaultFont->Descent + descent }; - fonts->AddFontFromMemoryTTF(font.fontData.data(), int(font.fontData.size()), 0, &cfg, ranges.back().Data); + fonts->AddFontFromMemoryTTF(const_cast(font.fontData.data()), int(font.fontData.size()), 0, &cfg, ranges.back().Data); } cfg.FontBuilderFlags = startFlags; diff --git a/plugins/builtin/source/content/project.cpp b/plugins/builtin/source/content/project.cpp index 1a9ef242e..5e6b2231e 100644 --- a/plugins/builtin/source/content/project.cpp +++ b/plugins/builtin/source/content/project.cpp @@ -57,8 +57,7 @@ namespace hex::plugin::builtin { } } - auto providers = auto(ImHexApi::Provider::getProviders()); - for (const auto &provider : providers) { + for (const auto &provider : ImHexApi::Provider::getProviders()) { ImHexApi::Provider::remove(provider); } diff --git a/plugins/builtin/source/content/providers.cpp b/plugins/builtin/source/content/providers.cpp index 4eb2266ba..8a59ad955 100644 --- a/plugins/builtin/source/content/providers.cpp +++ b/plugins/builtin/source/content/providers.cpp @@ -61,7 +61,7 @@ namespace hex::plugin::builtin { task->interrupt(); TaskManager::runWhenTasksFinished([]{ - for (auto provider : ImHexApi::Provider::getProviders()) + for (const auto &provider : ImHexApi::Provider::getProviders()) ImHexApi::Provider::remove(provider, true); }); } diff --git a/plugins/builtin/source/content/settings_entries.cpp b/plugins/builtin/source/content/settings_entries.cpp index 592a17712..25ae3bd69 100644 --- a/plugins/builtin/source/content/settings_entries.cpp +++ b/plugins/builtin/source/content/settings_entries.cpp @@ -443,7 +443,7 @@ namespace hex::plugin::builtin { // Find all menu items that are in the toolbar and sort them by their toolbar index std::set toolbarItems; - for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) { + for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItemsMutable()) { if (menuItem.toolbarIndex == -1) continue; @@ -580,10 +580,10 @@ namespace hex::plugin::builtin { if (toolbarItems.empty()) return; - for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) + for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItemsMutable()) menuItem.toolbarIndex = -1; - for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) { + for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItemsMutable()) { for (const auto &[index, value] : toolbarItems) { const auto &[name, color] = value; if (menuItem.unlocalizedNames.back().get() == name) { @@ -604,184 +604,208 @@ namespace hex::plugin::builtin { } void registerSettings() { - - /* General */ - namespace Widgets = ContentRegistry::Settings::Widgets; - ContentRegistry::Settings::add("hex.builtin.setting.general", "", "hex.builtin.setting.general.show_tips", false); - ContentRegistry::Settings::add("hex.builtin.setting.general", "", "hex.builtin.setting.general.save_recent_providers", true); - ContentRegistry::Settings::add("hex.builtin.setting.general", "", "hex.builtin.setting.general.auto_backup_time"); - ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.patterns", "hex.builtin.setting.general.auto_load_patterns", true); - ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.patterns", "hex.builtin.setting.general.sync_pattern_source", false); - ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.network_interface", false); + /* General */ + { - #if !defined(OS_WEB) - ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.server_contact"); - ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.upload_crash_logs", true); - #endif + ContentRegistry::Settings::add("hex.builtin.setting.general", "", "hex.builtin.setting.general.show_tips", false); + ContentRegistry::Settings::add("hex.builtin.setting.general", "", "hex.builtin.setting.general.save_recent_providers", true); + ContentRegistry::Settings::add("hex.builtin.setting.general", "", "hex.builtin.setting.general.auto_backup_time"); + ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.patterns", "hex.builtin.setting.general.auto_load_patterns", true); + ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.patterns", "hex.builtin.setting.general.sync_pattern_source", false); + ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.network_interface", false); - /* Interface */ - - auto themeNames = ThemeManager::getThemeNames(); - std::vector themeJsons = { }; - for (const auto &themeName : themeNames) - themeJsons.emplace_back(themeName); - - themeNames.emplace(themeNames.begin(), ThemeManager::NativeTheme); - themeJsons.emplace(themeJsons.begin(), ThemeManager::NativeTheme); - - ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.style", "hex.builtin.setting.interface.color", - themeNames, - themeJsons, - "Dark").setChangedCallback([](auto &widget) { - auto dropDown = static_cast(&widget); - - if (dropDown->getValue() == ThemeManager::NativeTheme) - ImHexApi::System::enableSystemThemeDetection(true); - else { - ImHexApi::System::enableSystemThemeDetection(false); - ThemeManager::changeTheme(dropDown->getValue()); - } - }); - - ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.style", "hex.builtin.setting.interface.scaling_factor").requiresRestart(); - - ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.style", "hex.builtin.setting.interface.pattern_data_row_bg", false); - ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.style", "hex.builtin.setting.interface.always_show_provider_tabs", false); - - std::vector languageNames; - std::vector languageCodes; - - for (auto &[languageCode, languageName] : LocalizationManager::getSupportedLanguages()) { - languageNames.emplace_back(languageName); - languageCodes.emplace_back(languageCode); + #if !defined(OS_WEB) + ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.server_contact"); + ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.upload_crash_logs", true); + #endif } - ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.language", "hex.builtin.setting.interface.language", languageNames, languageCodes, "en-US"); + /* Interface */ + { + auto themeNames = ThemeManager::getThemeNames(); + std::vector themeJsons = { }; + for (const auto &themeName : themeNames) + themeJsons.emplace_back(themeName); - ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.language", "hex.builtin.setting.interface.wiki_explain_language", "en"); - ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.fps"); + themeNames.emplace(themeNames.begin(), ThemeManager::NativeTheme); + themeJsons.emplace(themeJsons.begin(), ThemeManager::NativeTheme); - #if defined (OS_LINUX) - constexpr static auto MultiWindowSupportEnabledDefault = 0; - #else - constexpr static auto MultiWindowSupportEnabledDefault = 1; - #endif + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.style", "hex.builtin.setting.interface.color", + themeNames, + themeJsons, + "Dark").setChangedCallback([](auto &widget) { + auto dropDown = static_cast(&widget); - ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.multi_windows", MultiWindowSupportEnabledDefault).requiresRestart(); - ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.restore_window_pos", false); + if (dropDown->getValue() == ThemeManager::NativeTheme) + ImHexApi::System::enableSystemThemeDetection(true); + else { + ImHexApi::System::enableSystemThemeDetection(false); + ThemeManager::changeTheme(dropDown->getValue()); + } + }); - ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.highlight_color", ImColor(0x80, 0x80, 0xC0, 0x60)); - ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.sync_scrolling", false); - ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.byte_padding", 0, 0, 50); - ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.char_padding", 0, 0, 50); + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.style", "hex.builtin.setting.interface.scaling_factor").requiresRestart(); + #if defined (OS_WEB) + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.style", "hex.builtin.setting.interface.crisp_scaling", false) + .setChangedCallback([](Widgets::Widget &widget) { + auto checkBox = static_cast(&widget); + + EM_ASM({ + var canvas = document.getElementById('canvas'); + if ($0) + canvas.style.imageRendering = 'pixelated'; + else + canvas.style.imageRendering = 'smooth'; + }, checkBox->isChecked()); + }); + #endif + + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.style", "hex.builtin.setting.interface.pattern_data_row_bg", false); + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.style", "hex.builtin.setting.interface.always_show_provider_tabs", false); + + std::vector languageNames; + std::vector languageCodes; + + for (auto &[languageCode, languageName] : LocalizationManager::getSupportedLanguages()) { + languageNames.emplace_back(languageName); + languageCodes.emplace_back(languageCode); + } + + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.language", "hex.builtin.setting.interface.language", languageNames, languageCodes, "en-US"); + + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.language", "hex.builtin.setting.interface.wiki_explain_language", "en"); + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.fps"); + + #if defined (OS_LINUX) + constexpr static auto MultiWindowSupportEnabledDefault = 0; + #else + constexpr static auto MultiWindowSupportEnabledDefault = 1; + #endif + + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.multi_windows", MultiWindowSupportEnabledDefault).requiresRestart(); + ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.window", "hex.builtin.setting.interface.restore_window_pos", false); + + ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.highlight_color", ImColor(0x80, 0x80, 0xC0, 0x60)); + ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.sync_scrolling", false); + ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.byte_padding", 0, 0, 50); + ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "", "hex.builtin.setting.hex_editor.char_padding", 0, 0, 50); + } /* Fonts */ + { - ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.glyphs", "hex.builtin.setting.font.load_all_unicode_chars", false) - .requiresRestart(); + ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.glyphs", "hex.builtin.setting.font.load_all_unicode_chars", false) + .requiresRestart(); - auto customFontEnabledSetting = ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.custom_font_enable", false).requiresRestart(); + auto customFontEnabledSetting = ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.custom_font_enable", false).requiresRestart(); - const auto customFontsEnabled = [customFontEnabledSetting] { - auto &customFontsEnabled = static_cast(customFontEnabledSetting.getWidget()); + const auto customFontsEnabled = [customFontEnabledSetting] { + auto &customFontsEnabled = static_cast(customFontEnabledSetting.getWidget()); - return customFontsEnabled.isChecked(); - }; + return customFontsEnabled.isChecked(); + }; - auto customFontPathSetting = ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_path") - .requiresRestart() - .setEnabledCallback(customFontsEnabled); + auto customFontPathSetting = ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_path") + .requiresRestart() + .setEnabledCallback(customFontsEnabled); - const auto customFontSettingsEnabled = [customFontEnabledSetting, customFontPathSetting] { - auto &customFontsEnabled = static_cast(customFontEnabledSetting.getWidget()); - auto &fontPath = static_cast(customFontPathSetting.getWidget()); + const auto customFontSettingsEnabled = [customFontEnabledSetting, customFontPathSetting] { + auto &customFontsEnabled = static_cast(customFontEnabledSetting.getWidget()); + auto &fontPath = static_cast(customFontPathSetting.getWidget()); - return customFontsEnabled.isChecked() && !fontPath.getPath().empty(); - }; + return customFontsEnabled.isChecked() && !fontPath.getPath().empty(); + }; - ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.custom_font_info") - .setEnabledCallback(customFontsEnabled); - - - ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_size", 13, 0, 100) - .requiresRestart() - .setEnabledCallback(customFontSettingsEnabled); - ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_bold", false) - .requiresRestart() - .setEnabledCallback(customFontSettingsEnabled); - ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_italic", false) - .requiresRestart() - .setEnabledCallback(customFontSettingsEnabled); - ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_antialias", true) - .requiresRestart() - .setEnabledCallback(customFontSettingsEnabled); + ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.custom_font_info") + .setEnabledCallback(customFontsEnabled); + ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_size", 13, 0, 100) + .requiresRestart() + .setEnabledCallback(customFontSettingsEnabled); + ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_bold", false) + .requiresRestart() + .setEnabledCallback(customFontSettingsEnabled); + ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_italic", false) + .requiresRestart() + .setEnabledCallback(customFontSettingsEnabled); + ContentRegistry::Settings::add("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_antialias", true) + .requiresRestart() + .setEnabledCallback(customFontSettingsEnabled); + } /* Folders */ - - ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.folders", "hex.builtin.setting.folders.description"); - ContentRegistry::Settings::add("hex.builtin.setting.folders", "", "hex.builtin.setting.folders.description"); + { + ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.folders", "hex.builtin.setting.folders.description"); + ContentRegistry::Settings::add("hex.builtin.setting.folders", "", "hex.builtin.setting.folders.description"); + } /* Proxy */ + { + HttpRequest::setProxyUrl(ContentRegistry::Settings::read("hex.builtin.setting.proxy", "hex.builtin.setting.proxy.url", "")); - HttpRequest::setProxyUrl(ContentRegistry::Settings::read("hex.builtin.setting.proxy", "hex.builtin.setting.proxy.url", "")); + ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.proxy", "hex.builtin.setting.proxy.description"); - ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.proxy", "hex.builtin.setting.proxy.description"); + auto proxyEnabledSetting = ContentRegistry::Settings::add("hex.builtin.setting.proxy", "", "hex.builtin.setting.proxy.enable", false) + .setChangedCallback([](Widgets::Widget &widget) { + auto checkBox = static_cast(&widget); - auto proxyEnabledSetting = ContentRegistry::Settings::add("hex.builtin.setting.proxy", "", "hex.builtin.setting.proxy.enable", false).setChangedCallback([](Widgets::Widget &widget) { - auto checkBox = static_cast(&widget); + HttpRequest::setProxyState(checkBox->isChecked()); + }); - HttpRequest::setProxyState(checkBox->isChecked()); - }); + ContentRegistry::Settings::add("hex.builtin.setting.proxy", "", "hex.builtin.setting.proxy.url", "") + .setEnabledCallback([proxyEnabledSetting] { + auto &checkBox = static_cast(proxyEnabledSetting.getWidget()); - ContentRegistry::Settings::add("hex.builtin.setting.proxy", "", "hex.builtin.setting.proxy.url", "") - .setEnabledCallback([proxyEnabledSetting] { - auto &checkBox = static_cast(proxyEnabledSetting.getWidget()); - - return checkBox.isChecked(); - }) - .setChangedCallback([](Widgets::Widget &widget) { - auto textBox = static_cast(&widget); - - HttpRequest::setProxyUrl(textBox->getValue()); - }); + return checkBox.isChecked(); + }) + .setChangedCallback([](Widgets::Widget &widget) { + auto textBox = static_cast(&widget); + HttpRequest::setProxyUrl(textBox->getValue()); + }); + } /* Experiments */ - ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.experiments", "hex.builtin.setting.experiments.description"); - EventImHexStartupFinished::subscribe([]{ - for (const auto &[name, experiment] : ContentRegistry::Experiments::impl::getExperiments()) { - ContentRegistry::Settings::add("hex.builtin.setting.experiments", "", experiment.unlocalizedName, false) + { + ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.experiments", "hex.builtin.setting.experiments.description"); + EventImHexStartupFinished::subscribe([]{ + for (const auto &[name, experiment] : ContentRegistry::Experiments::impl::getExperiments()) { + ContentRegistry::Settings::add("hex.builtin.setting.experiments", "", experiment.unlocalizedName, false) .setTooltip(Lang(experiment.unlocalizedDescription)) .setChangedCallback([name](Widgets::Widget &widget) { auto checkBox = static_cast(&widget); ContentRegistry::Experiments::enableExperiement(name, checkBox->isChecked()); }); - } - }); + } + }); + } /* Shorcuts */ - EventImHexStartupFinished::subscribe([]{ - for (const auto &shortcutEntry : ShortcutManager::getGlobalShortcuts()) { - ContentRegistry::Settings::add("hex.builtin.setting.shortcuts", "hex.builtin.setting.shortcuts.global", shortcutEntry.unlocalizedName, nullptr, shortcutEntry.shortcut); - } - - for (auto &[viewName, view] : ContentRegistry::Views::impl::getEntries()) { - for (const auto &shortcutEntry : ShortcutManager::getViewShortcuts(view.get())) { - ContentRegistry::Settings::add("hex.builtin.setting.shortcuts", viewName, shortcutEntry.unlocalizedName, view.get(), shortcutEntry.shortcut); + { + EventImHexStartupFinished::subscribe([]{ + for (const auto &shortcutEntry : ShortcutManager::getGlobalShortcuts()) { + ContentRegistry::Settings::add("hex.builtin.setting.shortcuts", "hex.builtin.setting.shortcuts.global", shortcutEntry.unlocalizedName, nullptr, shortcutEntry.shortcut); } - } - }); - /* Toolbar icons */ - ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.toolbar", "hex.builtin.setting.toolbar.description"); + for (auto &[viewName, view] : ContentRegistry::Views::impl::getEntries()) { + for (const auto &shortcutEntry : ShortcutManager::getViewShortcuts(view.get())) { + ContentRegistry::Settings::add("hex.builtin.setting.shortcuts", viewName, shortcutEntry.unlocalizedName, view.get(), shortcutEntry.shortcut); + } + } + }); + } - ContentRegistry::Settings::add("hex.builtin.setting.toolbar", "", "hex.builtin.setting.toolbar.icons"); + /* Toolbar icons */ + { + ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.toolbar", "hex.builtin.setting.toolbar.description"); + + ContentRegistry::Settings::add("hex.builtin.setting.toolbar", "", "hex.builtin.setting.toolbar.icons"); + } } diff --git a/plugins/builtin/source/content/ui_items.cpp b/plugins/builtin/source/content/ui_items.cpp index 55dc1889d..67d53404c 100644 --- a/plugins/builtin/source/content/ui_items.cpp +++ b/plugins/builtin/source/content/ui_items.cpp @@ -326,7 +326,7 @@ namespace hex::plugin::builtin { ImGui::BeginDisabled(!providerValid || tasksRunning); { - auto &providers = ImHexApi::Provider::getProviders(); + auto providers = ImHexApi::Provider::getProviders(); ImGui::PushStyleColor(ImGuiCol_TabActive, ImGui::GetColorU32(ImGuiCol_MenuBarBg)); ImGui::PushStyleColor(ImGuiCol_TabUnfocusedActive, ImGui::GetColorU32(ImGuiCol_MenuBarBg)); diff --git a/plugins/builtin/source/content/views.cpp b/plugins/builtin/source/content/views.cpp index c6a92abb5..ed2257822 100644 --- a/plugins/builtin/source/content/views.cpp +++ b/plugins/builtin/source/content/views.cpp @@ -20,6 +20,8 @@ #include "content/views/view_highlight_rules.hpp" #include "content/views/view_tutorials.hpp" +#include + namespace hex::plugin::builtin { void registerViews() { @@ -44,6 +46,20 @@ namespace hex::plugin::builtin { ContentRegistry::Views::add(); ContentRegistry::Views::add(); ContentRegistry::Views::add(); + + + LayoutManager::registerLoadCallback([](std::string_view line) { + for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) { + std::string format = hex::format("{}=%d", view->getUnlocalizedName().get()); + sscanf(line.data(), format.c_str(), &view->getWindowOpenState()); + } + }); + + LayoutManager::registerStoreCallback([](ImGuiTextBuffer *buffer) { + for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) { + buffer->appendf("%s=%d\n", name.c_str(), view->getWindowOpenState()); + } + }); } } \ No newline at end of file diff --git a/plugins/builtin/source/content/views/view_achievements.cpp b/plugins/builtin/source/content/views/view_achievements.cpp index 650eba220..abe6e6771 100644 --- a/plugins/builtin/source/content/views/view_achievements.cpp +++ b/plugins/builtin/source/content/views/view_achievements.cpp @@ -160,7 +160,7 @@ namespace hex::plugin::builtin { } void drawOverlay(ImDrawList *drawList, ImVec2 windowMin, ImVec2 windowMax, const std::string &currCategory) { - auto &achievements = AchievementManager::getAchievements()[currCategory]; + auto &achievements = AchievementManager::getAchievements().at(currCategory); // Calculate number of achievements that have been unlocked const auto unlockedCount = std::count_if(achievements.begin(), achievements.end(), [](const auto &entry) { @@ -313,7 +313,7 @@ namespace hex::plugin::builtin { // Draw each individual achievement category for (const auto &categoryName : categories) { - const auto &achievements = startNodes[categoryName]; + const auto &achievements = startNodes.at(categoryName); // Check if any achievements in the category are unlocked or unlockable bool visible = false; diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index ded1199d0..9df06d44e 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -803,7 +803,7 @@ namespace hex::plugin::builtin { RequestHexEditorSelectionChange::subscribe(this, [this](Region region) { auto provider = ImHexApi::Provider::get(); - if (region == Region::Invalid()) { + if (region == Region::Invalid() || provider == nullptr) { m_selectionStart->reset(); m_selectionEnd->reset(); EventRegionSelected::post(ImHexApi::HexEditor::ProviderRegion({ Region::Invalid(), nullptr })); diff --git a/plugins/builtin/source/content/views/view_tools.cpp b/plugins/builtin/source/content/views/view_tools.cpp index d26318224..7cb13bd51 100644 --- a/plugins/builtin/source/content/views/view_tools.cpp +++ b/plugins/builtin/source/content/views/view_tools.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -9,6 +10,21 @@ namespace hex::plugin::builtin { ViewTools::ViewTools() : View::Window("hex.builtin.view.tools.name", ICON_VS_TOOLS) { m_dragStartIterator = ContentRegistry::Tools::impl::getEntries().end(); + + LayoutManager::registerLoadCallback([this](std::string_view line) { + auto parts = wolv::util::splitString(std::string(line), "="); + if (parts.size() != 2) + return; + + m_detachedTools[parts[0]] = parts[1] == "1"; + }); + + LayoutManager::registerStoreCallback([this](ImGuiTextBuffer *buffer) { + for (auto &[unlocalizedName, function] : ContentRegistry::Tools::impl::getEntries()) { + auto detached = m_detachedTools[unlocalizedName]; + buffer->appendf("%s=%d\n", unlocalizedName.get().c_str(), detached); + } + }); } void ViewTools::drawContent() { @@ -16,13 +32,13 @@ namespace hex::plugin::builtin { // Draw all tools for (auto iter = tools.begin(); iter != tools.end(); ++iter) { - auto &[name, function, detached] = *iter; + auto &[unlocalizedName, function] = *iter; // If the tool has been detached from the main window, don't draw it here anymore - if (detached) continue; + if (m_detachedTools[unlocalizedName]) continue; // Draw the tool - if (ImGui::CollapsingHeader(Lang(name))) { + if (ImGui::CollapsingHeader(Lang(unlocalizedName))) { function(); ImGui::NewLine(); } else { @@ -38,7 +54,7 @@ namespace hex::plugin::builtin { // Detach the tool if the user dragged it out of the main window if (!ImGui::IsItemHovered() && m_dragStartIterator == iter) { - detached = true; + m_detachedTools[unlocalizedName] = true; } } @@ -53,19 +69,19 @@ namespace hex::plugin::builtin { auto &tools = ContentRegistry::Tools::impl::getEntries(); for (auto iter = tools.begin(); iter != tools.end(); ++iter) { - auto &[name, function, detached] = *iter; + auto &[unlocalizedName, function] = *iter; // If the tool is still attached to the main window, don't draw it here - if (!detached) continue; + if (!m_detachedTools[unlocalizedName]) continue; // Load the window height that is dependent on the tool content - const auto windowName = View::toWindowName(name); + const auto windowName = View::toWindowName(unlocalizedName); const auto height = m_windowHeights[ImGui::FindWindowByName(windowName.c_str())]; if (height > 0) ImGui::SetNextWindowSizeConstraints(ImVec2(400_scaled, height), ImVec2(FLT_MAX, height)); // Create a new window for the tool - if (ImGui::Begin(windowName.c_str(), &detached, ImGuiWindowFlags_NoCollapse)) { + if (ImGui::Begin(windowName.c_str(), &m_detachedTools[unlocalizedName], ImGuiWindowFlags_NoCollapse)) { // Draw the tool content function(); diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index 6f615e16a..f985e713b 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -243,7 +243,7 @@ namespace hex::plugin::builtin { ImGui::TableNextRow(); ImGui::TableNextColumn(); - if (ImGuiExt::DescriptionButton("hex.builtin.welcome.update.title"_lang, hex::format("hex.builtin.welcome.update.desc"_lang, ImHexApi::System::getInitArguments()["update-available"]).c_str(), ImVec2(ImGui::GetContentRegionAvail().x * 0.8F, 0))) + if (ImGuiExt::DescriptionButton("hex.builtin.welcome.update.title"_lang, hex::format("hex.builtin.welcome.update.desc"_lang, ImHexApi::System::getInitArgument("update-available")).c_str(), ImVec2(ImGui::GetContentRegionAvail().x * 0.8F, 0))) ImHexApi::System::updateImHex(ImHexApi::System::UpdateType::Stable); } diff --git a/plugins/builtin/source/content/window_decoration.cpp b/plugins/builtin/source/content/window_decoration.cpp index 4b029bf78..af23573f1 100644 --- a/plugins/builtin/source/content/window_decoration.cpp +++ b/plugins/builtin/source/content/window_decoration.cpp @@ -180,7 +180,7 @@ namespace hex::plugin::builtin { #endif } - auto &titleBarButtons = ContentRegistry::Interface::impl::getTitleBarButtons(); + auto &titleBarButtons = ContentRegistry::Interface::impl::getTitlebarButtons(); // Draw custom title bar buttons if (!titleBarButtons.empty()) { diff --git a/plugins/diffing/source/content/views/view_diff.cpp b/plugins/diffing/source/content/views/view_diff.cpp index d84b61025..97f5ac796 100644 --- a/plugins/diffing/source/content/views/view_diff.cpp +++ b/plugins/diffing/source/content/views/view_diff.cpp @@ -61,7 +61,7 @@ namespace hex::plugin::diffing { ImGui::PushID(&column); - auto &providers = ImHexApi::Provider::getProviders(); + auto providers = ImHexApi::Provider::getProviders(); auto &providerIndex = column.provider; // Get the name of the currently selected provider