diff --git a/include/views/view_hexeditor.hpp b/include/views/view_hexeditor.hpp index 0125c511f..d95aaec45 100644 --- a/include/views/view_hexeditor.hpp +++ b/include/views/view_hexeditor.hpp @@ -30,7 +30,6 @@ namespace hex { private: MemoryEditor m_memoryEditor; - imgui_addons::ImGuiFileBrowser m_fileBrowser; std::vector &m_patternData; diff --git a/include/views/view_pattern.hpp b/include/views/view_pattern.hpp index e1f50421d..809bbd6e8 100644 --- a/include/views/view_pattern.hpp +++ b/include/views/view_pattern.hpp @@ -32,7 +32,6 @@ namespace hex { TextEditor m_textEditor; std::vector> m_console; - imgui_addons::ImGuiFileBrowser m_fileBrowser; void loadPatternFile(std::string path); void clearPatternData(); diff --git a/plugins/libimhex/include/hex/helpers/shared_data.hpp b/plugins/libimhex/include/hex/helpers/shared_data.hpp index f1e94a673..737477af1 100644 --- a/plugins/libimhex/include/hex/helpers/shared_data.hpp +++ b/plugins/libimhex/include/hex/helpers/shared_data.hpp @@ -12,6 +12,8 @@ #include #include +#include + #include namespace hex { class SharedData; } @@ -59,6 +61,12 @@ namespace hex { static std::string errorPopupMessage; static std::list bookmarkEntries; + static imgui_addons::ImGuiFileBrowser fileBrowser; + static imgui_addons::ImGuiFileBrowser::DialogMode fileBrowserDialogMode; + static std::string fileBrowserTitle; + static std::string fileBrowserValidExtensions; + static std::function fileBrowserCallback; + static int mainArgc; static char **mainArgv; diff --git a/plugins/libimhex/include/hex/views/view.hpp b/plugins/libimhex/include/hex/views/view.hpp index 63ce2a0f5..619c3af74 100644 --- a/plugins/libimhex/include/hex/views/view.hpp +++ b/plugins/libimhex/include/hex/views/view.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -22,6 +23,7 @@ namespace hex { virtual void drawMenu(); virtual bool handleShortcut(int key, int mods); + static void openFileBrowser(std::string title, imgui_addons::ImGuiFileBrowser::DialogMode mode, std::string validExtensions, const std::function &callback); static void doLater(std::function &&function); static std::vector>& getDeferedCalls(); diff --git a/plugins/libimhex/source/helpers/shared_data.cpp b/plugins/libimhex/source/helpers/shared_data.cpp index f0ccaa0ac..e23c44217 100644 --- a/plugins/libimhex/source/helpers/shared_data.cpp +++ b/plugins/libimhex/source/helpers/shared_data.cpp @@ -18,6 +18,12 @@ namespace hex { std::string SharedData::errorPopupMessage; std::list SharedData::bookmarkEntries; + imgui_addons::ImGuiFileBrowser SharedData::fileBrowser; + imgui_addons::ImGuiFileBrowser::DialogMode SharedData::fileBrowserDialogMode; + std::string SharedData::fileBrowserTitle; + std::string SharedData::fileBrowserValidExtensions; + std::function SharedData::fileBrowserCallback; + int SharedData::mainArgc; char **SharedData::mainArgv; diff --git a/plugins/libimhex/source/views/view.cpp b/plugins/libimhex/source/views/view.cpp index 500ec45b8..e22261fca 100644 --- a/plugins/libimhex/source/views/view.cpp +++ b/plugins/libimhex/source/views/view.cpp @@ -24,6 +24,17 @@ namespace hex { return EventManager::post(eventType, userData); } + void View::openFileBrowser(std::string title, imgui_addons::ImGuiFileBrowser::DialogMode mode, std::string validExtensions, const std::function &callback) { + SharedData::fileBrowserTitle = title; + SharedData::fileBrowserDialogMode = mode; + SharedData::fileBrowserValidExtensions = std::move(validExtensions); + SharedData::fileBrowserCallback = callback; + + View::doLater([title]{ + ImGui::OpenPopup(title.c_str()); + }); + } + void View::drawCommonInterfaces() { if (ImGui::BeginPopupModal("Error", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::NewLine(); @@ -38,6 +49,11 @@ namespace hex { ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } + + if (SharedData::fileBrowser.showFileDialog(SharedData::fileBrowserTitle, SharedData::fileBrowserDialogMode, ImVec2(0, 0), SharedData::fileBrowserValidExtensions)) { + SharedData::fileBrowserCallback(SharedData::fileBrowser.selected_path); + SharedData::fileBrowserTitle = ""; + } } void View::showErrorPopup(std::string_view errorMessage) { diff --git a/source/views/view_hexeditor.cpp b/source/views/view_hexeditor.cpp index ba5d50104..86af06aa2 100644 --- a/source/views/view_hexeditor.cpp +++ b/source/views/view_hexeditor.cpp @@ -124,7 +124,6 @@ namespace hex { if (ProjectFile::hasUnsavedChanges()) { glfwSetWindowShouldClose(window, GLFW_FALSE); - this->getWindowOpenState() = true; View::doLater([] { ImGui::OpenPopup("Save Changes"); }); } }); @@ -210,23 +209,21 @@ namespace hex { ImGui::NewLine(); ImGui::InputText("##nolabel", this->m_loaderScriptScriptPath.data(), this->m_loaderScriptScriptPath.length(), ImGuiInputTextFlags_ReadOnly); ImGui::SameLine(); - if (ImGui::Button("Script")) - ImGui::OpenPopup("Loader Script: Open Script"); + if (ImGui::Button("Script")) { + View::openFileBrowser("Loader Script: Open Script", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ".py", [this](auto path) { + this->m_loaderScriptScriptPath = path; + }); + } ImGui::InputText("##nolabel", this->m_loaderScriptFilePath.data(), this->m_loaderScriptFilePath.length(), ImGuiInputTextFlags_ReadOnly); ImGui::SameLine(); - if (ImGui::Button("File")) - ImGui::OpenPopup("Loader Script: Open File"); - + if (ImGui::Button("File")) { + View::openFileBrowser("Loader Script: Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { + this->m_loaderScriptFilePath = path; + }); + } if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape))) ImGui::CloseCurrentPopup(); - if (this->m_fileBrowser.showFileDialog("Loader Script: Open Script", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(0, 0), ".py")) { - this->m_loaderScriptScriptPath = this->m_fileBrowser.selected_path; - } - if (this->m_fileBrowser.showFileDialog("Loader Script: Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN)) { - this->m_loaderScriptFilePath = this->m_fileBrowser.selected_path; - } - ImGui::NewLine(); confirmButtons("Load", "Cancel", @@ -265,62 +262,17 @@ namespace hex { ImGui::EndPopup(); } + } + static void save() { + auto provider = SharedData::currentProvider; + for (const auto &[address, value] : provider->getPatches()) + provider->writeRaw(address, &value, sizeof(u8)); + } - if (this->m_fileBrowser.showFileDialog("Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN)) { - this->openFile(this->m_fileBrowser.selected_path); - } - - if (this->m_fileBrowser.showFileDialog("Open Base64 File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN)) { - std::vector base64; - this->loadFromFile(this->m_fileBrowser.selected_path, base64); - - if (!base64.empty()) { - this->m_dataToSave = decode64(base64); - - if (this->m_dataToSave.empty()) - View::showErrorPopup("File is not in a valid Base64 format!"); - else - ImGui::OpenPopup("Save Data"); - } else View::showErrorPopup("Failed to open file!"); - - } - - - if (this->m_fileBrowser.showFileDialog("Open Project", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(0, 0), ".hexproj")) { - ProjectFile::load(this->m_fileBrowser.selected_path); - View::postEvent(Events::ProjectFileLoad); - } - - if (this->m_fileBrowser.showFileDialog("Save Project", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, ImVec2(0, 0), ".hexproj")) { - ProjectFile::store(this->m_fileBrowser.selected_path); - } - - - if (this->m_fileBrowser.showFileDialog("Export File", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE)) { - this->saveToFile(this->m_fileBrowser.selected_path, this->m_dataToSave); - } - - if (this->m_fileBrowser.showFileDialog("Apply IPS Patch", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN)) { - auto patchData = hex::readFile(this->m_fileBrowser.selected_path); - auto patch = hex::loadIPSPatch(patchData); - - for (auto &[address, value] : patch) { - provider->write(address, &value, 1); - } - } - - if (this->m_fileBrowser.showFileDialog("Apply IPS32 Patch", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN)) { - auto patchData = hex::readFile(this->m_fileBrowser.selected_path); - auto patch = hex::loadIPS32Patch(patchData); - - for (auto &[address, value] : patch) { - provider->write(address, &value, 1); - } - } - - if (this->m_fileBrowser.showFileDialog("Save As", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE)) { - FILE *file = fopen(this->m_fileBrowser.selected_path.c_str(), "wb"); + static void saveAs() { + View::openFileBrowser("Save As", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, "*.*", [](auto path) { + FILE *file = fopen(path.c_str(), "wb"); if (file != nullptr) { std::vector buffer(0xFF'FFFF, 0x00); @@ -328,6 +280,7 @@ namespace hex { fseek(file, 0, SEEK_SET); + auto provider = SharedData::currentProvider; for (u64 offset = 0; offset < provider->getActualSize(); offset += bufferSize) { if (bufferSize > provider->getActualSize() - offset) bufferSize = provider->getActualSize() - offset; @@ -338,39 +291,47 @@ namespace hex { fclose(file); } - } - } + }); + }; void ViewHexEditor::drawMenu() { auto provider = SharedData::currentProvider; if (ImGui::BeginMenu("File")) { if (ImGui::MenuItem("Open File...", "CTRL + O")) { - this->getWindowOpenState() = true; - View::doLater([]{ ImGui::OpenPopup("Open File"); }); + + View::openFileBrowser("Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { + this->openFile(path); + this->getWindowOpenState() = true; + }); } if (ImGui::MenuItem("Save", "CTRL + S", false, provider != nullptr && provider->isWritable())) { - for (const auto &[address, value] : provider->getPatches()) - provider->writeRaw(address, &value, sizeof(u8)); + save(); } if (ImGui::MenuItem("Save As...", "CTRL + SHIFT + S", false, provider != nullptr && provider->isWritable())) { - View::doLater([]{ ImGui::OpenPopup("Save As"); }); + saveAs(); } ImGui::Separator(); if (ImGui::MenuItem("Open Project", "")) { - this->getWindowOpenState() = true; - View::doLater([]{ ImGui::OpenPopup("Open Project"); }); + View::openFileBrowser("Open Project", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ".hexproj", [this](auto path) { + ProjectFile::load(path); + View::postEvent(Events::ProjectFileLoad); + this->getWindowOpenState() = true; + }); } if (ImGui::MenuItem("Save Project", "", false, provider != nullptr && provider->isWritable())) { View::postEvent(Events::ProjectFileStore); - if (ProjectFile::getProjectFilePath() == "") - View::doLater([] { ImGui::OpenPopup("Save Project"); }); + if (ProjectFile::getProjectFilePath() == "") { + View::openFileBrowser("Save Project", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, ".hexproj", [](auto path) { + ProjectFile::store(path); + }); + } else ProjectFile::store(); } @@ -379,24 +340,53 @@ namespace hex { if (ImGui::BeginMenu("Import...")) { if (ImGui::MenuItem("Base64 File")) { - this->getWindowOpenState() = true; - View::doLater([]{ ImGui::OpenPopup("Open Base64 File"); }); + + View::openFileBrowser("Open Base64 File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { + std::vector base64; + this->loadFromFile(path, base64); + + if (!base64.empty()) { + this->m_dataToSave = decode64(base64); + + if (this->m_dataToSave.empty()) + View::showErrorPopup("File is not in a valid Base64 format!"); + else + ImGui::OpenPopup("Save Data"); + this->getWindowOpenState() = true; + } else View::showErrorPopup("Failed to open file!"); + }); } ImGui::Separator(); if (ImGui::MenuItem("IPS Patch")) { - this->getWindowOpenState() = true; - View::doLater([]{ ImGui::OpenPopup("Apply IPS Patch"); }); + + View::openFileBrowser("Apply IPS Patch", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { + auto patchData = hex::readFile(path); + auto patch = hex::loadIPSPatch(patchData); + + for (auto &[address, value] : patch) { + SharedData::currentProvider->write(address, &value, 1); + } + this->getWindowOpenState() = true; + }); + + } if (ImGui::MenuItem("IPS32 Patch")) { - this->getWindowOpenState() = true; - View::doLater([]{ ImGui::OpenPopup("Apply IPS32 Patch"); }); + View::openFileBrowser("Apply IPS32 Patch", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { + auto patchData = hex::readFile(path); + auto patch = hex::loadIPS32Patch(patchData); + + for (auto &[address, value] : patch) { + SharedData::currentProvider->write(address, &value, 1); + } + this->getWindowOpenState() = true; + }); } if (ImGui::MenuItem("File with Loader Script")) { - this->getWindowOpenState() = true; this->m_loaderScriptFilePath.clear(); this->m_loaderScriptScriptPath.clear(); View::doLater([]{ ImGui::OpenPopup("Load File with Loader Script"); }); @@ -415,7 +405,9 @@ namespace hex { } this->m_dataToSave = generateIPSPatch(patches); - View::doLater([]{ ImGui::OpenPopup("Export File"); }); + View::openFileBrowser("Export File", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, "*.*", [this](auto path) { + this->saveToFile(path, this->m_dataToSave); + }); } if (ImGui::MenuItem("IPS32 Patch")) { Patches patches = provider->getPatches(); @@ -426,7 +418,9 @@ namespace hex { } this->m_dataToSave = generateIPS32Patch(patches); - View::doLater([]{ ImGui::OpenPopup("Export File"); }); + View::openFileBrowser("Export File", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, "*.*", [this](auto path) { + this->saveToFile(path, this->m_dataToSave); + }); } ImGui::EndMenu(); @@ -457,12 +451,10 @@ namespace hex { bool ViewHexEditor::handleShortcut(int key, int mods) { if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_S) { - auto provider = SharedData::currentProvider; - for (const auto &[address, value] : provider->getPatches()) - provider->writeRaw(address, &value, sizeof(u8)); + save(); return true; } else if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT) && key == GLFW_KEY_S) { - ImGui::OpenPopup("Save As"); + saveAs(); return true; } else if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_F) { ImGui::OpenPopup("Search"); diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index 61bdcd40f..83e692d9d 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -217,7 +217,9 @@ namespace hex { void ViewPattern::drawMenu() { if (ImGui::BeginMenu("File")) { if (ImGui::MenuItem("Load pattern...")) { - View::doLater([]{ ImGui::OpenPopup("Open Hex Pattern"); }); + View::openFileBrowser("Open Hex Pattern", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ".hexpat", [this](auto path) { + this->loadPatternFile(path); + }); } ImGui::EndMenu(); } @@ -272,9 +274,7 @@ namespace hex { } ImGui::End(); - if (this->m_fileBrowser.showFileDialog("Open Hex Pattern", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(0, 0), ".hexpat")) { - this->loadPatternFile(this->m_fileBrowser.selected_path); - } + if (ImGui::BeginPopupModal("Accept Pattern", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::TextWrapped("One or more patterns compatible with this data type has been found");