mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #4235 from FearlessTobi/port-1259
Port various game_list changes from yuzu
This commit is contained in:
		
						commit
						6742472133
					
				
					 10 changed files with 265 additions and 198 deletions
				
			
		|  | @ -14,6 +14,8 @@ add_executable(citra-qt | |||
|     applets/swkbd.h | ||||
|     bootmanager.cpp | ||||
|     bootmanager.h | ||||
|     compatibility_list.cpp | ||||
|     compatibility_list.h | ||||
|     camera/camera_util.cpp | ||||
|     camera/camera_util.h | ||||
|     camera/still_image_camera.cpp | ||||
|  | @ -76,6 +78,8 @@ add_executable(citra-qt | |||
|     game_list.cpp | ||||
|     game_list.h | ||||
|     game_list_p.h | ||||
|     game_list_worker.cpp | ||||
|     game_list_worker.h | ||||
|     hotkeys.cpp | ||||
|     hotkeys.h | ||||
|     main.cpp | ||||
|  |  | |||
							
								
								
									
										16
									
								
								src/citra_qt/compatibility_list.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/citra_qt/compatibility_list.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| // Copyright 2018 yuzu Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <fmt/format.h> | ||||
| #include "citra_qt/compatibility_list.h" | ||||
| 
 | ||||
| CompatibilityList::const_iterator FindMatchingCompatibilityEntry( | ||||
|     const CompatibilityList& compatibility_list, u64 program_id) { | ||||
|     return std::find_if(compatibility_list.begin(), compatibility_list.end(), | ||||
|                         [program_id](const auto& element) { | ||||
|                             std::string pid = fmt::format("{:016X}", program_id); | ||||
|                             return element.first == pid; | ||||
|                         }); | ||||
| } | ||||
							
								
								
									
										15
									
								
								src/citra_qt/compatibility_list.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/citra_qt/compatibility_list.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| // Copyright 2018 yuzu Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <string> | ||||
| #include <unordered_map> | ||||
| #include <QString> | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| using CompatibilityList = std::unordered_map<std::string, std::pair<QString, QString>>; | ||||
| 
 | ||||
| CompatibilityList::const_iterator FindMatchingCompatibilityEntry( | ||||
|     const CompatibilityList& compatibility_list, u64 program_id); | ||||
|  | @ -21,8 +21,10 @@ | |||
| #include <QToolButton> | ||||
| #include <QTreeView> | ||||
| #include <fmt/format.h> | ||||
| #include "citra_qt/compatibility_list.h" | ||||
| #include "citra_qt/game_list.h" | ||||
| #include "citra_qt/game_list_p.h" | ||||
| #include "citra_qt/game_list_worker.h" | ||||
| #include "citra_qt/main.h" | ||||
| #include "citra_qt/ui_settings.h" | ||||
| #include "common/common_paths.h" | ||||
|  | @ -30,7 +32,6 @@ | |||
| #include "core/file_sys/archive_extsavedata.h" | ||||
| #include "core/file_sys/archive_source_sd_savedata.h" | ||||
| #include "core/hle/service/fs/archive.h" | ||||
| #include "core/loader/loader.h" | ||||
| 
 | ||||
| GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {} | ||||
| 
 | ||||
|  | @ -648,11 +649,6 @@ void GameList::LoadInterfaceLayout() { | |||
| const QStringList GameList::supported_file_extensions = {"3ds", "3dsx", "elf", "axf", | ||||
|                                                          "cci", "cxi",  "app"}; | ||||
| 
 | ||||
| static bool HasSupportedFileExtension(const std::string& file_name) { | ||||
|     QFileInfo file = QFileInfo(QString::fromStdString(file_name)); | ||||
|     return GameList::supported_file_extensions.contains(file.suffix(), Qt::CaseInsensitive); | ||||
| } | ||||
| 
 | ||||
| void GameList::RefreshGameDirectory() { | ||||
|     if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) { | ||||
|         LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); | ||||
|  | @ -678,123 +674,6 @@ QString GameList::FindGameByProgramID(QStandardItem* current_item, u64 program_i | |||
|     return ""; | ||||
| } | ||||
| 
 | ||||
| void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion, | ||||
|                                              GameListDir* parent_dir) { | ||||
|     const auto callback = [this, recursion, parent_dir](u64* num_entries_out, | ||||
|                                                         const std::string& directory, | ||||
|                                                         const std::string& virtual_name) -> bool { | ||||
|         std::string physical_name = directory + DIR_SEP + virtual_name; | ||||
| 
 | ||||
|         if (stop_processing) | ||||
|             return false; // Breaks the callback loop.
 | ||||
| 
 | ||||
|         bool is_dir = FileUtil::IsDirectory(physical_name); | ||||
|         if (!is_dir && HasSupportedFileExtension(physical_name)) { | ||||
|             std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(physical_name); | ||||
|             if (!loader) | ||||
|                 return true; | ||||
| 
 | ||||
|             u64 program_id = 0; | ||||
|             loader->ReadProgramId(program_id); | ||||
| 
 | ||||
|             u64 extdata_id = 0; | ||||
|             loader->ReadExtdataId(extdata_id); | ||||
| 
 | ||||
|             std::vector<u8> smdh = [program_id, &loader]() -> std::vector<u8> { | ||||
|                 std::vector<u8> original_smdh; | ||||
|                 loader->ReadIcon(original_smdh); | ||||
| 
 | ||||
|                 if (program_id < 0x0004000000000000 || program_id > 0x00040000FFFFFFFF) | ||||
|                     return original_smdh; | ||||
| 
 | ||||
|                 std::string update_path = Service::AM::GetTitleContentPath( | ||||
|                     Service::FS::MediaType::SDMC, program_id + 0x0000000E00000000); | ||||
| 
 | ||||
|                 if (!FileUtil::Exists(update_path)) | ||||
|                     return original_smdh; | ||||
| 
 | ||||
|                 std::unique_ptr<Loader::AppLoader> update_loader = Loader::GetLoader(update_path); | ||||
| 
 | ||||
|                 if (!update_loader) | ||||
|                     return original_smdh; | ||||
| 
 | ||||
|                 std::vector<u8> update_smdh; | ||||
|                 update_loader->ReadIcon(update_smdh); | ||||
|                 return update_smdh; | ||||
|             }(); | ||||
| 
 | ||||
|             if (!Loader::IsValidSMDH(smdh) && UISettings::values.game_list_hide_no_icon) { | ||||
|                 // Skip this invalid entry
 | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); | ||||
| 
 | ||||
|             // The game list uses this as compatibility number for untested games
 | ||||
|             QString compatibility("99"); | ||||
|             if (it != compatibility_list.end()) | ||||
|                 compatibility = it->second.first; | ||||
| 
 | ||||
|             emit EntryReady( | ||||
|                 { | ||||
|                     new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id, | ||||
|                                          extdata_id), | ||||
|                     new GameListItemCompat(compatibility), | ||||
|                     new GameListItemRegion(smdh), | ||||
|                     new GameListItem( | ||||
|                         QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), | ||||
|                     new GameListItemSize(FileUtil::GetSize(physical_name)), | ||||
|                 }, | ||||
|                 parent_dir); | ||||
| 
 | ||||
|         } else if (is_dir && recursion > 0) { | ||||
|             watch_list.append(QString::fromStdString(physical_name)); | ||||
|             AddFstEntriesToGameList(physical_name, recursion - 1, parent_dir); | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
|     }; | ||||
| 
 | ||||
|     FileUtil::ForeachDirectoryEntry(nullptr, dir_path, callback); | ||||
| } | ||||
| 
 | ||||
| void GameListWorker::run() { | ||||
|     stop_processing = false; | ||||
|     for (UISettings::GameDir& game_dir : game_dirs) { | ||||
|         if (game_dir.path == "INSTALLED") { | ||||
|             QString path = | ||||
|                 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)) + | ||||
|                 "Nintendo " | ||||
|                 "3DS/00000000000000000000000000000000/" | ||||
|                 "00000000000000000000000000000000/title/00040000"; | ||||
|             watch_list.append(path); | ||||
|             GameListDir* game_list_dir = new GameListDir(game_dir, GameListItemType::InstalledDir); | ||||
|             emit DirEntryReady({game_list_dir}); | ||||
|             AddFstEntriesToGameList(path.toStdString(), 2, game_list_dir); | ||||
|         } else if (game_dir.path == "SYSTEM") { | ||||
|             QString path = | ||||
|                 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)) + | ||||
|                 "00000000000000000000000000000000/title/00040010"; | ||||
|             watch_list.append(path); | ||||
|             GameListDir* game_list_dir = new GameListDir(game_dir, GameListItemType::SystemDir); | ||||
|             emit DirEntryReady({game_list_dir}); | ||||
|             AddFstEntriesToGameList(path.toStdString(), 2, game_list_dir); | ||||
|         } else { | ||||
|             watch_list.append(game_dir.path); | ||||
|             GameListDir* game_list_dir = new GameListDir(game_dir); | ||||
|             emit DirEntryReady({game_list_dir}); | ||||
|             AddFstEntriesToGameList(game_dir.path.toStdString(), game_dir.deep_scan ? 256 : 0, | ||||
|                                     game_list_dir); | ||||
|         } | ||||
|     }; | ||||
|     emit Finished(watch_list); | ||||
| } | ||||
| 
 | ||||
