impr: Improve situation where ImHex crashes on exit when resources aren't cleared properly
This commit is contained in:
parent
0cba735eb3
commit
d584edf546
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@ -20,7 +21,7 @@ namespace hex {
|
||||
static void importFromFile(const std::fs::path &path);
|
||||
static bool exportToFile(std::fs::path path = {}, std::string workspaceName = {});
|
||||
|
||||
static const auto& getWorkspaces() { return s_workspaces; }
|
||||
static const auto& getWorkspaces() { return *s_workspaces; }
|
||||
static const auto& getCurrentWorkspace() { return s_currentWorkspace; }
|
||||
|
||||
static void reset();
|
||||
@ -30,8 +31,8 @@ namespace hex {
|
||||
private:
|
||||
WorkspaceManager() = default;
|
||||
|
||||
static std::map<std::string, Workspace> s_workspaces;
|
||||
static decltype(s_workspaces)::iterator s_currentWorkspace, s_previousWorkspace;
|
||||
static AutoReset<std::map<std::string, Workspace>> s_workspaces;
|
||||
static decltype(s_workspaces)::Type::iterator s_currentWorkspace, s_previousWorkspace;
|
||||
};
|
||||
|
||||
}
|
64
lib/libimhex/include/hex/helpers/auto_reset.hpp
Normal file
64
lib/libimhex/include/hex/helpers/auto_reset.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
class AutoReset {
|
||||
public:
|
||||
using Type = T;
|
||||
|
||||
AutoReset() {
|
||||
EventImHexClosing::subscribe(this, [this] {
|
||||
this->reset();
|
||||
});
|
||||
}
|
||||
|
||||
~AutoReset() {
|
||||
EventImHexClosing::unsubscribe(this);
|
||||
}
|
||||
|
||||
T* operator->() {
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
const T* operator->() const {
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
T& operator*() {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
const T& operator*() const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
operator T&() {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
operator const T&() const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
T& operator=(const T &value) {
|
||||
m_value = value;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
T& operator=(T &&value) noexcept {
|
||||
m_value = std::move(value);
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_value = T();
|
||||
}
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
};
|
||||
|
||||
}
|
@ -1,27 +1,29 @@
|
||||
#include <hex/api/achievement_manager.hpp>
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>> &AchievementManager::getAchievements() {
|
||||
static std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>> achievements;
|
||||
static AutoReset<std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>> achievements;
|
||||
|
||||
return achievements;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::list<AchievementManager::AchievementNode>>& AchievementManager::getAchievementNodes(bool rebuild) {
|
||||
static std::unordered_map<std::string, std::list<AchievementNode>> nodeCategoryStorage;
|
||||
static AutoReset<std::unordered_map<std::string, std::list<AchievementNode>>> nodeCategoryStorage;
|
||||
|
||||
if (!nodeCategoryStorage.empty() || !rebuild)
|
||||
if (!nodeCategoryStorage->empty() || !rebuild)
|
||||
return nodeCategoryStorage;
|
||||
|
||||
nodeCategoryStorage.clear();
|
||||
nodeCategoryStorage->clear();
|
||||
|
||||
// Add all achievements to the node storage
|
||||
for (auto &[categoryName, achievements] : getAchievements()) {
|
||||
auto &nodes = nodeCategoryStorage[categoryName];
|
||||
auto &nodes = (*nodeCategoryStorage)[categoryName];
|
||||
|
||||
for (auto &[achievementName, achievement] : achievements) {
|
||||
nodes.emplace_back(achievement.get());
|
||||
@ -32,21 +34,21 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::vector<AchievementManager::AchievementNode*>>& AchievementManager::getAchievementStartNodes(bool rebuild) {
|
||||
static std::unordered_map<std::string, std::vector<AchievementNode*>> startNodes;
|
||||
static AutoReset<std::unordered_map<std::string, std::vector<AchievementNode*>>> startNodes;
|
||||
|
||||
if (!startNodes.empty() || !rebuild)
|
||||
if (!startNodes->empty() || !rebuild)
|
||||
return startNodes;
|
||||
|
||||
auto &nodeCategoryStorage = getAchievementNodes();
|
||||
|
||||
startNodes.clear();
|
||||
startNodes->clear();
|
||||
|
||||
// Add all parents and children to the nodes
|
||||
for (auto &[categoryName, achievements] : nodeCategoryStorage) {
|
||||
for (auto &achievementNode : achievements) {
|
||||
for (auto &requirement : achievementNode.achievement->getRequirements()) {
|
||||
for (auto &[requirementCategoryName, requirementAchievements] : nodeCategoryStorage) {
|
||||
auto iter = std::find_if(requirementAchievements.begin(), requirementAchievements.end(), [&requirement](auto &node) {
|
||||
auto iter = std::ranges::find_if(requirementAchievements, [&requirement](auto &node) {
|
||||
return node.achievement->getUnlocalizedName() == requirement;
|
||||
});
|
||||
|
||||
@ -59,7 +61,7 @@ namespace hex {
|
||||
|
||||
for (auto &requirement : achievementNode.achievement->getVisibilityRequirements()) {
|
||||
for (auto &[requirementCategoryName, requirementAchievements] : nodeCategoryStorage) {
|
||||
auto iter = std::find_if(requirementAchievements.begin(), requirementAchievements.end(), [&requirement](auto &node) {
|
||||
auto iter = std::ranges::find_if(requirementAchievements, [&requirement](auto &node) {
|
||||
return node.achievement->getUnlocalizedName() == requirement;
|
||||
});
|
||||
|
||||
@ -74,12 +76,12 @@ namespace hex {
|
||||
for (auto &[categoryName, achievements] : nodeCategoryStorage) {
|
||||
for (auto &achievementNode : achievements) {
|
||||
if (!achievementNode.hasParents()) {
|
||||
startNodes[categoryName].emplace_back(&achievementNode);
|
||||
(*startNodes)[categoryName].emplace_back(&achievementNode);
|
||||
}
|
||||
|
||||
for (const auto &parent : achievementNode.parents) {
|
||||
if (parent->achievement->getUnlocalizedCategory() != achievementNode.achievement->getUnlocalizedCategory())
|
||||
startNodes[categoryName].emplace_back(&achievementNode);
|
||||
(*startNodes)[categoryName].emplace_back(&achievementNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -97,14 +99,12 @@ namespace hex {
|
||||
|
||||
auto &[categoryName, achievements] = *categoryIter;
|
||||
|
||||
auto achievementIter = achievements.find(unlocalizedName);
|
||||
|
||||
const auto achievementIter = achievements.find(unlocalizedName);
|
||||
if (achievementIter == achievements.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto &nodes = getAchievementNodes()[categoryName];
|
||||
|
||||
const auto &nodes = getAchievementNodes()[categoryName];
|
||||
for (const auto &node : nodes) {
|
||||
auto &achievement = node.achievement;
|
||||
|
||||
@ -238,7 +238,7 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
auto result = json.dump(4);
|
||||
const auto result = json.dump(4);
|
||||
file.setSize(0);
|
||||
file.writeString(result);
|
||||
break;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/data_processor/node.hpp>
|
||||
@ -40,7 +41,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
nlohmann::json &getSettingsData() {
|
||||
static nlohmann::json settings;
|
||||
static AutoReset<nlohmann::json> settings;
|
||||
|
||||
return settings;
|
||||
}
|
||||
@ -89,19 +90,21 @@ namespace hex {
|
||||
}
|
||||
|
||||
void store() {
|
||||
auto settingsData = getSettingsData();
|
||||
const auto &settingsData = getSettingsData();
|
||||
|
||||
// During a crash settings can be empty, causing them to be overwritten.
|
||||
if (settingsData.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto result = settingsData.dump(4);
|
||||
if (result.empty()) {
|
||||
return;
|
||||
}
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Write);
|
||||
|
||||
if (file.isValid()) {
|
||||
auto result = settingsData.dump(4);
|
||||
|
||||
file.setSize(0);
|
||||
file.writeString(result);
|
||||
break;
|
||||
@ -137,7 +140,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::vector<Category> &getSettings() {
|
||||
static std::vector<Category> categories;
|
||||
static AutoReset<std::vector<Category>> categories;
|
||||
|
||||
return categories;
|
||||
}
|
||||
@ -245,7 +248,7 @@ namespace hex {
|
||||
|
||||
void ColorPicker::load(const nlohmann::json &data) {
|
||||
if (data.is_number()) {
|
||||
ImColor color(data.get<u32>());
|
||||
const ImColor color(data.get<u32>());
|
||||
m_value = { color.Value.x, color.Value.y, color.Value.z, color.Value.w };
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for color picker!");
|
||||
@ -264,7 +267,7 @@ namespace hex {
|
||||
|
||||
|
||||
bool DropDown::draw(const std::string &name) {
|
||||
const char *preview = "";
|
||||
auto preview = "";
|
||||
if (static_cast<size_t>(m_value) < m_items.size())
|
||||
preview = m_items[m_value].c_str();
|
||||
|
||||
@ -408,13 +411,13 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> commands;
|
||||
static AutoReset<std::vector<Entry>> commands;
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
std::vector<Handler> &getHandlers() {
|
||||
static std::vector<Handler> commands;
|
||||
static AutoReset<std::vector<Handler>> commands;
|
||||
|
||||
return commands;
|
||||
}
|
||||
@ -521,25 +524,25 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::map<std::string, Visualizer> &getVisualizers() {
|
||||
static std::map<std::string, Visualizer> visualizers;
|
||||
static AutoReset<std::map<std::string, Visualizer>> visualizers;
|
||||
|
||||
return visualizers;
|
||||
}
|
||||
|
||||
std::map<std::string, Visualizer> &getInlineVisualizers() {
|
||||
static std::map<std::string, Visualizer> visualizers;
|
||||
static AutoReset<std::map<std::string, Visualizer>> visualizers;
|
||||
|
||||
return visualizers;
|
||||
}
|
||||
|
||||
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
|
||||
static std::map<std::string, pl::api::PragmaHandler> pragmas;
|
||||
static AutoReset<std::map<std::string, pl::api::PragmaHandler>> pragmas;
|
||||
|
||||
return pragmas;
|
||||
}
|
||||
|
||||
std::vector<FunctionDefinition> &getFunctions() {
|
||||
static std::vector<FunctionDefinition> functions;
|
||||
static AutoReset<std::vector<FunctionDefinition>> functions;
|
||||
|
||||
return functions;
|
||||
}
|
||||
@ -555,7 +558,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::map<std::string, std::unique_ptr<View>> &getEntries() {
|
||||
static std::map<std::string, std::unique_ptr<View>> views;
|
||||
static AutoReset<std::map<std::string, std::unique_ptr<View>>> views;
|
||||
|
||||
return views;
|
||||
}
|
||||
@ -590,7 +593,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> tools;
|
||||
static AutoReset<std::vector<Entry>> tools;
|
||||
|
||||
return tools;
|
||||
}
|
||||
@ -616,7 +619,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> entries;
|
||||
static AutoReset<std::vector<Entry>> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
@ -641,7 +644,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> nodes;
|
||||
static AutoReset<std::vector<Entry>> nodes;
|
||||
|
||||
return nodes;
|
||||
}
|
||||
@ -696,13 +699,13 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::map<std::string, std::string> &getLanguages() {
|
||||
static std::map<std::string, std::string> languages;
|
||||
static AutoReset<std::map<std::string, std::string>> languages;
|
||||
|
||||
return languages;
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<LocalizationManager::LanguageDefinition>> &getLanguageDefinitions() {
|
||||
static std::map<std::string, std::vector<LocalizationManager::LanguageDefinition>> definitions;
|
||||
static AutoReset<std::map<std::string, std::vector<LocalizationManager::LanguageDefinition>>> definitions;
|
||||
|
||||
return definitions;
|
||||
}
|
||||
@ -784,7 +787,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void addMenuItemToToolbar(const UnlocalizedString& unlocalizedName, ImGuiCustomCol color) {
|
||||
auto maxIndex = std::ranges::max_element(impl::getMenuItems(), [](const auto &a, const auto &b) {
|
||||
const auto maxIndex = std::ranges::max_element(impl::getMenuItems(), [](const auto &a, const auto &b) {
|
||||
return a.second.toolbarIndex < b.second.toolbarIndex;
|
||||
})->second.toolbarIndex;
|
||||
|
||||
@ -809,38 +812,38 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::multimap<u32, MainMenuItem> &getMainMenuItems() {
|
||||
static std::multimap<u32, MainMenuItem> items;
|
||||
static AutoReset<std::multimap<u32, MainMenuItem>> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
std::multimap<u32, MenuItem> &getMenuItems() {
|
||||
static std::multimap<u32, MenuItem> items;
|
||||
static AutoReset<std::multimap<u32, MenuItem>> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
std::vector<DrawCallback> &getWelcomeScreenEntries() {
|
||||
static std::vector<DrawCallback> entries;
|
||||
static AutoReset<std::vector<DrawCallback>> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
std::vector<DrawCallback> &getFooterItems() {
|
||||
static std::vector<DrawCallback> items;
|
||||
static AutoReset<std::vector<DrawCallback>> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
std::vector<DrawCallback> &getToolbarItems() {
|
||||
static std::vector<DrawCallback> items;
|
||||
static AutoReset<std::vector<DrawCallback>> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
std::vector<SidebarItem> &getSidebarItems() {
|
||||
static std::vector<SidebarItem> items;
|
||||
static AutoReset<std::vector<SidebarItem>> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
std::vector<TitleBarButton> &getTitleBarButtons() {
|
||||
static std::vector<TitleBarButton> buttons;
|
||||
static AutoReset<std::vector<TitleBarButton>> buttons;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
@ -867,7 +870,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::vector<std::string> &getEntries() {
|
||||
static std::vector<std::string> providerNames;
|
||||
static AutoReset<std::vector<std::string>> providerNames;
|
||||
|
||||
return providerNames;
|
||||
}
|
||||
@ -894,7 +897,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> entries;
|
||||
static AutoReset<std::vector<Entry>> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
@ -915,7 +918,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> entries;
|
||||
static AutoReset<std::vector<Entry>> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
@ -996,13 +999,13 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<DataVisualizer>> &getVisualizers() {
|
||||
static std::vector<std::shared_ptr<DataVisualizer>> visualizers;
|
||||
static AutoReset<std::vector<std::shared_ptr<DataVisualizer>>> visualizers;
|
||||
|
||||
return visualizers;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<MiniMapVisualizer>> &getMiniMapVisualizers() {
|
||||
static std::vector<std::shared_ptr<MiniMapVisualizer>> visualizers;
|
||||
static AutoReset<std::vector<std::shared_ptr<MiniMapVisualizer>>> visualizers;
|
||||
|
||||
return visualizers;
|
||||
}
|
||||
@ -1029,7 +1032,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::vector<std::unique_ptr<Algorithm>>& getAlgorithms() {
|
||||
static std::vector<std::unique_ptr<Algorithm>> algorithms;
|
||||
static AutoReset<std::vector<std::unique_ptr<Algorithm>>> algorithms;
|
||||
|
||||
return algorithms;
|
||||
}
|
||||
@ -1047,7 +1050,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::vector<std::unique_ptr<Hash>> &getHashes() {
|
||||
static std::vector<std::unique_ptr<Hash>> hashes;
|
||||
static AutoReset<std::vector<std::unique_ptr<Hash>>> hashes;
|
||||
|
||||
return hashes;
|
||||
}
|
||||
@ -1064,29 +1067,41 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
struct Service {
|
||||
std::string name;
|
||||
std::jthread thread;
|
||||
class Service {
|
||||
public:
|
||||
Service(std::string name, std::jthread thread) : m_name(std::move(name)), m_thread(std::move(thread)) { }
|
||||
Service(const Service&) = delete;
|
||||
Service(Service &&) = default;
|
||||
~Service() {
|
||||
m_thread.request_stop();
|
||||
if (m_thread.joinable())
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
Service& operator=(const Service&) = delete;
|
||||
Service& operator=(Service &&) = default;
|
||||
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::jthread &getThread() const {
|
||||
return m_thread;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::jthread m_thread;
|
||||
};
|
||||
|
||||
std::vector<Service> &getServices() {
|
||||
static std::vector<Service> services;
|
||||
static AutoReset<std::vector<Service>> services;
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
void stopServices() {
|
||||
auto &services = getServices();
|
||||
|
||||
for (auto &service : services) {
|
||||
service.thread.request_stop();
|
||||
}
|
||||
|
||||
for (auto &service : services) {
|
||||
if (service.thread.joinable())
|
||||
service.thread.join();
|
||||
}
|
||||
|
||||
services.clear();
|
||||
}
|
||||
|
||||
@ -1095,7 +1110,7 @@ namespace hex {
|
||||
void registerService(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) {
|
||||
log::debug("Registered new background service: {}", unlocalizedName.get());
|
||||
|
||||
impl::getServices().push_back(impl::Service {
|
||||
impl::getServices().emplace_back(
|
||||
unlocalizedName,
|
||||
std::jthread([callback = auto(callback)](const std::stop_token &stopToken){
|
||||
while (!stopToken.stop_requested()) {
|
||||
@ -1103,7 +1118,7 @@ namespace hex {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
})
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1113,7 +1128,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::map<std::string, NetworkCallback> &getNetworkEndpoints() {
|
||||
static std::map<std::string, NetworkCallback> endpoints;
|
||||
static AutoReset<std::map<std::string, NetworkCallback>> endpoints;
|
||||
|
||||
return endpoints;
|
||||
}
|
||||
@ -1133,7 +1148,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::map<std::string, Experiment> &getExperiments() {
|
||||
static std::map<std::string, Experiment> experiments;
|
||||
static AutoReset<std::map<std::string, Experiment>> experiments;
|
||||
|
||||
return experiments;
|
||||
}
|
||||
@ -1184,7 +1199,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::vector<ReportGenerator> &getGenerators() {
|
||||
static std::vector<ReportGenerator> generators;
|
||||
static AutoReset<std::vector<ReportGenerator>> generators;
|
||||
|
||||
return generators;
|
||||
}
|
||||
|
@ -5,11 +5,11 @@
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
@ -19,6 +19,7 @@
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace hex {
|
||||
@ -36,39 +37,39 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
static std::map<u32, Highlighting> s_backgroundHighlights;
|
||||
std::map<u32, Highlighting> &getBackgroundHighlights() {
|
||||
return s_backgroundHighlights;
|
||||
static AutoReset<std::map<u32, Highlighting>> backgroundHighlights;
|
||||
return backgroundHighlights;
|
||||
}
|
||||
|
||||
static std::map<u32, HighlightingFunction> s_backgroundHighlightingFunctions;
|
||||
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions() {
|
||||
return s_backgroundHighlightingFunctions;
|
||||
static AutoReset<std::map<u32, HighlightingFunction>> backgroundHighlightingFunctions;
|
||||
return backgroundHighlightingFunctions;
|
||||
}
|
||||
|
||||
static std::map<u32, Highlighting> s_foregroundHighlights;
|
||||
std::map<u32, Highlighting> &getForegroundHighlights() {
|
||||
return s_foregroundHighlights;
|
||||
static AutoReset<std::map<u32, Highlighting>> foregroundHighlights;
|
||||
return foregroundHighlights;
|
||||
}
|
||||
|
||||
static std::map<u32, HighlightingFunction> s_foregroundHighlightingFunctions;
|
||||
std::map<u32, HighlightingFunction> &getForegroundHighlightingFunctions() {
|
||||
return s_foregroundHighlightingFunctions;
|
||||
static AutoReset<std::map<u32, HighlightingFunction>> foregroundHighlightingFunctions;
|
||||
return foregroundHighlightingFunctions;
|
||||
}
|
||||
|
||||
static std::map<u32, Tooltip> s_tooltips;
|
||||
std::map<u32, Tooltip> &getTooltips() {
|
||||
return s_tooltips;
|
||||
static AutoReset<std::map<u32, Tooltip>> tooltips;
|
||||
return tooltips;
|
||||
}
|
||||
|
||||
static std::map<u32, TooltipFunction> s_tooltipFunctions;
|
||||
std::map<u32, TooltipFunction> &getTooltipFunctions() {
|
||||
return s_tooltipFunctions;
|
||||
static AutoReset<std::map<u32, TooltipFunction>> tooltipFunctions;
|
||||
return tooltipFunctions;
|
||||
}
|
||||
|
||||
static std::optional<ProviderRegion> s_currentSelection;
|
||||
static AutoReset<std::optional<ProviderRegion>> s_currentSelection;
|
||||
void setCurrentSelection(const std::optional<ProviderRegion> ®ion) {
|
||||
s_currentSelection = region;
|
||||
*s_currentSelection = region;
|
||||
}
|
||||
|
||||
}
|
||||
@ -226,7 +227,7 @@ namespace hex {
|
||||
namespace ImHexApi::Provider {
|
||||
|
||||
static i64 s_currentProvider = -1;
|
||||
static std::vector<prv::Provider *> s_providers;
|
||||
static AutoReset<std::vector<prv::Provider *>> s_providers;
|
||||
|
||||
namespace impl {
|
||||
|
||||
@ -245,7 +246,7 @@ namespace hex {
|
||||
if (!ImHexApi::Provider::isValid())
|
||||
return nullptr;
|
||||
|
||||
return s_providers[s_currentProvider];
|
||||
return (*s_providers)[s_currentProvider];
|
||||
}
|
||||
|
||||
const std::vector<prv::Provider *> &getProviders() {
|
||||
@ -256,7 +257,7 @@ namespace hex {
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
if (index < s_providers.size() && s_currentProvider != index) {
|
||||
if (index < s_providers->size() && s_currentProvider != index) {
|
||||
auto oldProvider = get();
|
||||
s_currentProvider = index;
|
||||
EventProviderChanged::post(oldProvider, get());
|
||||
@ -268,7 +269,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
return !s_providers.empty() && s_currentProvider >= 0 && s_currentProvider < i64(s_providers.size());
|
||||
return !s_providers->empty() && s_currentProvider >= 0 && s_currentProvider < i64(s_providers->size());
|
||||
}
|
||||
|
||||
void markDirty() {
|
||||
@ -276,12 +277,12 @@ namespace hex {
|
||||
}
|
||||
|
||||
void resetDirty() {
|
||||
for (auto &provider : s_providers)
|
||||
for (const auto &provider : *s_providers)
|
||||
provider->markDirty(false);
|
||||
}
|
||||
|
||||
bool isDirty() {
|
||||
return std::ranges::any_of(s_providers, [](const auto &provider) {
|
||||
return std::ranges::any_of(*s_providers, [](const auto &provider) {
|
||||
return provider->isDirty();
|
||||
});
|
||||
}
|
||||
@ -293,11 +294,11 @@ namespace hex {
|
||||
if (skipLoadInterface)
|
||||
provider->skipLoadInterface();
|
||||
|
||||
s_providers.push_back(provider);
|
||||
s_providers->push_back(provider);
|
||||
EventProviderCreated::post(provider);
|
||||
|
||||
if (select || s_providers.size() == 1)
|
||||
setCurrentProvider(s_providers.size() - 1);
|
||||
if (select || s_providers->size() == 1)
|
||||
setCurrentProvider(s_providers->size() - 1);
|
||||
}
|
||||
|
||||
void remove(prv::Provider *provider, bool noQuestions) {
|
||||
@ -316,29 +317,29 @@ namespace hex {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = std::find(s_providers.begin(), s_providers.end(), provider);
|
||||
if (it == s_providers.end())
|
||||
const auto it = std::ranges::find(*s_providers, provider);
|
||||
if (it == s_providers->end())
|
||||
return;
|
||||
|
||||
if (!s_providers.empty()) {
|
||||
if (it == s_providers.begin()) {
|
||||
if (!s_providers->empty()) {
|
||||
if (it == s_providers->begin()) {
|
||||
// If the first provider is being closed, select the one that's the first one now
|
||||
setCurrentProvider(0);
|
||||
|
||||
if (s_providers.size() > 1)
|
||||
EventProviderChanged::post(s_providers[0], s_providers[1]);
|
||||
if (s_providers->size() > 1)
|
||||
EventProviderChanged::post(s_providers->at(0), s_providers->at(1));
|
||||
}
|
||||
else if (std::distance(s_providers.begin(), it) == s_currentProvider) {
|
||||
else if (std::distance(s_providers->begin(), it) == s_currentProvider) {
|
||||
// If the current provider is being closed, select the one that's before it
|
||||
setCurrentProvider(s_currentProvider - 1);
|
||||
}
|
||||
else {
|
||||
// If any other provider is being closed, find the current provider in the list again and select it again
|
||||
auto currentProvider = get();
|
||||
auto currentIt = std::find(s_providers.begin(), s_providers.end(), currentProvider);
|
||||
const auto currentProvider = get();
|
||||
const auto currentIt = std::ranges::find(*s_providers, currentProvider);
|
||||
|
||||
if (currentIt != s_providers.end()) {
|
||||
auto newIndex = std::distance(s_providers.begin(), currentIt);
|
||||
if (currentIt != s_providers->end()) {
|
||||
auto newIndex = std::distance(s_providers->begin(), currentIt);
|
||||
|
||||
if (s_currentProvider == newIndex)
|
||||
newIndex -= 1;
|
||||
@ -351,11 +352,11 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
s_providers.erase(it);
|
||||
if (s_currentProvider >= i64(s_providers.size()))
|
||||
s_providers->erase(it);
|
||||
if (s_currentProvider >= i64(s_providers->size()))
|
||||
setCurrentProvider(0);
|
||||
|
||||
if (s_providers.empty())
|
||||
if (s_providers->empty())
|
||||
EventProviderChanged::post(provider, nullptr);
|
||||
|
||||
provider->close();
|
||||
@ -391,11 +392,11 @@ namespace hex {
|
||||
static ImVec2 s_mainWindowPos;
|
||||
static ImVec2 s_mainWindowSize;
|
||||
void setMainWindowPosition(i32 x, i32 y) {
|
||||
s_mainWindowPos = ImVec2(x, y);
|
||||
s_mainWindowPos = ImVec2(float(x), float(y));
|
||||
}
|
||||
|
||||
void setMainWindowSize(u32 width, u32 height) {
|
||||
s_mainWindowSize = ImVec2(width, height);
|
||||
s_mainWindowSize = ImVec2(float(width), float(height));
|
||||
}
|
||||
|
||||
static ImGuiID s_mainDockSpaceId;
|
||||
@ -436,7 +437,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
static std::string s_gpuVendor;
|
||||
static AutoReset<std::string> s_gpuVendor;
|
||||
void setGPUVendor(const std::string &vendor) {
|
||||
s_gpuVendor = vendor;
|
||||
}
|
||||
@ -536,7 +537,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> &getInitArguments() {
|
||||
static std::map<std::string, std::string> initArgs;
|
||||
static AutoReset<std::map<std::string, std::string>> initArgs;
|
||||
|
||||
return initArgs;
|
||||
}
|
||||
@ -556,7 +557,7 @@ namespace hex {
|
||||
|
||||
|
||||
std::vector<std::fs::path> &getAdditionalFolderPaths() {
|
||||
static std::vector<std::fs::path> additionalFolderPaths;
|
||||
static AutoReset<std::vector<std::fs::path>> additionalFolderPaths;
|
||||
return additionalFolderPaths;
|
||||
}
|
||||
|
||||
@ -595,7 +596,7 @@ namespace hex {
|
||||
|
||||
return hex::format("{}.{}.{}", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber);
|
||||
#elif defined(OS_LINUX) || defined(OS_MACOS) || defined(OS_WEB)
|
||||
struct utsname details;
|
||||
struct utsname details = { };
|
||||
|
||||
if (uname(&details) != 0) {
|
||||
return "Unknown";
|
||||
@ -627,13 +628,13 @@ namespace hex {
|
||||
return "Unknown";
|
||||
}
|
||||
#elif defined(OS_LINUX) || defined(OS_MACOS) || defined(OS_WEB)
|
||||
struct utsname details;
|
||||
struct utsname details = { };
|
||||
|
||||
if (uname(&details) != 0) {
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
return std::string(details.machine);
|
||||
return { details.machine };
|
||||
#else
|
||||
return "Unknown";
|
||||
#endif
|
||||
@ -732,7 +733,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void setWindowResizable(bool resizable) {
|
||||
glfwSetWindowAttrib(impl::s_mainWindowHandle, GLFW_RESIZABLE, resizable);
|
||||
glfwSetWindowAttrib(impl::s_mainWindowHandle, GLFW_RESIZABLE, int(resizable));
|
||||
impl::s_windowResizable = resizable;
|
||||
}
|
||||
|
||||
@ -745,14 +746,14 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::map<std::string, MessagingHandler> &getHandlers() {
|
||||
static std::map<std::string, MessagingHandler> handlers;
|
||||
static AutoReset<std::map<std::string, MessagingHandler>> handlers;
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
void runHandler(const std::string &eventName, const std::vector<u8> &args) {
|
||||
const auto& handlers = impl::getHandlers();
|
||||
auto matchHandler = handlers.find(eventName);
|
||||
const auto matchHandler = handlers.find(eventName);
|
||||
|
||||
if (matchHandler == handlers.end()) {
|
||||
log::error("Forward event handler {} not found", eventName);
|
||||
@ -777,12 +778,12 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
std::vector<Font>& getFonts() {
|
||||
static std::vector<Font> fonts;
|
||||
static AutoReset<std::vector<Font>> fonts;
|
||||
|
||||
return fonts;
|
||||
}
|
||||
|
||||
static std::fs::path s_customFontPath;
|
||||
static AutoReset<std::fs::path> s_customFontPath;
|
||||
void setCustomFontPath(const std::fs::path &path) {
|
||||
s_customFontPath = path;
|
||||
}
|
||||
@ -792,7 +793,7 @@ namespace hex {
|
||||
s_fontSize = size;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ImFontAtlas> s_fontAtlas;
|
||||
static AutoReset<std::unique_ptr<ImFontAtlas>> s_fontAtlas;
|
||||
void setFontAtlas(ImFontAtlas* fontAtlas) {
|
||||
s_fontAtlas = std::unique_ptr<ImFontAtlas>(fontAtlas);
|
||||
}
|
||||
@ -875,7 +876,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
ImFontAtlas* getFontAtlas() {
|
||||
return impl::s_fontAtlas.get();
|
||||
return impl::s_fontAtlas->get();
|
||||
}
|
||||
|
||||
ImFont* Bold() {
|
||||
|
@ -6,16 +6,16 @@
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
std::optional<std::fs::path> s_layoutPathToLoad;
|
||||
std::optional<std::string> s_layoutStringToLoad;
|
||||
std::vector<LayoutManager::Layout> s_layouts;
|
||||
AutoReset<std::optional<std::fs::path>> s_layoutPathToLoad;
|
||||
AutoReset<std::optional<std::string>> s_layoutStringToLoad;
|
||||
AutoReset<std::vector<LayoutManager::Layout>> s_layouts;
|
||||
|
||||
bool s_layoutLocked = false;
|
||||
|
||||
@ -33,7 +33,7 @@ namespace hex {
|
||||
void LayoutManager::save(const std::string &name) {
|
||||
auto fileName = name;
|
||||
fileName = wolv::util::replaceStrings(fileName, " ", "_");
|
||||
std::transform(fileName.begin(), fileName.end(), fileName.begin(), tolower);
|
||||
std::ranges::transform(fileName, fileName.begin(), tolower);
|
||||
fileName += ".hexlyt";
|
||||
|
||||
std::fs::path layoutPath;
|
||||
@ -71,8 +71,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void LayoutManager::process() {
|
||||
if (s_layoutPathToLoad.has_value()) {
|
||||
const auto pathString = wolv::util::toUTF8String(*s_layoutPathToLoad);
|
||||
if (s_layoutPathToLoad->has_value()) {
|
||||
const auto pathString = wolv::util::toUTF8String(**s_layoutPathToLoad);
|
||||
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromDisk(pathString.c_str());
|
||||
@ -81,9 +81,9 @@ namespace hex {
|
||||
log::info("Loaded layout from {}", pathString);
|
||||
}
|
||||
|
||||
if (s_layoutStringToLoad.has_value()) {
|
||||
if (s_layoutStringToLoad->has_value()) {
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromMemory(s_layoutStringToLoad->c_str());
|
||||
ImGui::LoadIniSettingsFromMemory((*s_layoutStringToLoad)->c_str());
|
||||
|
||||
s_layoutStringToLoad = std::nullopt;
|
||||
log::info("Loaded layout from string");
|
||||
@ -91,7 +91,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void LayoutManager::reload() {
|
||||
s_layouts.clear();
|
||||
s_layouts->clear();
|
||||
|
||||
for (const auto &directory : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
|
||||
for (const auto &entry : std::fs::directory_iterator(directory)) {
|
||||
@ -107,7 +107,7 @@ namespace hex {
|
||||
name[i] = char(std::toupper(name[i]));
|
||||
}
|
||||
|
||||
s_layouts.push_back({
|
||||
s_layouts->push_back({
|
||||
name,
|
||||
path
|
||||
});
|
||||
@ -118,7 +118,7 @@ namespace hex {
|
||||
void LayoutManager::reset() {
|
||||
s_layoutPathToLoad.reset();
|
||||
s_layoutStringToLoad.reset();
|
||||
s_layouts.clear();
|
||||
s_layouts->clear();
|
||||
}
|
||||
|
||||
bool LayoutManager::isLayoutLocked() {
|
||||
|
@ -7,17 +7,17 @@ namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string s_fallbackLanguage;
|
||||
std::string s_selectedLanguage;
|
||||
std::map<std::string, std::string> s_currStrings;
|
||||
AutoReset<std::string> s_fallbackLanguage;
|
||||
AutoReset<std::string> s_selectedLanguage;
|
||||
AutoReset<std::map<std::string, std::string>> s_currStrings;
|
||||
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
|
||||
void resetLanguageStrings() {
|
||||
s_currStrings.clear();
|
||||
s_selectedLanguage.clear();
|
||||
s_currStrings->clear();
|
||||
s_selectedLanguage->clear();
|
||||
}
|
||||
|
||||
void setFallbackLanguage(const std::string &language) {
|
||||
@ -41,7 +41,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void loadLanguage(const std::string &language) {
|
||||
s_currStrings.clear();
|
||||
s_currStrings->clear();
|
||||
|
||||
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
|
||||
|
||||
@ -49,12 +49,12 @@ namespace hex {
|
||||
return;
|
||||
|
||||
for (auto &definition : definitions[language])
|
||||
s_currStrings.insert(definition.getEntries().begin(), definition.getEntries().end());
|
||||
s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end());
|
||||
|
||||
const auto& fallbackLanguage = getFallbackLanguage();
|
||||
if (language != fallbackLanguage) {
|
||||
for (auto &definition : definitions[fallbackLanguage])
|
||||
s_currStrings.insert(definition.getEntries().begin(), definition.getEntries().end());
|
||||
s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end());
|
||||
}
|
||||
|
||||
s_selectedLanguage = language;
|
||||
@ -122,8 +122,8 @@ namespace hex {
|
||||
|
||||
const std::string &Lang::get() const {
|
||||
auto &lang = LocalizationManager::s_currStrings;
|
||||
if (lang.contains(m_unlocalizedString))
|
||||
return lang[m_unlocalizedString];
|
||||
if (lang->contains(m_unlocalizedString))
|
||||
return lang->at(m_unlocalizedString);
|
||||
else
|
||||
return m_unlocalizedString;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
@ -303,13 +302,13 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> &PluginManager::getPluginPaths() {
|
||||
static std::vector<std::fs::path> pluginPaths;
|
||||
static AutoReset<std::vector<std::fs::path>> pluginPaths;
|
||||
|
||||
return pluginPaths;
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> &PluginManager::getPluginLoadPaths() {
|
||||
static std::vector<std::fs::path> pluginPaths;
|
||||
static AutoReset<std::vector<std::fs::path>> pluginPaths;
|
||||
|
||||
return pluginPaths;
|
||||
}
|
||||
|
@ -1,20 +1,18 @@
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<ProjectFile::Handler> s_handlers;
|
||||
std::vector<ProjectFile::ProviderHandler> s_providerHandlers;
|
||||
AutoReset<std::vector<ProjectFile::Handler>> s_handlers;
|
||||
AutoReset<std::vector<ProjectFile::ProviderHandler>> s_providerHandlers;
|
||||
|
||||
std::fs::path s_currProjectPath;
|
||||
AutoReset<std::fs::path> s_currProjectPath;
|
||||
|
||||
std::function<bool(const std::fs::path&)> s_loadProjectFunction;
|
||||
std::function<bool(std::optional<std::fs::path>, bool)> s_storeProjectFunction;
|
||||
AutoReset<std::function<bool(const std::fs::path&)>> s_loadProjectFunction;
|
||||
AutoReset<std::function<bool(std::optional<std::fs::path>, bool)>> s_storeProjectFunction;
|
||||
|
||||
}
|
||||
|
||||
@ -28,19 +26,19 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool ProjectFile::load(const std::fs::path &filePath) {
|
||||
return s_loadProjectFunction(filePath);
|
||||
return (*s_loadProjectFunction)(filePath);
|
||||
}
|
||||
|
||||
bool ProjectFile::store(std::optional<std::fs::path> filePath, bool updateLocation) {
|
||||
return s_storeProjectFunction(std::move(filePath), updateLocation);
|
||||
return (*s_storeProjectFunction)(std::move(filePath), updateLocation);
|
||||
}
|
||||
|
||||
bool ProjectFile::hasPath() {
|
||||
return !s_currProjectPath.empty();
|
||||
return !s_currProjectPath->empty();
|
||||
}
|
||||
|
||||
void ProjectFile::clearPath() {
|
||||
s_currProjectPath.clear();
|
||||
s_currProjectPath->clear();
|
||||
}
|
||||
|
||||
std::fs::path ProjectFile::getPath() {
|
||||
|
@ -8,7 +8,7 @@ namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<Shortcut, ShortcutManager::ShortcutEntry> s_globalShortcuts;
|
||||
AutoReset<std::map<Shortcut, ShortcutManager::ShortcutEntry>> s_globalShortcuts;
|
||||
std::atomic<bool> s_paused;
|
||||
std::optional<Shortcut> s_prevShortcut;
|
||||
|
||||
@ -16,7 +16,7 @@ namespace hex {
|
||||
|
||||
|
||||
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
|
||||
s_globalShortcuts.insert({ shortcut, { shortcut, unlocalizedName, callback } });
|
||||
s_globalShortcuts->insert({ shortcut, { shortcut, unlocalizedName, callback } });
|
||||
}
|
||||
|
||||
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
|
||||
@ -57,7 +57,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ShortcutManager::process(const std::unique_ptr<View> ¤tView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
|
||||
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, focused, keyCode);
|
||||
const Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, focused, keyCode);
|
||||
if (keyCode != 0)
|
||||
s_prevShortcut = Shortcut(pressedShortcut.getKeys());
|
||||
|
||||
@ -65,7 +65,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ShortcutManager::processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode) {
|
||||
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, false, keyCode);
|
||||
const Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, false, keyCode);
|
||||
if (keyCode != 0)
|
||||
s_prevShortcut = Shortcut(pressedShortcut.getKeys());
|
||||
|
||||
@ -73,7 +73,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ShortcutManager::clearShortcuts() {
|
||||
s_globalShortcuts.clear();
|
||||
s_globalShortcuts->clear();
|
||||
}
|
||||
|
||||
void ShortcutManager::resumeShortcuts() {
|
||||
@ -90,17 +90,18 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::vector<ShortcutManager::ShortcutEntry> ShortcutManager::getGlobalShortcuts() {
|
||||
std::vector<ShortcutManager::ShortcutEntry> result;
|
||||
std::vector<ShortcutEntry> result;
|
||||
|
||||
for (auto &[shortcut, entry] : s_globalShortcuts)
|
||||
for (auto &[shortcut, entry] : *s_globalShortcuts)
|
||||
result.push_back(entry);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<ShortcutManager::ShortcutEntry> ShortcutManager::getViewShortcuts(const View *view) {
|
||||
std::vector<ShortcutManager::ShortcutEntry> result;
|
||||
std::vector<ShortcutEntry> result;
|
||||
|
||||
result.reserve(view->m_shortcuts.size());
|
||||
for (auto &[shortcut, entry] : view->m_shortcuts)
|
||||
result.push_back(entry);
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <ranges>
|
||||
|
||||
#include <jthread.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
@ -149,7 +148,7 @@ namespace hex {
|
||||
|
||||
|
||||
bool TaskHolder::isRunning() const {
|
||||
auto task = m_task.lock();
|
||||
const auto &task = m_task.lock();
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
@ -157,7 +156,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool TaskHolder::hadException() const {
|
||||
auto task = m_task.lock();
|
||||
const auto &task = m_task.lock();
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
@ -165,7 +164,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool TaskHolder::shouldInterrupt() const {
|
||||
auto task = m_task.lock();
|
||||
const auto &task = m_task.lock();
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
@ -173,7 +172,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool TaskHolder::wasInterrupted() const {
|
||||
auto task = m_task.lock();
|
||||
const auto &task = m_task.lock();
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
@ -181,7 +180,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void TaskHolder::interrupt() const {
|
||||
auto task = m_task.lock();
|
||||
const auto &task = m_task.lock();
|
||||
if (!task)
|
||||
return;
|
||||
|
||||
@ -189,9 +188,9 @@ namespace hex {
|
||||
}
|
||||
|
||||
u32 TaskHolder::getProgress() const {
|
||||
auto task = m_task.lock();
|
||||
const auto &task = m_task.lock();
|
||||
if (!task)
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
// If the max value is 0, the task has no progress
|
||||
if (task->getMaxValue() == 0)
|
||||
@ -265,7 +264,7 @@ namespace hex {
|
||||
|
||||
void TaskManager::exit() {
|
||||
// Interrupt all tasks
|
||||
for (auto &task : s_tasks) {
|
||||
for (const auto &task : s_tasks) {
|
||||
task->interrupt();
|
||||
}
|
||||
|
||||
@ -342,7 +341,7 @@ namespace hex {
|
||||
size_t TaskManager::getRunningTaskCount() {
|
||||
std::scoped_lock lock(s_queueMutex);
|
||||
|
||||
return std::count_if(s_tasks.begin(), s_tasks.end(), [](const auto &task){
|
||||
return std::ranges::count_if(s_tasks, [](const auto &task){
|
||||
return !task->isBackgroundTask();
|
||||
});
|
||||
}
|
||||
@ -350,7 +349,7 @@ namespace hex {
|
||||
size_t TaskManager::getRunningBackgroundTaskCount() {
|
||||
std::scoped_lock lock(s_queueMutex);
|
||||
|
||||
return std::count_if(s_tasks.begin(), s_tasks.end(), [](const auto &task){
|
||||
return std::ranges::count_if(s_tasks, [](const auto &task){
|
||||
return task->isBackgroundTask();
|
||||
});
|
||||
}
|
||||
|
@ -10,21 +10,21 @@ namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<std::string, nlohmann::json> s_themes;
|
||||
std::map<std::string, ThemeManager::ThemeHandler> s_themeHandlers;
|
||||
std::map<std::string, ThemeManager::StyleHandler> s_styleHandlers;
|
||||
std::string s_imageTheme;
|
||||
std::string s_currTheme;
|
||||
AutoReset<std::map<std::string, nlohmann::json>> s_themes;
|
||||
AutoReset<std::map<std::string, ThemeManager::ThemeHandler>> s_themeHandlers;
|
||||
AutoReset<std::map<std::string, ThemeManager::StyleHandler>> s_styleHandlers;
|
||||
AutoReset<std::string> s_imageTheme;
|
||||
AutoReset<std::string> s_currTheme;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction) {
|
||||
s_themeHandlers[name] = { colorMap, getFunction, setFunction };
|
||||
(*s_themeHandlers)[name] = { colorMap, getFunction, setFunction };
|
||||
}
|
||||
|
||||
void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) {
|
||||
s_styleHandlers[name] = { styleMap };
|
||||
(*s_styleHandlers)[name] = { styleMap };
|
||||
}
|
||||
|
||||
void ThemeManager::addTheme(const std::string &content) {
|
||||
@ -32,7 +32,7 @@ namespace hex {
|
||||
auto theme = nlohmann::json::parse(content);
|
||||
|
||||
if (theme.contains("name") && theme.contains("colors")) {
|
||||
s_themes[theme["name"].get<std::string>()] = theme;
|
||||
(*s_themes)[theme["name"].get<std::string>()] = theme;
|
||||
} else {
|
||||
hex::log::error("Invalid theme file");
|
||||
}
|
||||
@ -77,7 +77,7 @@ namespace hex {
|
||||
{ "base", s_currTheme }
|
||||
};
|
||||
|
||||
for (const auto &[type, handler] : s_themeHandlers) {
|
||||
for (const auto &[type, handler] : *s_themeHandlers) {
|
||||
theme["colors"][type] = {};
|
||||
|
||||
for (const auto &[key, value] : handler.colorMap) {
|
||||
@ -86,7 +86,7 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &[type, handler] : s_styleHandlers) {
|
||||
for (const auto &[type, handler] : *s_styleHandlers) {
|
||||
theme["styles"][type] = {};
|
||||
|
||||
for (const auto &[key, style] : handler.styleMap) {
|
||||
@ -105,17 +105,17 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ThemeManager::changeTheme(std::string name) {
|
||||
if (!s_themes.contains(name)) {
|
||||
if (s_themes.empty()) {
|
||||
if (!s_themes->contains(name)) {
|
||||
if (s_themes->empty()) {
|
||||
return;
|
||||
} else {
|
||||
const std::string &defaultTheme = s_themes.begin()->first;
|
||||
const std::string &defaultTheme = s_themes->begin()->first;
|
||||
hex::log::error("Theme '{}' does not exist, using default theme '{}' instead!", name, defaultTheme);
|
||||
name = defaultTheme;
|
||||
}
|
||||
}
|
||||
|
||||
const auto &theme = s_themes[name];
|
||||
const auto &theme = (*s_themes)[name];
|
||||
|
||||
if (theme.contains("base")) {
|
||||
if (theme["base"].is_string()) {
|
||||
@ -126,14 +126,14 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
if (theme.contains("colors") && !s_themeHandlers.empty()) {
|
||||
if (theme.contains("colors") && !s_themeHandlers->empty()) {
|
||||
for (const auto&[type, content] : theme["colors"].items()) {
|
||||
if (!s_themeHandlers.contains(type)) {
|
||||
if (!s_themeHandlers->contains(type)) {
|
||||
log::warn("No theme handler found for '{}'", type);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto &handler = s_themeHandlers[type];
|
||||
const auto &handler = (*s_themeHandlers)[type];
|
||||
for (const auto &[key, value] : content.items()) {
|
||||
if (!handler.colorMap.contains(key)) {
|
||||
log::warn("No color found for '{}.{}'", type, key);
|
||||
@ -146,19 +146,19 @@ namespace hex {
|
||||
continue;
|
||||
}
|
||||
|
||||
s_themeHandlers[type].setFunction(s_themeHandlers[type].colorMap.at(key), color.value());
|
||||
(*s_themeHandlers)[type].setFunction((*s_themeHandlers)[type].colorMap.at(key), color.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (theme.contains("styles") && !s_styleHandlers.empty()) {
|
||||
if (theme.contains("styles") && !s_styleHandlers->empty()) {
|
||||
for (const auto&[type, content] : theme["styles"].items()) {
|
||||
if (!s_styleHandlers.contains(type)) {
|
||||
if (!s_styleHandlers->contains(type)) {
|
||||
log::warn("No style handler found for '{}'", type);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto &handler = s_styleHandlers[type];
|
||||
auto &handler = (*s_styleHandlers)[type];
|
||||
for (const auto &[key, value] : content.items()) {
|
||||
if (!handler.styleMap.contains(key))
|
||||
continue;
|
||||
@ -167,12 +167,12 @@ namespace hex {
|
||||
const float scale = style.needsScaling ? 1_scaled : 1.0F;
|
||||
|
||||
if (value.is_number_float()) {
|
||||
if (auto newValue = std::get_if<float*>(&style.value); newValue != nullptr)
|
||||
if (const auto newValue = std::get_if<float*>(&style.value); newValue != nullptr)
|
||||
**newValue = value.get<float>() * scale;
|
||||
else
|
||||
log::warn("Style variable '{}' was of type ImVec2 but a float was expected.", name);
|
||||
} else if (value.is_array() && value.size() == 2 && value[0].is_number_float() && value[1].is_number_float()) {
|
||||
if (auto newValue = std::get_if<ImVec2*>(&style.value); newValue != nullptr)
|
||||
if (const auto newValue = std::get_if<ImVec2*>(&style.value); newValue != nullptr)
|
||||
**newValue = ImVec2(value[0].get<float>() * scale, value[1].get<float>() * scale);
|
||||
else
|
||||
log::warn("Style variable '{}' was of type float but a ImVec2 was expected.", name);
|
||||
@ -203,18 +203,18 @@ namespace hex {
|
||||
|
||||
std::vector<std::string> ThemeManager::getThemeNames() {
|
||||
std::vector<std::string> themeNames;
|
||||
for (const auto &[name, theme] : s_themes)
|
||||
for (const auto &[name, theme] : *s_themes)
|
||||
themeNames.push_back(name);
|
||||
|
||||
return themeNames;
|
||||
}
|
||||
|
||||
void ThemeManager::reset() {
|
||||
s_themes.clear();
|
||||
s_styleHandlers.clear();
|
||||
s_themeHandlers.clear();
|
||||
s_imageTheme.clear();
|
||||
s_currTheme.clear();
|
||||
s_themes->clear();
|
||||
s_styleHandlers->clear();
|
||||
s_themeHandlers->clear();
|
||||
s_imageTheme->clear();
|
||||
s_currTheme->clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,11 +13,11 @@ namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<std::string, TutorialManager::Tutorial> s_tutorials;
|
||||
decltype(s_tutorials)::iterator s_currentTutorial = s_tutorials.end();
|
||||
AutoReset<std::map<std::string, TutorialManager::Tutorial>> s_tutorials;
|
||||
auto s_currentTutorial = s_tutorials->end();
|
||||
|
||||
std::map<ImGuiID, std::string> s_highlights;
|
||||
std::vector<std::pair<ImRect, std::string>> s_highlightDisplays;
|
||||
AutoReset<std::map<ImGuiID, std::string>> s_highlights;
|
||||
AutoReset<std::vector<std::pair<ImRect, std::string>>> s_highlightDisplays;
|
||||
|
||||
|
||||
class IDStack {
|
||||
@ -67,19 +67,19 @@ namespace hex {
|
||||
|
||||
|
||||
TutorialManager::Tutorial& TutorialManager::createTutorial(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) {
|
||||
return s_tutorials.try_emplace(unlocalizedName, Tutorial(unlocalizedName, unlocalizedDescription)).first->second;
|
||||
return s_tutorials->try_emplace(unlocalizedName, Tutorial(unlocalizedName, unlocalizedDescription)).first->second;
|
||||
}
|
||||
|
||||
void TutorialManager::startTutorial(const UnlocalizedString &unlocalizedName) {
|
||||
s_currentTutorial = s_tutorials.find(unlocalizedName);
|
||||
if (s_currentTutorial == s_tutorials.end())
|
||||
s_currentTutorial = s_tutorials->find(unlocalizedName);
|
||||
if (s_currentTutorial == s_tutorials->end())
|
||||
return;
|
||||
|
||||
s_currentTutorial->second.start();
|
||||
}
|
||||
|
||||
void TutorialManager::drawHighlights() {
|
||||
for (const auto &[rect, unlocalizedText] : s_highlightDisplays) {
|
||||
for (const auto &[rect, unlocalizedText] : *s_highlightDisplays) {
|
||||
const auto drawList = ImGui::GetForegroundDrawList();
|
||||
|
||||
drawList->PushClipRectFullScreen();
|
||||
@ -122,7 +122,7 @@ namespace hex {
|
||||
drawList->PopClipRect();
|
||||
|
||||
}
|
||||
s_highlightDisplays.clear();
|
||||
s_highlightDisplays->clear();
|
||||
}
|
||||
|
||||
void TutorialManager::drawMessageBox(std::optional<Tutorial::Step::Message> message) {
|
||||
@ -196,7 +196,7 @@ namespace hex {
|
||||
void TutorialManager::drawTutorial() {
|
||||
drawHighlights();
|
||||
|
||||
if (s_currentTutorial == s_tutorials.end())
|
||||
if (s_currentTutorial == s_tutorials->end())
|
||||
return;
|
||||
|
||||
const auto ¤tStep = s_currentTutorial->second.m_currentStep;
|
||||
@ -210,11 +210,11 @@ namespace hex {
|
||||
|
||||
|
||||
void TutorialManager::reset() {
|
||||
s_tutorials.clear();
|
||||
s_currentTutorial = s_tutorials.end();
|
||||
s_tutorials->clear();
|
||||
s_currentTutorial = s_tutorials->end();
|
||||
|
||||
s_highlights.clear();
|
||||
s_highlightDisplays.clear();
|
||||
s_highlights->clear();
|
||||
s_highlightDisplays->clear();
|
||||
}
|
||||
|
||||
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::addStep() {
|
||||
@ -252,7 +252,7 @@ namespace hex {
|
||||
}, id);
|
||||
}
|
||||
|
||||
s_highlights.emplace(idStack.get(), text);
|
||||
s_highlights->emplace(idStack.get(), text);
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,7 +271,7 @@ namespace hex {
|
||||
}, id);
|
||||
}
|
||||
|
||||
s_highlights.erase(idStack.get());
|
||||
s_highlights->erase(idStack.get());
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +285,7 @@ namespace hex {
|
||||
if (m_parent->m_currentStep != m_parent->m_steps.end())
|
||||
m_parent->m_currentStep->addHighlights();
|
||||
else
|
||||
s_currentTutorial = s_tutorials.end();
|
||||
s_currentTutorial = s_tutorials->end();
|
||||
}
|
||||
|
||||
|
||||
@ -369,9 +369,9 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ImGuiTestEngineHook_ItemAdd(ImGuiContext*, ImGuiID id, const ImRect& bb, const ImGuiLastItemData*) {
|
||||
const auto element = hex::s_highlights.find(id);
|
||||
if (element != hex::s_highlights.end()) {
|
||||
hex::s_highlightDisplays.emplace_back(bb, element->second);
|
||||
const auto element = hex::s_highlights->find(id);
|
||||
if (element != hex::s_highlights->end()) {
|
||||
hex::s_highlightDisplays->emplace_back(bb, element->second);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,12 +11,12 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::map<std::string, WorkspaceManager::Workspace> WorkspaceManager::s_workspaces;
|
||||
decltype(WorkspaceManager::s_workspaces)::iterator WorkspaceManager::s_currentWorkspace = s_workspaces.end();
|
||||
decltype(WorkspaceManager::s_workspaces)::iterator WorkspaceManager::s_previousWorkspace = s_workspaces.end();
|
||||
AutoReset<std::map<std::string, WorkspaceManager::Workspace>> WorkspaceManager::s_workspaces;
|
||||
decltype(WorkspaceManager::s_workspaces)::Type::iterator WorkspaceManager::s_currentWorkspace = s_workspaces->end();
|
||||
decltype(WorkspaceManager::s_workspaces)::Type::iterator WorkspaceManager::s_previousWorkspace = s_workspaces->end();
|
||||
|
||||
void WorkspaceManager::createWorkspace(const std::string& name, const std::string &layout) {
|
||||
s_currentWorkspace = s_workspaces.insert_or_assign(name, Workspace {
|
||||
s_currentWorkspace = s_workspaces->insert_or_assign(name, Workspace {
|
||||
.layout = layout.empty() ? LayoutManager::saveToString() : layout,
|
||||
.path = {}
|
||||
}).first;
|
||||
@ -28,8 +28,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void WorkspaceManager::switchWorkspace(const std::string& name) {
|
||||
const auto newWorkspace = s_workspaces.find(name);
|
||||
if (newWorkspace != s_workspaces.end()) {
|
||||
const auto newWorkspace = s_workspaces->find(name);
|
||||
if (newWorkspace != s_workspaces->end()) {
|
||||
s_currentWorkspace = newWorkspace;
|
||||
log::info("Switching to workspace '{}'", name);
|
||||
}
|
||||
@ -46,10 +46,10 @@ namespace hex {
|
||||
try {
|
||||
auto json = nlohmann::json::parse(content.begin(), content.end());
|
||||
|
||||
std::string name = json["name"];
|
||||
const std::string name = json["name"];
|
||||
std::string layout = json["layout"];
|
||||
|
||||
s_workspaces[name] = Workspace {
|
||||
(*s_workspaces)[name] = Workspace {
|
||||
.layout = std::move(layout),
|
||||
.path = path
|
||||
};
|
||||
@ -60,7 +60,7 @@ namespace hex {
|
||||
|
||||
bool WorkspaceManager::exportToFile(std::fs::path path, std::string workspaceName) {
|
||||
if (path.empty()) {
|
||||
if (s_currentWorkspace == s_workspaces.end())
|
||||
if (s_currentWorkspace == s_workspaces->end())
|
||||
return false;
|
||||
|
||||
path = s_currentWorkspace->second.path;
|
||||
@ -86,7 +86,7 @@ namespace hex {
|
||||
|
||||
void WorkspaceManager::process() {
|
||||
if (s_previousWorkspace != s_currentWorkspace) {
|
||||
if (s_previousWorkspace != s_workspaces.end())
|
||||
if (s_previousWorkspace != s_workspaces->end())
|
||||
exportToFile(s_previousWorkspace->second.path, s_previousWorkspace->first);
|
||||
|
||||
LayoutManager::closeAllViews();
|
||||
@ -98,9 +98,9 @@ namespace hex {
|
||||
|
||||
|
||||
void WorkspaceManager::reset() {
|
||||
s_workspaces.clear();
|
||||
s_currentWorkspace = s_workspaces.end();
|
||||
s_previousWorkspace = s_workspaces.end();
|
||||
s_workspaces->clear();
|
||||
s_currentWorkspace = s_workspaces->end();
|
||||
s_previousWorkspace = s_workspaces->end();
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,8 +5,7 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/utils_linux.hpp>
|
||||
|
||||
#include <xdg.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
@ -23,7 +22,6 @@
|
||||
#include <nfd.hpp>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
@ -32,7 +30,7 @@
|
||||
|
||||
namespace hex::fs {
|
||||
|
||||
static std::function<void(const std::string&)> s_fileBrowserErrorCallback;
|
||||
static AutoReset<std::function<void(const std::string&)>> s_fileBrowserErrorCallback;
|
||||
void setFileBrowserErrorCallback(const std::function<void(const std::string&)> &callback) {
|
||||
s_fileBrowserErrorCallback = callback;
|
||||
}
|
||||
@ -40,8 +38,9 @@ namespace hex::fs {
|
||||
// With help from https://github.com/owncloud/client/blob/cba22aa34b3677406e0499aadd126ce1d94637a2/src/gui/openfilemanager.cpp
|
||||
void openFileExternal(const std::fs::path &filePath) {
|
||||
// Make sure the file exists before trying to open it
|
||||
if (!wolv::io::fs::exists(filePath))
|
||||
if (!wolv::io::fs::exists(filePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
hex::unused(
|
||||
@ -58,8 +57,9 @@ namespace hex::fs {
|
||||
|
||||
void openFolderExternal(const std::fs::path &dirPath) {
|
||||
// Make sure the folder exists before trying to open it
|
||||
if (!wolv::io::fs::exists(dirPath))
|
||||
if (!wolv::io::fs::exists(dirPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
hex::unused(system(
|
||||
@ -76,8 +76,9 @@ namespace hex::fs {
|
||||
|
||||
void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath) {
|
||||
// Make sure the file exists before trying to open it
|
||||
if (!wolv::io::fs::exists(selectedFilePath))
|
||||
if (!wolv::io::fs::exists(selectedFilePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
hex::unused(system(
|
||||
@ -203,7 +204,7 @@ namespace hex::fs {
|
||||
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<ItemFilter> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath, bool multiple) {
|
||||
// Turn the content of the ItemFilter objects into something NFD understands
|
||||
std::vector<nfdfilteritem_t> validExtensionsNfd;
|
||||
std::vector<nfdfilteritem_t> validExtensionsNfd(validExtensions.size());
|
||||
for (const auto &extension : validExtensions) {
|
||||
validExtensionsNfd.emplace_back(nfdfilteritem_t{ extension.name.c_str(), extension.spec.c_str() });
|
||||
}
|
||||
@ -215,9 +216,9 @@ namespace hex::fs {
|
||||
if (NFD::Init() != NFD_OKAY) {
|
||||
// Handle errors if initialization failed
|
||||
log::error("NFD init returned an error: {}", NFD::GetError());
|
||||
if (s_fileBrowserErrorCallback != nullptr) {
|
||||
auto error = NFD::GetError();
|
||||
s_fileBrowserErrorCallback(error != nullptr ? error : "No details");
|
||||
if (*s_fileBrowserErrorCallback != nullptr) {
|
||||
const auto error = NFD::GetError();
|
||||
(*s_fileBrowserErrorCallback)(error != nullptr ? error : "No details");
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -267,9 +268,9 @@ namespace hex::fs {
|
||||
|
||||
log::error("Requested file dialog returned an error: {}", NFD::GetError());
|
||||
|
||||
if (s_fileBrowserErrorCallback != nullptr) {
|
||||
auto error = NFD::GetError();
|
||||
s_fileBrowserErrorCallback(error != nullptr ? error : "No details");
|
||||
if (*s_fileBrowserErrorCallback != nullptr) {
|
||||
const auto error = NFD::GetError();
|
||||
(*s_fileBrowserErrorCallback)(error != nullptr ? error : "No details");
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,7 +327,7 @@ namespace hex::fs {
|
||||
|
||||
// Add additional data directories to the path
|
||||
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
|
||||
std::copy(additionalDirs.begin(), additionalDirs.end(), std::back_inserter(paths));
|
||||
std::ranges::copy(additionalDirs, std::back_inserter(paths));
|
||||
|
||||
// Add the project file directory to the path, if one is loaded
|
||||
if (ProjectFile::hasPath()) {
|
||||
@ -457,7 +458,7 @@ namespace hex::fs {
|
||||
// Try to create a new file in the given path
|
||||
// If that fails, or the file cannot be deleted anymore afterward; the path is not writable
|
||||
wolv::io::File file(path / TestFileName, wolv::io::File::Mode::Create);
|
||||
bool result = file.isValid();
|
||||
const bool result = file.isValid();
|
||||
if (!file.remove())
|
||||
return false;
|
||||
|
||||
|
@ -47,6 +47,12 @@
|
||||
void setupMacosWindowStyle(GLFWwindow *window) {
|
||||
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
|
||||
cocoaWindow.titleVisibility = NSWindowTitleHidden;
|
||||
|
||||
NSVisualEffectView *visualEffectView = [[NSVisualEffectView alloc] init];
|
||||
[visualEffectView setMaterial:NSVisualEffectMaterialAppearanceBased];
|
||||
[visualEffectView setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
|
||||
|
||||
[cocoaWindow.contentView addSubview:visualEffectView positioned:NSWindowBelow relativeTo:nil];
|
||||
}
|
||||
|
||||
@interface HexDocument : NSDocument
|
||||
|
@ -1,10 +1,11 @@
|
||||
#include <hex/ui/popup.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
|
||||
namespace hex::impl {
|
||||
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<PopupBase>> &PopupBase::getOpenPopups() {
|
||||
static std::vector<std::unique_ptr<PopupBase>> openPopups;
|
||||
static AutoReset<std::vector<std::unique_ptr<PopupBase>>> openPopups;
|
||||
|
||||
return openPopups;
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
#include <hex/ui/toast.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
|
||||
namespace hex::impl {
|
||||
|
||||
[[nodiscard]] std::list<std::unique_ptr<ToastBase>> &ToastBase::getQueuedToasts() {
|
||||
static std::list<std::unique_ptr<ToastBase>> queuedToasts;
|
||||
static AutoReset<std::list<std::unique_ptr<ToastBase>>> queuedToasts;
|
||||
|
||||
return queuedToasts;
|
||||
}
|
||||
|
@ -9,17 +9,11 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/api/theme_manager.hpp>
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
#include <hex/api/layout_manager.hpp>
|
||||
#include <hex/api/achievement_manager.hpp>
|
||||
#include <hex/api/tutorial_manager.hpp>
|
||||
#include <hex/api/workspace_manager.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/ui/popup.hpp>
|
||||
#include <hex/ui/toast.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@ -59,108 +53,41 @@ namespace hex::init {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool deleteSharedData() {
|
||||
// This function is called when ImHex is closed. It deletes all shared data that was created by plugins
|
||||
// This is a bit of a hack but necessary because when ImHex gets closed, all plugins are unloaded in order for
|
||||
// destructors to be called correctly. To prevent crashes when ImHex exits, we need to delete all shared data
|
||||
|
||||
EventImHexClosing::post();
|
||||
EventManager::clear();
|
||||
|
||||
while (ImHexApi::Provider::isValid())
|
||||
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
||||
|
||||
bool prepareExit() {
|
||||
// Terminate all asynchronous tasks
|
||||
TaskManager::exit();
|
||||
|
||||
ContentRegistry::Provider::impl::getEntries().clear();
|
||||
|
||||
ImHexApi::System::getInitArguments().clear();
|
||||
ImHexApi::HexEditor::impl::getBackgroundHighlights().clear();
|
||||
ImHexApi::HexEditor::impl::getForegroundHighlights().clear();
|
||||
ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions().clear();
|
||||
ImHexApi::HexEditor::impl::getForegroundHighlightingFunctions().clear();
|
||||
ImHexApi::HexEditor::impl::getTooltips().clear();
|
||||
ImHexApi::HexEditor::impl::getTooltipFunctions().clear();
|
||||
ImHexApi::System::getAdditionalFolderPaths().clear();
|
||||
ImHexApi::Messaging::impl::getHandlers().clear();
|
||||
ImHexApi::Fonts::getCustomFontPath().clear();
|
||||
ImHexApi::Fonts::impl::getFonts().clear();
|
||||
|
||||
ContentRegistry::Settings::impl::getSettings().clear();
|
||||
ContentRegistry::Settings::impl::getSettingsData().clear();
|
||||
|
||||
ContentRegistry::CommandPaletteCommands::impl::getEntries().clear();
|
||||
ContentRegistry::CommandPaletteCommands::impl::getHandlers().clear();
|
||||
|
||||
ContentRegistry::PatternLanguage::impl::getFunctions().clear();
|
||||
ContentRegistry::PatternLanguage::impl::getPragmas().clear();
|
||||
ContentRegistry::PatternLanguage::impl::getVisualizers().clear();
|
||||
ContentRegistry::PatternLanguage::impl::getInlineVisualizers().clear();
|
||||
|
||||
ContentRegistry::Views::impl::getEntries().clear();
|
||||
impl::PopupBase::getOpenPopups().clear();
|
||||
impl::ToastBase::getQueuedToasts().clear();
|
||||
|
||||
|
||||
ContentRegistry::Tools::impl::getEntries().clear();
|
||||
ContentRegistry::DataInspector::impl::getEntries().clear();
|
||||
|
||||
ContentRegistry::Language::impl::getLanguages().clear();
|
||||
ContentRegistry::Language::impl::getLanguageDefinitions().clear();
|
||||
LocalizationManager::impl::resetLanguageStrings();
|
||||
|
||||
ContentRegistry::Interface::impl::getWelcomeScreenEntries().clear();
|
||||
ContentRegistry::Interface::impl::getFooterItems().clear();
|
||||
ContentRegistry::Interface::impl::getToolbarItems().clear();
|
||||
ContentRegistry::Interface::impl::getMainMenuItems().clear();
|
||||
ContentRegistry::Interface::impl::getMenuItems().clear();
|
||||
ContentRegistry::Interface::impl::getSidebarItems().clear();
|
||||
ContentRegistry::Interface::impl::getTitleBarButtons().clear();
|
||||
|
||||
ShortcutManager::clearShortcuts();
|
||||
|
||||
ContentRegistry::DataProcessorNode::impl::getEntries().clear();
|
||||
|
||||
ContentRegistry::DataFormatter::impl::getEntries().clear();
|
||||
ContentRegistry::FileHandler::impl::getEntries().clear();
|
||||
ContentRegistry::Hashes::impl::getHashes().clear();
|
||||
ContentRegistry::HexEditor::impl::getVisualizers().clear();
|
||||
ContentRegistry::HexEditor::impl::getMiniMapVisualizers().clear();
|
||||
|
||||
ContentRegistry::BackgroundServices::impl::stopServices();
|
||||
|
||||
ContentRegistry::CommunicationInterface::impl::getNetworkEndpoints().clear();
|
||||
|
||||
ContentRegistry::Experiments::impl::getExperiments().clear();
|
||||
ContentRegistry::Reports::impl::getGenerators().clear();
|
||||
|
||||
ContentRegistry::Diffing::impl::getAlgorithms().clear();
|
||||
|
||||
WorkspaceManager::reset();
|
||||
LayoutManager::reset();
|
||||
|
||||
ThemeManager::reset();
|
||||
|
||||
AchievementManager::getAchievements().clear();
|
||||
TutorialManager::reset();
|
||||
|
||||
ProjectFile::getHandlers().clear();
|
||||
ProjectFile::getProviderHandlers().clear();
|
||||
ProjectFile::setProjectFunctions(nullptr, nullptr);
|
||||
|
||||
fs::setFileBrowserErrorCallback(nullptr);
|
||||
|
||||
// Unlock font atlas so it can be deleted in case of a crash
|
||||
if (ImGui::GetCurrentContext() != nullptr)
|
||||
ImGui::GetIO().Fonts->Locked = false;
|
||||
|
||||
// Print a nice message if a crash happened while cleaning up resources
|
||||
// To the person fixing this:
|
||||
// ALWAYS wrap static heap allocated objects inside libimhex such as std::vector, std::string, std::function, etc. in a AutoReset<T>
|
||||
// e.g `AutoReset<std::vector<MyStruct>> m_structs;`
|
||||
//
|
||||
// The reason this is necessary is because each plugin / dynamic library gets its own instance of `std::allocator`
|
||||
// which will try to free the allocated memory when the object is destroyed. However since the storage is static, this
|
||||
// will happen only when libimhex is unloaded after main() returns. At this point all plugins have been unloaded already so
|
||||
// the std::allocator will try to free memory in a heap that does not exist anymore which will cause a crash.
|
||||
// By wrapping the object in a AutoReset<T>, the `EventImHexClosing` event will automatically handle clearing the object
|
||||
// while the heap is still valid.
|
||||
// The heap stays valid right up to the point where `PluginManager::unload()` is called.
|
||||
EventAbnormalTermination::post([] {
|
||||
log::fatal("A crash happened while cleaning up resources during exit!");
|
||||
log::fatal("This is most certainly because WerWolv again forgot to mark a heap allocated object as 'AutoReset'.");
|
||||
log::fatal("Please report this issue on the ImHex GitHub page!");
|
||||
log::fatal("To the person fixing this, read the comment above this message for more information.");
|
||||
});
|
||||
|
||||
EventImHexClosing::post();
|
||||
EventManager::clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool loadPlugins() {
|
||||
// Load all plugins
|
||||
bool hasExtraPluginFolders = !PluginManager::getPluginLoadPaths().empty();
|
||||
#if !defined(IMHEX_STATIC_LINK_PLUGINS)
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Plugins)) {
|
||||
PluginManager::addLoadPath(dir);
|
||||
@ -170,7 +97,7 @@ namespace hex::init {
|
||||
#endif
|
||||
|
||||
// Get loaded plugins
|
||||
auto &plugins = PluginManager::getPlugins();
|
||||
const auto &plugins = PluginManager::getPlugins();
|
||||
|
||||
// If no plugins were loaded, ImHex wasn't installed properly. This will trigger an error popup later on
|
||||
if (plugins.empty()) {
|
||||
@ -180,7 +107,7 @@ namespace hex::init {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto shouldLoadPlugin = [hasExtraPluginFolders, executablePath = wolv::io::fs::getExecutablePath()](const Plugin &plugin) {
|
||||
const auto shouldLoadPlugin = [executablePath = wolv::io::fs::getExecutablePath()](const Plugin &plugin) {
|
||||
// In debug builds, ignore all plugins that are not part of the executable directory
|
||||
#if !defined(DEBUG)
|
||||
return true;
|
||||
@ -189,7 +116,7 @@ namespace hex::init {
|
||||
if (!executablePath.has_value())
|
||||
return true;
|
||||
|
||||
if (hasExtraPluginFolders)
|
||||
if (!PluginManager::getPluginLoadPaths().empty())
|
||||
return true;
|
||||
|
||||
// Check if the plugin is somewhere in the same directory tree as the executable
|
||||
@ -283,7 +210,6 @@ namespace hex::init {
|
||||
|
||||
bool unloadPlugins() {
|
||||
PluginManager::unload();
|
||||
PluginManager::getPluginLoadPaths().clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -320,7 +246,7 @@ namespace hex::init {
|
||||
// Run all exit tasks, and print to console
|
||||
void runExitTasks() {
|
||||
for (const auto &[name, task, async] : init::getExitTasks()) {
|
||||
bool result = task();
|
||||
const bool result = task();
|
||||
log::info("Exit task '{0}' finished {1}", name, result ? "successfully" : "unsuccessfully");
|
||||
}
|
||||
}
|
||||
@ -337,7 +263,7 @@ namespace hex::init {
|
||||
std::vector<Task> getExitTasks() {
|
||||
return {
|
||||
{ "Saving settings", storeSettings, false },
|
||||
{ "Cleaning up shared data", deleteSharedData, false },
|
||||
{ "Prepare exit", prepareExit, false },
|
||||
{ "Unloading plugins", unloadPlugins, false },
|
||||
{ "Deleting old files", deleteOldFiles, false },
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user