From 5666a5c5fb497d5866f3038dc92bebfe022f06a8 Mon Sep 17 00:00:00 2001 From: iTrooz Date: Sun, 21 May 2023 13:21:53 +0200 Subject: [PATCH] feat: Added context menu with right-clicking on file provider (#1084) Co-authored-by: Nik --- lib/libimhex/include/hex/helpers/fs.hpp | 4 ++ .../include/hex/providers/provider.hpp | 4 ++ lib/libimhex/source/helpers/fs.cpp | 66 +++++++++++++++++++ .../content/providers/file_provider.hpp | 2 + plugins/builtin/romfs/lang/base.json | 2 + plugins/builtin/romfs/lang/en_US.json | 2 + .../content/providers/file_provider.cpp | 13 ++++ plugins/builtin/source/content/ui_items.cpp | 14 ++++ 8 files changed, 107 insertions(+) diff --git a/lib/libimhex/include/hex/helpers/fs.hpp b/lib/libimhex/include/hex/helpers/fs.hpp index 939d57290..8a04454ef 100644 --- a/lib/libimhex/include/hex/helpers/fs.hpp +++ b/lib/libimhex/include/hex/helpers/fs.hpp @@ -23,6 +23,10 @@ namespace hex::fs { void setFileBrowserErrorCallback(const std::function &callback); bool openFileBrowser(DialogMode mode, const std::vector &validExtensions, const std::function &callback, const std::string &defaultPath = {}, bool multiple = false); + void openFileExternal(const std::fs::path &filePath); + void openFolderExternal(const std::fs::path &dirPath); + void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath); + enum class ImHexPath : u32 { Patterns = 0, PatternsInclude, diff --git a/lib/libimhex/include/hex/providers/provider.hpp b/lib/libimhex/include/hex/providers/provider.hpp index 71421d51e..8a55e7687 100644 --- a/lib/libimhex/include/hex/providers/provider.hpp +++ b/lib/libimhex/include/hex/providers/provider.hpp @@ -118,6 +118,10 @@ namespace hex::prv { [[nodiscard]] virtual bool hasFilePicker() const; virtual bool handleFilePicker(); + virtual std::vector>> getMenuEntries() { + return { }; + }; + [[nodiscard]] virtual bool hasLoadInterface() const; [[nodiscard]] virtual bool hasInterface() const; virtual bool drawLoadInterface(); diff --git a/lib/libimhex/source/helpers/fs.cpp b/lib/libimhex/source/helpers/fs.cpp index a92bd024e..a966fa51f 100644 --- a/lib/libimhex/source/helpers/fs.cpp +++ b/lib/libimhex/source/helpers/fs.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -27,6 +28,71 @@ namespace hex::fs { s_fileBrowserErrorCallback = callback; } + // With help from https://github.com/owncloud/client/blob/cba22aa34b3677406e0499aadd126ce1d94637a2/src/gui/openfilemanager.cpp + + void openFileExternal(const std::fs::path &filePath) { + if (!wolv::io::fs::exists(filePath)) + return; + + #if defined(OS_WINDOWS) + hex::unused( + ShellExecute(nullptr, "open", wolv::util::toUTF8String(filePath).c_str(), nullptr, nullptr, SW_SHOWNORMAL) + ); + #elif defined(OS_MACOS) + hex::unused(system( + hex::format("open {}", wolv::util::toUTF8String(filePath)).c_str() + )); + #elif defined(OS_LINUX) + hex::unused(system( + hex::format("xdg-open {}", wolv::util::toUTF8String(filePath)).c_str() + )); + #endif + } + + void openFolderExternal(const std::fs::path &dirPath) { + if (!wolv::io::fs::exists(dirPath)) + return; + + #if defined(OS_WINDOWS) + hex::unused(system( + hex::format("explorer.exe {}", wolv::util::toUTF8String(dirPath)).c_str() + )); + #elif defined(OS_MACOS) + hex::unused(system( + hex::format("open {}", wolv::util::toUTF8String(dirPath)).c_str() + )); + #elif defined(OS_LINUX) + hex::unused(system( + hex::format("xdg-open {}", wolv::util::toUTF8String(dirPath)).c_str() + )); + #endif + } + + void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath) { + if (!wolv::io::fs::exists(selectedFilePath)) + return; + + #if defined(OS_WINDOWS) + hex::unused(system( + hex::format(R"(explorer.exe /select,"{}")", wolv::util::toUTF8String(selectedFilePath)).c_str() + )); + #elif defined(OS_MACOS) + hex::unused(system( + hex::format( + R"(osascript -e 'tell application "Finder" to reveal POSIX file "{}"')", + wolv::util::toUTF8String(selectedFilePath) + ).c_str() + )); + system(R"(osascript -e 'tell application "Finder" to activate')"); + #elif defined(OS_LINUX) + // fallback to only opening the folder for now + // TODO actually select the file + hex::unused(system( + hex::format("xdg-open {}", wolv::util::toUTF8String(selectedFilePath.parent_path())).c_str() + )); + #endif + } + bool openFileBrowser(DialogMode mode, const std::vector &validExtensions, const std::function &callback, const std::string &defaultPath, bool multiple) { NFD::ClearError(); diff --git a/plugins/builtin/include/content/providers/file_provider.hpp b/plugins/builtin/include/content/providers/file_provider.hpp index 4c3c7c5bd..7afd5bf8b 100644 --- a/plugins/builtin/include/content/providers/file_provider.hpp +++ b/plugins/builtin/include/content/providers/file_provider.hpp @@ -42,6 +42,8 @@ namespace hex::plugin::builtin { [[nodiscard]] bool hasFilePicker() const override { return true; } [[nodiscard]] bool handleFilePicker() override; + std::vector>> getMenuEntries() override; + void setPath(const std::fs::path &path); [[nodiscard]] bool open() override; diff --git a/plugins/builtin/romfs/lang/base.json b/plugins/builtin/romfs/lang/base.json index 0e0f6c60f..4c5fe35a5 100644 --- a/plugins/builtin/romfs/lang/base.json +++ b/plugins/builtin/romfs/lang/base.json @@ -352,6 +352,8 @@ "hex.builtin.provider.file.modification", "hex.builtin.provider.file.path", "hex.builtin.provider.file.size", + "hex.builtin.provider.file.menu.open_file", + "hex.builtin.provider.file.menu.open_folder", "hex.builtin.provider.gdb", "hex.builtin.provider.gdb.ip", "hex.builtin.provider.gdb.name", diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 17a0d3e9f..06c45fff3 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -403,6 +403,8 @@ "hex.builtin.provider.file.modification": "Last modification time", "hex.builtin.provider.file.path": "File path", "hex.builtin.provider.file.size": "Size", + "hex.builtin.provider.file.menu.open_file": "Open file externally", + "hex.builtin.provider.file.menu.open_folder": "Open containing folder", "hex.builtin.provider.gdb": "GDB Server Provider", "hex.builtin.provider.gdb.ip": "IP Address", "hex.builtin.provider.gdb.name": "GDB Server <{0}:{1}>", diff --git a/plugins/builtin/source/content/providers/file_provider.cpp b/plugins/builtin/source/content/providers/file_provider.cpp index e66188126..c5a89d4be 100644 --- a/plugins/builtin/source/content/providers/file_provider.cpp +++ b/plugins/builtin/source/content/providers/file_provider.cpp @@ -185,6 +185,19 @@ namespace hex::plugin::builtin { }); } + std::vector>> FileProvider::getMenuEntries(){ + return { + {"hex.builtin.provider.file.menu.open_folder"_lang, [path = this->m_path] { + fs::openFolderWithSelectionExternal(path); + }}, + + {"hex.builtin.provider.file.menu.open_file"_lang, [path = this->m_path] { + fs::openFileExternal(path); + }}, + + }; + } + void FileProvider::setPath(const std::fs::path &path) { this->m_path = path; } diff --git a/plugins/builtin/source/content/ui_items.cpp b/plugins/builtin/source/content/ui_items.cpp index 90e7fb620..e2d33e981 100644 --- a/plugins/builtin/source/content/ui_items.cpp +++ b/plugins/builtin/source/content/ui_items.cpp @@ -224,6 +224,20 @@ namespace hex::plugin::builtin { ImHexApi::Provider::remove(providers[i]); break; } + + std::string popupID = std::string("ProviderMenu.") + std::to_string(tabProvider->getID()); + if (ImGui::IsMouseReleased(1) && ImGui::IsItemHovered()) { + ImGui::OpenPopup(popupID.c_str()); + } + + if (ImGui::BeginPopup(popupID.c_str())) { + for (auto p : tabProvider->getMenuEntries()) { + if (ImGui::MenuItem(p.first.c_str())) { + p.second(); + } + } + ImGui::EndPopup(); + } } ImGui::EndTabBar(); }