| void GameListWorker::Cancel() { | ||||
|     this->disconnect(); | ||||
|     stop_processing = true; | ||||
| } | ||||
| 
 | ||||
| GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent} { | ||||
|     this->main_window = parent; | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,9 +4,10 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <unordered_map> | ||||
| #include <QMenu> | ||||
| #include <QString> | ||||
| #include <QWidget> | ||||
| #include "citra_qt/compatibility_list.h" | ||||
| #include "common/common_types.h" | ||||
| #include "ui_settings.h" | ||||
| 
 | ||||
|  | @ -70,9 +71,8 @@ signals: | |||
|     void GameChosen(QString game_path); | ||||
|     void ShouldCancelWorker(); | ||||
|     void OpenFolderRequested(u64 program_id, GameListOpenTarget target); | ||||
|     void NavigateToGamedbEntryRequested( | ||||
|         u64 program_id, | ||||
|         std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list); | ||||
|     void NavigateToGamedbEntryRequested(u64 program_id, | ||||
|                                         const CompatibilityList& compatibility_list); | ||||
|     void OpenDirectory(QString directory); | ||||
|     void AddDirectory(); | ||||
|     void ShowList(bool show); | ||||
|  | @ -103,7 +103,7 @@ private: | |||
|     QStandardItemModel* item_model = nullptr; | ||||
|     GameListWorker* current_worker = nullptr; | ||||
|     QFileSystemWatcher* watcher = nullptr; | ||||
|     std::unordered_map<std::string, std::pair<QString, QString>> compatibility_list; | ||||
|     CompatibilityList compatibility_list; | ||||
| 
 | ||||
|     friend class GameListSearchField; | ||||
| }; | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <atomic> | ||||
| #include <map> | ||||
| #include <unordered_map> | ||||
| #include <utility> | ||||
|  | @ -59,17 +58,6 @@ static QPixmap GetDefaultIcon(bool large) { | |||
|     return icon; | ||||
| } | ||||
| 
 | ||||
