diff --git a/src/core/emulator_settings.h b/src/core/emulator_settings.h index 28a76bb6e..dff7b77c0 100644 --- a/src/core/emulator_settings.h +++ b/src/core/emulator_settings.h @@ -199,6 +199,7 @@ struct GeneralSettings { Setting show_fps_counter{false}; Setting console_language{1}; Setting big_picture_scale{1000}; + Setting big_picture_folder_depth{2}; Setting shadnet_server{"srv.shadps4.net:31313"}; Setting shadnet_webapi_server{"http://srv.shadps4.net:31315"}; Setting signaling_info{}; @@ -241,8 +242,9 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GeneralSettings, install_dirs, addon_install_ trophy_popup_disabled, trophy_notification_duration, show_splash, trophy_notification_side, connected_to_network, discord_rpc_enabled, show_fps_counter, console_language, - big_picture_scale, shadnet_server, shadnet_webapi_server, - signaling_info, enable_upnp, redzone_patches) + big_picture_scale, big_picture_folder_depth, shadnet_server, + shadnet_webapi_server, signaling_info, enable_upnp, + redzone_patches) // ------------------------------- // Log settings @@ -659,6 +661,7 @@ public: SETTING_FORWARD_BOOL(m_general, ShowFpsCounter, show_fps_counter) SETTING_FORWARD(m_general, ConsoleLanguage, console_language) SETTING_FORWARD(m_general, BigPictureScale, big_picture_scale) + SETTING_FORWARD(m_general, BigPictureFolderDepth, big_picture_folder_depth) SETTING_FORWARD(m_general, ShadNetServer, shadnet_server) SETTING_FORWARD(m_general, ShadNetWebApiServer, shadnet_webapi_server) SETTING_FORWARD(m_general, SignalingInfo, signaling_info) diff --git a/src/imgui/big_picture/big_picture.cpp b/src/imgui/big_picture/big_picture.cpp index 70838fd81..dfb1b21ee 100644 --- a/src/imgui/big_picture/big_picture.cpp +++ b/src/imgui/big_picture/big_picture.cpp @@ -162,62 +162,108 @@ SDL_Texture* LoadSdlTextureDataFromFile(std::filesystem::path filePath) { return LoadSdlTextureData(data); } +void scanFolder(std::vector& icons, std::filesystem::path folderPath, int depth) { + if (depth > EmulatorSettings.GetBigPictureFolderDepth()) { + return; + } + + std::error_code ec; + std::filesystem::directory_iterator it(folderPath, std::filesystem::directory_options::none, + ec); + std::filesystem::directory_iterator end; + + if (ec) { + LOG_ERROR(ImGui, "Cannot open folder: {} due to filesystem error: {}", folderPath.string(), + ec.message()); + return; + } + + while (it != end) { + // For access errors getting it.path may not be safe, so log parent folder + if (ec) { + LOG_ERROR(ImGui, "Cannot access item inside folder {} due to error: {}", + folderPath.string(), ec.message()); + ec.clear(); + it.increment(ec); + continue; + } + + const auto& entry = *it; + bool isEntryDir = std::filesystem::is_directory(entry, ec); + + if (ec) { + LOG_ERROR(ImGui, "Skipping file/subfolder {} due to filesystem error: {}", + entry.path().string(), ec.message()); + ec.clear(); + it.increment(ec); + continue; + } + + if (isEntryDir && !std::filesystem::exists(entry.path() / "eboot.bin", ec)) { + scanFolder(icons, entry.path(), depth + 1); + } + + std::string pathstring = entry.path().filename().string(); + if (pathstring.ends_with("-UPDATE") || pathstring.ends_with("-patch") || + (!isEntryDir && !Core::FileSys::IsZArchiveFile(entry))) { + it.increment(ec); + continue; + } + + if (Core::FileSys::IsZArchiveFile(entry)) { + size_t start = pathstring.length() - 3; + for (size_t i = start; i < pathstring.length(); ++i) { + pathstring[i] = + static_cast(std::tolower(static_cast(pathstring[i]))); + } + + if (pathstring.ends_with("-UPDATE.zar") || pathstring.ends_with("-patch.zar")) { + it.increment(ec); + continue; + } + } + + IconInfo icon; + PSF psf; + const std::string sfoFileName = "param.sfo"; + std::filesystem::path sfoPath = UpdateChecker(sfoFileName, entry.path()); + + if (std::filesystem::exists(sfoPath, ec) && psf.Open(sfoPath)) { + if (const auto title = psf.GetString("TITLE"); title.has_value()) { + icon.title = *title; + } + + if (const auto title_id = psf.GetString("TITLE_ID"); title_id.has_value()) { + icon.serial = *title_id; + } + } else { + it.increment(ec); + continue; + } + + const std::string iconFileName = "icon0.png"; + std::filesystem::path iconPath = UpdateChecker(iconFileName, entry.path()); + + SDL_Texture* texture = LoadSdlTextureDataFromFile(iconPath); + icon.textureId = ImTextureID(texture); + + icon.ebootPath = entry.path() / "eboot.bin"; + if (Core::FileSys::IsZArchiveFile(entry.path())) { + icon.ebootPath = entry.path(); + } + + icon.focusState = false; + icons.push_back(icon); + it.increment(ec); + } +} + void GetGameIconInfo(std::vector& icons) { icons.clear(); for (const auto& installLoc : EmulatorSettings.GetAllGameInstallDirs()) { if (installLoc.enabled && std::filesystem::exists(installLoc.path)) { - for (const auto& entry : std::filesystem::directory_iterator(installLoc.path)) { - - std::string pathstring = entry.path().filename().string(); - if (pathstring.ends_with("-UPDATE") || pathstring.ends_with("-patch") || - (!entry.is_directory() && !Core::FileSys::IsZArchiveFile(entry))) { - continue; - } - - if (Core::FileSys::IsZArchiveFile(entry)) { - size_t start = pathstring.length() - 3; - for (size_t i = start; i < pathstring.length(); ++i) { - pathstring[i] = static_cast( - std::tolower(static_cast(pathstring[i]))); - } - - if (pathstring.ends_with("-UPDATE.zar") || pathstring.ends_with("-patch.zar")) { - continue; - } - } - - IconInfo icon; - PSF psf; - const std::string sfoFileName = "param.sfo"; - std::filesystem::path sfoPath = UpdateChecker(sfoFileName, entry.path()); - - if (std::filesystem::exists(sfoPath) && psf.Open(sfoPath)) { - if (const auto title = psf.GetString("TITLE"); title.has_value()) { - icon.title = *title; - } - - if (const auto title_id = psf.GetString("TITLE_ID"); title_id.has_value()) { - icon.serial = *title_id; - } - } else { - continue; - } - - const std::string iconFileName = "icon0.png"; - std::filesystem::path iconPath = UpdateChecker(iconFileName, entry.path()); - - SDL_Texture* texture = LoadSdlTextureDataFromFile(iconPath); - icon.textureId = ImTextureID(texture); - - icon.ebootPath = entry.path() / "eboot.bin"; - if (Core::FileSys::IsZArchiveFile(entry.path())) { - icon.ebootPath = entry.path(); - } - - icon.focusState = false; - icons.push_back(icon); - } + scanFolder(icons, installLoc.path, 0); } } diff --git a/src/imgui/big_picture/settings_dialog_imgui.cpp b/src/imgui/big_picture/settings_dialog_imgui.cpp index 92bcace50..5a7681ba4 100644 --- a/src/imgui/big_picture/settings_dialog_imgui.cpp +++ b/src/imgui/big_picture/settings_dialog_imgui.cpp @@ -32,8 +32,14 @@ int SettingsWindow::GetComboIndex(std::string selection, std::vectorSize); } + float buttonWidth = ImGui::GetItemRectSize().x; + ImGui::PushItemWidth(buttonWidth); + if (ImGui::SliderInt("Folder Scan Depth", &scanDepthSetting, 0, 5)) { + std::string profile; + const bool isGlobal = currentProfile == "Global"; + if (!isGlobal) { + profile = currentProfile.substr(0, 9); + EmulatorSettings.Load(); + } + + EmulatorSettings.SetBigPictureFolderDepth(scanDepthSetting); + EmulatorSettings.Save(); + + if (!isGlobal) { + EmulatorSettings.Load(profile); + } + + if (!isGameRunning) { + GetProfileInfo(); + } + } + ImGui::PopItemWidth(); + if (ImGuiFileDialog::Instance()->Display("OpenFolder", child_flags | ImGuiWindowFlags_NoMove)) { if (ImGuiFileDialog::Instance()->IsOk()) { GameInstallDir dir; diff --git a/src/imgui/big_picture/settings_dialog_imgui.h b/src/imgui/big_picture/settings_dialog_imgui.h index e98216dc7..0a668c976 100644 --- a/src/imgui/big_picture/settings_dialog_imgui.h +++ b/src/imgui/big_picture/settings_dialog_imgui.h @@ -166,6 +166,9 @@ private: bool pipelineCacheArchiveSetting; int extraDmemSetting; int vblankFrequencySetting; + + // Folders tab + int scanDepthSetting; }; } // namespace ImGuiEmuSettings