feat: Allow recents to also display other providers
This commit is contained in:
parent
440ba3823e
commit
85f0e04d0e
@ -337,12 +337,12 @@ namespace hex {
|
||||
void add(bool addToList = true) {
|
||||
auto typeName = T().getTypeName();
|
||||
|
||||
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = typeName](const std::string &name, hex::prv::Provider **provider) {
|
||||
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = typeName](const std::string &name, bool skipLoadInterface, hex::prv::Provider **provider) {
|
||||
if (name != expectedName) return;
|
||||
|
||||
auto newProvider = new T();
|
||||
prv::Provider *newProvider = new T();
|
||||
|
||||
hex::ImHexApi::Provider::add(newProvider);
|
||||
hex::ImHexApi::Provider::add(newProvider, skipLoadInterface);
|
||||
|
||||
if (provider != nullptr)
|
||||
*provider = newProvider;
|
||||
|
@ -129,7 +129,7 @@ namespace hex {
|
||||
EVENT_DEF(RequestOpenFile, std::fs::path);
|
||||
EVENT_DEF(RequestChangeTheme, u32);
|
||||
EVENT_DEF(RequestOpenPopup, std::string);
|
||||
EVENT_DEF(RequestCreateProvider, std::string, hex::prv::Provider **);
|
||||
EVENT_DEF(RequestCreateProvider, std::string, bool, hex::prv::Provider **);
|
||||
|
||||
EVENT_DEF(RequestShowInfoPopup, std::string);
|
||||
EVENT_DEF(RequestShowErrorPopup, std::string);
|
||||
|
@ -137,7 +137,7 @@ namespace hex {
|
||||
void resetDirty();
|
||||
bool isDirty();
|
||||
|
||||
void add(prv::Provider *provider);
|
||||
void add(prv::Provider *provider, bool skipLoadInterface = false);
|
||||
|
||||
template<std::derived_from<prv::Provider> T>
|
||||
void add(auto &&...args) {
|
||||
@ -146,7 +146,7 @@ namespace hex {
|
||||
|
||||
void remove(prv::Provider *provider, bool noQuestions = false);
|
||||
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName);
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface = false);
|
||||
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,8 @@ namespace hex::fs {
|
||||
Resources,
|
||||
Constants,
|
||||
Encodings,
|
||||
Logs
|
||||
Logs,
|
||||
Recent
|
||||
};
|
||||
|
||||
std::optional<std::fs::path> getExecutablePath();
|
||||
|
@ -104,6 +104,9 @@ namespace hex::prv {
|
||||
|
||||
virtual std::pair<Region, bool> getRegionValidity(u64 address) const;
|
||||
|
||||
void skipLoadInterface() { this->m_skipLoadInterface = true; }
|
||||
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
|
||||
|
||||
protected:
|
||||
u32 m_currPage = 0;
|
||||
u64 m_baseAddress = 0;
|
||||
@ -115,6 +118,7 @@ namespace hex::prv {
|
||||
u32 m_id;
|
||||
|
||||
bool m_dirty = false;
|
||||
bool m_skipLoadInterface = false;
|
||||
|
||||
private:
|
||||
static u32 s_idCounter;
|
||||
|
@ -268,10 +268,13 @@ namespace hex {
|
||||
});
|
||||
}
|
||||
|
||||
void add(prv::Provider *provider) {
|
||||
void add(prv::Provider *provider, bool skipLoadInterface) {
|
||||
if (Task::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
if (skipLoadInterface)
|
||||
provider->skipLoadInterface();
|
||||
|
||||
s_providers.push_back(provider);
|
||||
EventManager::post<EventProviderCreated>(provider);
|
||||
|
||||
@ -310,9 +313,9 @@ namespace hex {
|
||||
delete provider;
|
||||
}
|
||||
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName) {
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface) {
|
||||
prv::Provider* result = nullptr;
|
||||
EventManager::post<RequestCreateProvider>(unlocalizedName, &result);
|
||||
EventManager::post<RequestCreateProvider>(unlocalizedName, skipLoadInterface, &result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -232,6 +232,9 @@ namespace hex::fs {
|
||||
case ImHexPath::Yara:
|
||||
result = appendPath(getDataPaths(), "yara");
|
||||
break;
|
||||
case ImHexPath::Recent:
|
||||
result = appendPath(getConfigPaths(), "recent");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!listNonExisting) {
|
||||
|
@ -251,6 +251,9 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
nlohmann::json Provider::storeSettings(nlohmann::json settings) const {
|
||||
settings["displayName"] = this->getName();
|
||||
settings["type"] = this->getTypeName();
|
||||
|
||||
settings["baseAddress"] = this->m_baseAddress;
|
||||
settings["currPage"] = this->m_currPage;
|
||||
|
||||
@ -263,7 +266,7 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
std::pair<Region, bool> Provider::getRegionValidity(u64 address) const {
|
||||
if (address > this->getActualSize())
|
||||
if (address < this->getActualSize())
|
||||
return { Region::Invalid(), false };
|
||||
|
||||
bool insideValidRegion = false;
|
||||
|
@ -59,18 +59,20 @@ namespace hex::init {
|
||||
bool createDirectories() {
|
||||
bool result = true;
|
||||
|
||||
using enum fs::ImHexPath;
|
||||
constexpr std::array paths = {
|
||||
fs::ImHexPath::Patterns,
|
||||
fs::ImHexPath::PatternsInclude,
|
||||
fs::ImHexPath::Magic,
|
||||
fs::ImHexPath::Plugins,
|
||||
fs::ImHexPath::Resources,
|
||||
fs::ImHexPath::Config,
|
||||
fs::ImHexPath::Constants,
|
||||
fs::ImHexPath::Yara,
|
||||
fs::ImHexPath::Encodings,
|
||||
fs::ImHexPath::Python,
|
||||
fs::ImHexPath::Logs
|
||||
Patterns,
|
||||
PatternsInclude,
|
||||
Magic,
|
||||
Plugins,
|
||||
Resources,
|
||||
Config,
|
||||
Constants,
|
||||
Yara,
|
||||
Encodings,
|
||||
Python,
|
||||
Logs,
|
||||
Recent
|
||||
};
|
||||
|
||||
// Check if ImHex is installed in portable mode
|
||||
|
@ -27,8 +27,8 @@ namespace hex::plugin::builtin::prv {
|
||||
[[nodiscard]] std::string getName() const override;
|
||||
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override { return { }; }
|
||||
|
||||
void loadSettings(const nlohmann::json &settings) override { hex::unused(settings); }
|
||||
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override { return settings; }
|
||||
void loadSettings(const nlohmann::json &settings) override;
|
||||
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override;
|
||||
|
||||
[[nodiscard]] std::string getTypeName() const override {
|
||||
return "hex.builtin.provider.intel_hex";
|
||||
|
@ -13,11 +13,16 @@
|
||||
|
||||
#include "provider_extra_data.hpp"
|
||||
|
||||
#include "content/providers/file_provider.hpp"
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
static void openFile(const std::fs::path &path) {
|
||||
ImHexApi::Provider::createProvider("hex.builtin.provider.file");
|
||||
EventManager::post<EventFileLoaded>(path);
|
||||
auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
|
||||
if (auto *fileProvider = dynamic_cast<prv::FileProvider*>(provider); fileProvider != nullptr) {
|
||||
fileProvider->setPath(path);
|
||||
(void)fileProvider->open();
|
||||
}
|
||||
}
|
||||
|
||||
void registerEventHandlers() {
|
||||
@ -77,6 +82,9 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderCreated>([](hex::prv::Provider *provider) {
|
||||
if (provider->shouldSkipLoadInterface())
|
||||
return;
|
||||
|
||||
if (provider->hasFilePicker()) {
|
||||
if (!provider->handleFilePicker()) {
|
||||
ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); });
|
||||
@ -95,9 +103,6 @@ namespace hex::plugin::builtin {
|
||||
View::showErrorPopup("hex.builtin.popup.error.open"_lang);
|
||||
ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); });
|
||||
}
|
||||
|
||||
if (!provider->isWritable())
|
||||
View::showErrorPopup("hex.builtin.popup.error.read_only"_lang);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -232,4 +232,16 @@ namespace hex::plugin::builtin::prv {
|
||||
return { Region { closestInterval.start, (closestInterval.stop - closestInterval.start) + 1}, true };
|
||||
}
|
||||
|
||||
void IntelHexProvider::loadSettings(const nlohmann::json &settings) {
|
||||
Provider::loadSettings(settings);
|
||||
|
||||
this->m_sourceFilePath = settings["path"].get<std::string>();
|
||||
}
|
||||
|
||||
nlohmann::json IntelHexProvider::storeSettings(nlohmann::json settings) const {
|
||||
settings["path"] = this->m_sourceFilePath.string();
|
||||
|
||||
return Provider::storeSettings(settings);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,8 +35,9 @@ namespace hex::plugin::builtin {
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Button("hex.builtin.common.open"_lang)) {
|
||||
if (provider->open())
|
||||
if (provider->open()) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
else {
|
||||
View::showErrorPopup("hex.builtin.view.provider_settings.load_error"_lang);
|
||||
ImHexApi::Provider::remove(provider);
|
||||
|
@ -6,18 +6,17 @@
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <implot.h>
|
||||
#include <imnodes.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <romfs/romfs.hpp>
|
||||
|
||||
#include <fonts/fontawesome_font.h>
|
||||
#include <fonts/codicons_font.h>
|
||||
|
||||
#include <list>
|
||||
@ -25,12 +24,74 @@
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
static ImGui::Texture s_bannerTexture, s_backdropTexture;
|
||||
static std::list<std::fs::path> s_recentFilePaths;
|
||||
|
||||
static std::fs::path s_safetyBackupPath;
|
||||
|
||||
static std::string s_tipOfTheDay;
|
||||
|
||||
struct RecentProvider {
|
||||
std::string displayName;
|
||||
std::string type;
|
||||
std::fs::path filePath;
|
||||
|
||||
nlohmann::json data;
|
||||
|
||||
bool operator==(const RecentProvider &other) const {
|
||||
return displayName == other.displayName && type == other.type && data == other.data;
|
||||
}
|
||||
};
|
||||
static std::vector<RecentProvider> s_recentProviders;
|
||||
|
||||
static void updateRecentProviders() {
|
||||
s_recentProviders.clear();
|
||||
|
||||
// Query all recent providers
|
||||
std::vector<std::fs::path> recentFiles;
|
||||
for (const auto &folder : fs::getDefaultPaths(fs::ImHexPath::Recent)) {
|
||||
for (const auto &entry : std::fs::directory_iterator(folder)) {
|
||||
if (entry.is_regular_file())
|
||||
recentFiles.push_back(entry.path());
|
||||
}
|
||||
}
|
||||
|
||||
// Sort recent provider files by last modified time
|
||||
std::sort(recentFiles.begin(), recentFiles.end(), [](const auto &a, const auto &b) {
|
||||
return std::fs::last_write_time(a) > std::fs::last_write_time(b);
|
||||
});
|
||||
|
||||
for (u32 i = 0; i < recentFiles.size() && s_recentProviders.size() < 5; i++) {
|
||||
auto &path = recentFiles[i];
|
||||
try {
|
||||
auto jsonData = nlohmann::json::parse(fs::File(path, fs::File::Mode::Read).readString());
|
||||
s_recentProviders.push_back(RecentProvider {
|
||||
.displayName = jsonData["displayName"],
|
||||
.type = jsonData["type"],
|
||||
.filePath = path,
|
||||
.data = jsonData
|
||||
});
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
// De-duplicate recent providers
|
||||
s_recentProviders.erase(std::unique(s_recentProviders.begin(), s_recentProviders.end()), s_recentProviders.end());
|
||||
}
|
||||
|
||||
static void loadRecentProvider(const RecentProvider &recentProvider) {
|
||||
auto *provider = ImHexApi::Provider::createProvider(recentProvider.type, true);
|
||||
if (provider != nullptr) {
|
||||
provider->loadSettings(recentProvider.data);
|
||||
|
||||
if (!provider->open() || !provider->isAvailable()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.open"_lang);
|
||||
ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); });
|
||||
return;
|
||||
}
|
||||
|
||||
updateRecentProviders();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void loadDefaultLayout() {
|
||||
auto layouts = ContentRegistry::Interface::getLayouts();
|
||||
if (!layouts.empty()) {
|
||||
@ -153,9 +214,9 @@ namespace hex::plugin::builtin {
|
||||
ImGui::UnderlinedText("hex.builtin.welcome.start.recent"_lang);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5_scaled);
|
||||
{
|
||||
for (auto &path : s_recentFilePaths) {
|
||||
if (ImGui::BulletHyperlink(std::fs::path(path).filename().string().c_str())) {
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
for (const auto &recentProvider : s_recentProviders) {
|
||||
if (ImGui::BulletHyperlink(recentProvider.displayName.c_str())) {
|
||||
loadRecentProvider(recentProvider);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -314,6 +375,8 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
void createWelcomeScreen() {
|
||||
updateRecentProviders();
|
||||
|
||||
(void)EventManager::subscribe<EventFrameBegin>(drawWelcomeScreen);
|
||||
(void)EventManager::subscribe<EventFrameBegin>(drawNoViewsBackground);
|
||||
|
||||
@ -405,35 +468,16 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
});
|
||||
|
||||
(void)EventManager::subscribe<EventFileLoaded>([](const auto &path) {
|
||||
s_recentFilePaths.push_front(path);
|
||||
|
||||
(void)EventManager::subscribe<EventProviderOpened>([](prv::Provider *provider) {
|
||||
{
|
||||
std::list<std::fs::path> uniques;
|
||||
for (auto &file : s_recentFilePaths) {
|
||||
auto recentPath = fs::getDefaultPaths(fs::ImHexPath::Recent).front();
|
||||
auto fileName = hex::format("{:%y%m%d_%H%M%S}.json", fmt::gmtime(std::chrono::system_clock::now()));
|
||||
fs::File recentFile(recentPath / fileName, fs::File::Mode::Create);
|
||||
|
||||
bool exists = false;
|
||||
for (auto &unique : uniques) {
|
||||
if (file == unique)
|
||||
exists = true;
|
||||
recentFile.write(provider->storeSettings().dump(4));
|
||||
}
|
||||
|
||||
if (!exists && !file.empty())
|
||||
uniques.push_back(file);
|
||||
|
||||
if (uniques.size() > 5)
|
||||
break;
|
||||
}
|
||||
s_recentFilePaths = uniques;
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<std::string> recentFilesVector;
|
||||
for (const auto &recentPath : s_recentFilePaths)
|
||||
recentFilesVector.push_back(recentPath.string());
|
||||
|
||||
ContentRegistry::Settings::write("hex.builtin.setting.imhex", "hex.builtin.setting.imhex.recent_files", recentFilesVector);
|
||||
}
|
||||
updateRecentProviders();
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderCreated>([](auto) {
|
||||
@ -442,23 +486,23 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1075, [&] {
|
||||
if (ImGui::BeginMenu("hex.builtin.menu.file.open_recent"_lang, !s_recentFilePaths.empty())) {
|
||||
if (ImGui::BeginMenu("hex.builtin.menu.file.open_recent"_lang, !s_recentProviders.empty())) {
|
||||
// Copy to avoid changing list while iteration
|
||||
std::list<std::fs::path> recentFilePaths = s_recentFilePaths;
|
||||
for (auto &path : recentFilePaths) {
|
||||
auto filename = std::fs::path(path).filename().string();
|
||||
if (ImGui::MenuItem(filename.c_str())) {
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
auto recentProviders = s_recentProviders;
|
||||
for (auto &recentProvider : recentProviders) {
|
||||
if (ImGui::MenuItem(recentProvider.displayName.c_str())) {
|
||||
loadRecentProvider(recentProvider);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.clear_recent"_lang)) {
|
||||
s_recentFilePaths.clear();
|
||||
ContentRegistry::Settings::write(
|
||||
"hex.builtin.setting.imhex",
|
||||
"hex.builtin.setting.imhex.recent_files",
|
||||
std::vector<std::string> {});
|
||||
s_recentProviders.clear();
|
||||
|
||||
// Remove all recent files
|
||||
for (const auto &recentPath : fs::getDefaultPaths(fs::ImHexPath::Recent))
|
||||
for (const auto &entry : std::fs::directory_iterator(recentPath))
|
||||
std::fs::remove(entry.path());
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
@ -474,12 +518,6 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &pathString : ContentRegistry::Settings::read("hex.builtin.setting.imhex", "hex.builtin.setting.imhex.recent_files")) {
|
||||
std::fs::path path = std::u8string(pathString.begin(), pathString.end());
|
||||
if (fs::exists(path))
|
||||
s_recentFilePaths.emplace_back(path);
|
||||
}
|
||||
|
||||
if (ImHexApi::System::getInitArguments().contains("tip-of-the-day")) {
|
||||
s_tipOfTheDay = ImHexApi::System::getInitArguments()["tip-of-the-day"];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user