| static auto FindMatchingCompatibilityEntry( | ||||
|     const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list, | ||||
|     u64 program_id) { | ||||
|     return std::find_if( | ||||
|         compatibility_list.begin(), compatibility_list.end(), | ||||
|         [program_id](const std::pair<std::string, std::pair<QString, QString>>& element) { | ||||
|             std::string pid = fmt::format("{:016X}", program_id); | ||||
|             return element.first == pid; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets the short game title from SMDH data. | ||||
|  * @param smdh SMDH data | ||||
|  | @ -216,7 +204,7 @@ class GameListItemCompat : public GameListItem { | |||
| public: | ||||
|     static const int CompatNumberRole = SortRole; | ||||
|     GameListItemCompat() = default; | ||||
|     explicit GameListItemCompat(const QString& compatiblity) { | ||||
|     explicit GameListItemCompat(const QString& compatibility) { | ||||
|         setData(type(), TypeRole); | ||||
| 
 | ||||
|         struct CompatStatus { | ||||
|  | @ -235,13 +223,13 @@ public: | |||
|         {"99", {"#000000", QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}}; | ||||
|         // clang-format on
 | ||||
| 
 | ||||
|         auto iterator = status_data.find(compatiblity); | ||||
|         auto iterator = status_data.find(compatibility); | ||||
|         if (iterator == status_data.end()) { | ||||
|             LOG_WARNING(Frontend, "Invalid compatibility number {}", compatiblity.toStdString()); | ||||
|             LOG_WARNING(Frontend, "Invalid compatibility number {}", compatibility.toStdString()); | ||||
|             return; | ||||
|         } | ||||
|         CompatStatus status = iterator->second; | ||||
|         setData(compatiblity, CompatNumberRole); | ||||
|         const CompatStatus& status = iterator->second; | ||||
|         setData(compatibility, CompatNumberRole); | ||||
|         setText(QObject::tr(status.text)); | ||||
|         setToolTip(QObject::tr(status.tooltip)); | ||||
|         setData(CreateCirclePixmapFromColor(status.color), Qt::DecorationRole); | ||||
|  | @ -373,51 +361,6 @@ public: | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Asynchronous worker object for populating the game list. | ||||
|  * Communicates with other threads through Qt's signal/slot system. | ||||
|  */ | ||||
| class GameListWorker : public QObject, public QRunnable { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|     explicit GameListWorker( | ||||
|         QList<UISettings::GameDir>& game_dirs, | ||||
|         const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list) | ||||
|         : game_dirs(game_dirs), compatibility_list(compatibility_list) {} | ||||
| 
 | ||||
| public slots: | ||||
|     /// Starts the processing of directory tree information.
 | ||||
|     void run() override; | ||||
|     /// Tells the worker that it should no longer continue processing. Thread-safe.
 | ||||
|     void Cancel(); | ||||
| 
 | ||||
| signals: | ||||
|     /**
 | ||||
|      * The `EntryReady` signal is emitted once an entry has been prepared and is ready | ||||
|      * to be added to the game list. | ||||
|      * @param entry_items a list with `QStandardItem`s that make up the columns of the new | ||||
|      * entry. | ||||
|      */ | ||||
|     void DirEntryReady(GameListDir* entry_items); | ||||
|     void EntryReady(QList<QStandardItem*> entry_items, GameListDir* parent_dir); | ||||
| 
 | ||||
|     /**
 | ||||
|      * After the worker has traversed the game directory looking for entries, this signal is | ||||
|      * emitted with a list of folders that should be watched for changes as well. | ||||
|      */ | ||||
|     void Finished(QStringList watch_list); | ||||
| 
 | ||||
| private: | ||||
|     QStringList watch_list; | ||||
|     const std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list; | ||||
|     QList<UISettings::GameDir>& game_dirs; | ||||
|     std::atomic_bool stop_processing; | ||||
| 
 | ||||
|     void AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion, | ||||
|                                  GameListDir* parent_dir); | ||||
| }; | ||||
| 
 | ||||
| class GameList; | ||||
| class QHBoxLayout; | ||||
| class QTreeView; | ||||
|  |  | |||
							
								
								
									
										150
									
								
								src/citra_qt/game_list_worker.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/citra_qt/game_list_worker.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,150 @@ | |||
| // Copyright 2018 yuzu emulator team
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include <QDir> | ||||
| #include <QFileInfo> | ||||
| #include "citra_qt/compatibility_list.h" | ||||
| #include "citra_qt/game_list.h" | ||||
| #include "citra_qt/game_list_p.h" | ||||
| #include "citra_qt/game_list_worker.h" | ||||
| #include "citra_qt/ui_settings.h" | ||||
| #include "common/common_paths.h" | ||||
| #include "common/file_util.h" | ||||
| #include "core/hle/service/am/am.h" | ||||
| #include "core/hle/service/fs/archive.h" | ||||
| #include "core/loader/loader.h" | ||||
| 
 | ||||
| namespace { | ||||
| bool HasSupportedFileExtension(const std::string& file_name) { | ||||
|     const QFileInfo file = QFileInfo(QString::fromStdString(file_name)); | ||||
|     return GameList::supported_file_extensions.contains(file.suffix(), Qt::CaseInsensitive); | ||||
| } | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| GameListWorker::GameListWorker(QList<UISettings::GameDir>& game_dirs, | ||||
|                                const CompatibilityList& compatibility_list) | ||||
|     : game_dirs(game_dirs), compatibility_list(compatibility_list) {} | ||||
| 
 | ||||
| GameListWorker::~GameListWorker() = default; | ||||
| 
 | ||||
| void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion, | ||||
|                                              GameListDir* parent_dir) { | ||||
|     const auto callback = [this, recursion, parent_dir](u64* num_entries_out, | ||||
|                                                         const std::string& directory, | ||||
|                                                         const std::string& virtual_name) -> bool { | ||||
|         std::string physical_name = directory + DIR_SEP + virtual_name; | ||||
| 
 | ||||
|         if (stop_processing) | ||||
|             return false; // Breaks the callback loop.
 | ||||
| 
 | ||||
|         bool is_dir = FileUtil::IsDirectory(physical_name); | ||||
|         if (!is_dir && HasSupportedFileExtension(physical_name)) { | ||||
|             std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(physical_name); | ||||
|             if (!loader) | ||||
|                 return true; | ||||
| 
 | ||||
|             u64 program_id = 0; | ||||
|             loader->ReadProgramId(program_id); | ||||
| 
 | ||||
|             u64 extdata_id = 0; | ||||
|             loader->ReadExtdataId(extdata_id); | ||||
| 
 | ||||
|             std::vector<u8> smdh = [program_id, &loader]() -> std::vector<u8> { | ||||
|                 std::vector<u8> original_smdh; | ||||
|                 loader->ReadIcon(original_smdh); | ||||
| 
 | ||||
|                 if (program_id < 0x0004000000000000 || program_id > 0x00040000FFFFFFFF) | ||||
|                     return original_smdh; | ||||
| 
 | ||||
|                 std::string update_path = Service::AM::GetTitleContentPath( | ||||
|                     Service::FS::MediaType::SDMC, program_id + 0x0000000E00000000); | ||||
| 
 | ||||
|                 if (!FileUtil::Exists(update_path)) | ||||
|                     return original_smdh; | ||||
| 
 | ||||
|                 std::unique_ptr<Loader::AppLoader> update_loader = Loader::GetLoader(update_path); | ||||
| 
 | ||||
|                 if (!update_loader) | ||||
|                     return original_smdh; | ||||
| 
 | ||||
|                 std::vector<u8> update_smdh; | ||||
|                 update_loader->ReadIcon(update_smdh); | ||||
|                 return update_smdh; | ||||
|             }(); | ||||
| 
 | ||||
|             if (!Loader::IsValidSMDH(smdh) && UISettings::values.game_list_hide_no_icon) { | ||||
|                 // Skip this invalid entry
 | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); | ||||
| 
 | ||||
|             // The game list uses this as compatibility number for untested games
 | ||||
|             QString compatibility("99"); | ||||
|             if (it != compatibility_list.end()) | ||||
|                 compatibility = it->second.first; | ||||
| 
 | ||||
|             emit EntryReady( | ||||
|                 { | ||||
|                     new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id, | ||||
|                                          extdata_id), | ||||
|                     new GameListItemCompat(compatibility), | ||||
|                     new GameListItemRegion(smdh), | ||||
|                     new GameListItem( | ||||
|                         QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), | ||||
|                     new GameListItemSize(FileUtil::GetSize(physical_name)), | ||||
|                 }, | ||||
|                 parent_dir); | ||||
| 
 | ||||
|         } else if (is_dir && recursion > 0) { | ||||
|             watch_list.append(QString::fromStdString(physical_name)); | ||||
|             AddFstEntriesToGameList(physical_name, recursion - 1, parent_dir); | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
|     }; | ||||
| 
 | ||||
|     FileUtil::ForeachDirectoryEntry(nullptr, dir_path, callback); | ||||
| } | ||||
| 
 | ||||
| void GameListWorker::run() { | ||||
|     stop_processing = false; | ||||
|     for (UISettings::GameDir& game_dir : game_dirs) { | ||||
|         if (game_dir.path == "INSTALLED") { | ||||
|             QString path = | ||||
|                 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)) + | ||||
|                 "Nintendo " | ||||
|                 "3DS/00000000000000000000000000000000/" | ||||
|                 "00000000000000000000000000000000/title/00040000"; | ||||
|             watch_list.append(path); | ||||
|             GameListDir* game_list_dir = new GameListDir(game_dir, GameListItemType::InstalledDir); | ||||
|             emit DirEntryReady({game_list_dir}); | ||||
|             AddFstEntriesToGameList(path.toStdString(), 2, game_list_dir); | ||||
|         } else if (game_dir.path == "SYSTEM") { | ||||
|             QString path = | ||||
|                 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)) + | ||||
|                 "00000000000000000000000000000000/title/00040010"; | ||||
|             watch_list.append(path); | ||||
|             GameListDir* game_list_dir = new GameListDir(game_dir, GameListItemType::SystemDir); | ||||
|             emit DirEntryReady({game_list_dir}); | ||||
|             AddFstEntriesToGameList(path.toStdString(), 2, game_list_dir); | ||||
|         } else { | ||||
|             watch_list.append(game_dir.path); | ||||
|             GameListDir* game_list_dir = new GameListDir(game_dir); | ||||
|             emit DirEntryReady({game_list_dir}); | ||||
|             AddFstEntriesToGameList(game_dir.path.toStdString(), game_dir.deep_scan ? 256 : 0, | ||||
|                                     game_list_dir); | ||||
|         } | ||||
|     }; | ||||
|     emit Finished(watch_list); | ||||
| } | ||||
| 
 | ||||
| void GameListWorker::Cancel() { | ||||
|     this->disconnect(); | ||||
|     stop_processing = true; | ||||
| } | ||||
							
								
								
									
										62
									
								
								src/citra_qt/game_list_worker.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/citra_qt/game_list_worker.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | |||
| // Copyright 2018 yuzu emulator team
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <atomic> | ||||
| #include <map> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <unordered_map> | ||||
| #include <QList> | ||||
| #include <QObject> | ||||
| #include <QRunnable> | ||||
| #include <QString> | ||||
| #include "citra_qt/compatibility_list.h" | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| class QStandardItem; | ||||
| 
 | ||||
| /**
 | ||||
|  * Asynchronous worker object for populating the game list. | ||||
|  * Communicates with other threads through Qt's signal/slot system. | ||||
|  */ | ||||
| class GameListWorker : public QObject, public QRunnable { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|     GameListWorker(QList<UISettings::GameDir>& game_dirs, | ||||
|                    const CompatibilityList& compatibility_list); | ||||
|     ~GameListWorker() override; | ||||
| 
 | ||||
|     /// Starts the processing of directory tree information.
 | ||||
|     void run() override; | ||||
| 
 | ||||
|     /// Tells the worker that it should no longer continue processing. Thread-safe.
 | ||||
|     void Cancel(); | ||||
| 
 | ||||
| signals: | ||||
|     /**
 | ||||
|      * The `EntryReady` signal is emitted once an entry has been prepared and is ready | ||||
|      * to be added to the game list. | ||||
|      * @param entry_items a list with `QStandardItem`s that make up the columns of the new entry. | ||||
|      */ | ||||
|     void DirEntryReady(GameListDir* entry_items); | ||||
|     void EntryReady(QList<QStandardItem*> entry_items, GameListDir* parent_dir); | ||||
| 
 | ||||
|     /**
 | ||||
|      * After the worker has traversed the game directory looking for entries, this signal is emitted | ||||
|      * with a list of folders that should be watched for changes as well. | ||||
|      */ | ||||
|     void Finished(QStringList watch_list); | ||||
| 
 | ||||
| private: | ||||
|     void AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion, | ||||
|                                  GameListDir* parent_dir); | ||||
| 
 | ||||
|     QStringList watch_list; | ||||
|     const CompatibilityList& compatibility_list; | ||||
|     QList<UISettings::GameDir>& game_dirs; | ||||
|     std::atomic_bool stop_processing; | ||||
| }; | ||||
|  | @ -21,6 +21,7 @@ | |||
| #include "citra_qt/camera/qt_multimedia_camera.h" | ||||
| #include "citra_qt/camera/still_image_camera.h" | ||||
| #include "citra_qt/compatdb.h" | ||||
| #include "citra_qt/compatibility_list.h" | ||||
| #include "citra_qt/configuration/config.h" | ||||
| #include "citra_qt/configuration/configure_dialog.h" | ||||
| #include "citra_qt/debugger/console.h" | ||||
|  | @ -960,14 +961,11 @@ void GMainWindow::OnGameListOpenFolder(u64 data_id, GameListOpenTarget target) { | |||
|     QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::OnGameListNavigateToGamedbEntry( | ||||
|     u64 program_id, | ||||
|     std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list) { | ||||
| 
 | ||||
| void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, | ||||
|                                                   const CompatibilityList& compatibility_list) { | ||||
|     auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); | ||||
| 
 | ||||
|     QString directory; | ||||
| 
 | ||||
|     if (it != compatibility_list.end()) | ||||
|         directory = it->second.second; | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include <QMainWindow> | ||||
| #include <QTimer> | ||||
| #include <QTranslator> | ||||
| #include "citra_qt/compatibility_list.h" | ||||
| #include "citra_qt/hotkeys.h" | ||||
| #include "common/announce_multiplayer_room.h" | ||||
| #include "core/core.h" | ||||
|  | @ -153,9 +154,8 @@ private slots: | |||
|     /// Called whenever a user selects a game in the game list widget.
 | ||||
|     void OnGameListLoadFile(QString game_path); | ||||
|     void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); | ||||
|     void OnGameListNavigateToGamedbEntry( | ||||
|         u64 program_id, | ||||
|         std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list); | ||||
|     void OnGameListNavigateToGamedbEntry(u64 program_id, | ||||
|                                          const CompatibilityList& compatibility_list); | ||||
|     void OnGameListOpenDirectory(QString path); | ||||
|     void OnGameListAddDirectory(); | ||||
|     void OnGameListShowList(bool show); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue