From 2c11da1354664782674fa37a1ab54e2dd7e7604d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 13 Feb 2025 17:11:11 -0600 Subject: [PATCH] ImDebugger file browser: Add (slightly clunky) UI to extract individual files. --- UI/ImDebugger/ImDebugger.cpp | 34 ++++++++++++++++++++++++++++++---- UI/ImDebugger/ImDebugger.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index 5c5acc7840..8155acbe7f 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -4,6 +4,7 @@ #include "ext/imgui/imgui_internal.h" #include "Common/StringUtils.h" +#include "Common/File/FileUtil.h" #include "Common/Data/Format/IniFile.h" #include "Core/Config.h" #include "Core/System.h" @@ -403,17 +404,40 @@ void DrawThreadView(ImConfig &cfg, ImControl &control) { } // TODO: Add popup menu, export file, export dir, etc... -static void RecurseFileSystem(IFileSystem *fs, std::string path) { +static void RecurseFileSystem(IFileSystem *fs, std::string path, RequesterToken token) { std::vector fileInfo = fs->GetDirListing(path); for (auto &file : fileInfo) { if (file.type == FileType::FILETYPE_DIRECTORY) { if (file.name != "." && file.name != ".." && ImGui::TreeNode(file.name.c_str())) { std::string fpath = path + "/" + file.name; - RecurseFileSystem(fs, fpath); + RecurseFileSystem(fs, fpath, token); ImGui::TreePop(); } } else { - ImGui::TextUnformatted(file.name.c_str()); + ImGui::Selectable(file.name.c_str()); + if (ImGui::BeginPopupContextItem()) { + if (ImGui::MenuItem("Copy Path")) { + System_CopyStringToClipboard(path + "/" + file.name); + } + if (ImGui::MenuItem("Save file...")) { + std::string fullPath = path + "/" + file.name; + int size = file.size; + // save dialog + System_BrowseForFileSave(token, "Save file", file.name, BrowseFileType::ANY, [fullPath, fs, size](const char *responseString, int) { + int fd = fs->OpenFile(fullPath, FILEACCESS_READ); + if (fd >= 0) { + std::string data; + data.resize(size); + fs->ReadFile(fd, (u8 *)data.data(), size); + fs->CloseFile(fd); + Path dest(responseString); + File::WriteDataToFile(false, data.data(), data.size(), dest); + } + }); + } + // your popup code + ImGui::EndPopup(); + } } } } @@ -433,7 +457,7 @@ static void DrawFilesystemBrowser(ImConfig &cfg) { snprintf(fsTitle, sizeof(fsTitle), "%s - %s", fs.prefix.c_str(), desc); if (ImGui::TreeNode(fsTitle)) { auto system = fs.system; - RecurseFileSystem(system.get(), path); + RecurseFileSystem(system.get(), path, cfg.requesterToken); ImGui::TreePop(); } } @@ -1764,6 +1788,8 @@ Path ImDebugger::ConfigPath() { // But, I don't really want Core to know about the ImDebugger.. void ImConfig::LoadConfig(const Path &iniFile) { + requesterToken = g_requestManager.GenerateRequesterToken(); + IniFile ini; ini.Load(iniFile); // Ignore return value, might not exist yet. In that case we'll end up loading defaults. SyncConfig(&ini, false); diff --git a/UI/ImDebugger/ImDebugger.h b/UI/ImDebugger/ImDebugger.h index 915fef7caf..80f7d204fb 100644 --- a/UI/ImDebugger/ImDebugger.h +++ b/UI/ImDebugger/ImDebugger.h @@ -164,6 +164,7 @@ struct ImConfig { int breakCount = 0; bool displayLatched = false; + int requesterToken; // We use a separate ini file from the main PPSSPP config. void LoadConfig(const Path &iniFile);