diff options
25 files changed, 491 insertions, 21 deletions
diff --git a/CMakeModules/CopyYuzuQt5Deps.cmake b/CMakeModules/CopyYuzuQt5Deps.cmake index e4a9796c8..aaf80b77b 100644 --- a/CMakeModules/CopyYuzuQt5Deps.cmake +++ b/CMakeModules/CopyYuzuQt5Deps.cmake | |||
| @@ -4,8 +4,10 @@ function(copy_yuzu_Qt5_deps target_dir) | |||
| 4 | set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin") | 4 | set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin") |
| 5 | set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") | 5 | set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") |
| 6 | set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") | 6 | set(Qt5_STYLES_DIR "${Qt5_DIR}/../../../plugins/styles/") |
| 7 | set(Qt5_IMAGEFORMATS_DIR "${Qt5_DIR}/../../../plugins/imageformats/") | ||
| 7 | set(PLATFORMS ${DLL_DEST}platforms/) | 8 | set(PLATFORMS ${DLL_DEST}platforms/) |
| 8 | set(STYLES ${DLL_DEST}styles/) | 9 | set(STYLES ${DLL_DEST}styles/) |
| 10 | set(IMAGEFORMATS ${DLL_DEST}imageformats/) | ||
| 9 | windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST} | 11 | windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST} |
| 10 | icudt*.dll | 12 | icudt*.dll |
| 11 | icuin*.dll | 13 | icuin*.dll |
| @@ -17,4 +19,5 @@ function(copy_yuzu_Qt5_deps target_dir) | |||
| 17 | ) | 19 | ) |
| 18 | windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*) | 20 | windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*) |
| 19 | windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*) | 21 | windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*) |
| 22 | windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*) | ||
| 20 | endfunction(copy_yuzu_Qt5_deps) | 23 | endfunction(copy_yuzu_Qt5_deps) |
diff --git a/appveyor.yml b/appveyor.yml index 17d1b5fee..a6f12b267 100644 --- a/appveyor.yml +++ b/appveyor.yml | |||
| @@ -117,6 +117,7 @@ after_build: | |||
| 117 | mkdir $RELEASE_DIST | 117 | mkdir $RELEASE_DIST |
| 118 | mkdir $RELEASE_DIST/platforms | 118 | mkdir $RELEASE_DIST/platforms |
| 119 | mkdir $RELEASE_DIST/styles | 119 | mkdir $RELEASE_DIST/styles |
| 120 | mkdir $RELEASE_DIST/imageformats | ||
| 120 | 121 | ||
| 121 | # copy the compiled binaries and other release files to the release folder | 122 | # copy the compiled binaries and other release files to the release folder |
| 122 | Get-ChildItem "$CMAKE_BINARY_DIR" -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST | 123 | Get-ChildItem "$CMAKE_BINARY_DIR" -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST |
| @@ -140,6 +141,9 @@ after_build: | |||
| 140 | # copy the qt windows vista style dll to platforms | 141 | # copy the qt windows vista style dll to platforms |
| 141 | Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/styles/qwindowsvistastyle.dll" -force -destination "$RELEASE_DIST/styles" | 142 | Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/styles/qwindowsvistastyle.dll" -force -destination "$RELEASE_DIST/styles" |
| 142 | 143 | ||
| 144 | # copy the qt jpeg imageformat dll to platforms | ||
| 145 | Copy-Item -path "C:/msys64/mingw64/share/qt5/plugins/imageformats/qjpeg.dll" -force -destination "$RELEASE_DIST/imageformats" | ||
| 146 | |||
| 143 | 7z a -tzip $MINGW_BUILD_ZIP $RELEASE_DIST\* | 147 | 7z a -tzip $MINGW_BUILD_ZIP $RELEASE_DIST\* |
| 144 | 7z a $MINGW_SEVENZIP $RELEASE_DIST | 148 | 7z a $MINGW_SEVENZIP $RELEASE_DIST |
| 145 | } | 149 | } |
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 395eea8ae..e897d9913 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <array> | 5 | #include <array> |
| 6 | #include <string> | 6 | #include <string> |
| 7 | #include <core/loader/loader.h> | 7 | #include <core/loader/loader.h> |
| 8 | #include "common/logging/log.h" | ||
| 8 | #include "core/file_sys/card_image.h" | 9 | #include "core/file_sys/card_image.h" |
| 9 | #include "core/file_sys/partition_filesystem.h" | 10 | #include "core/file_sys/partition_filesystem.h" |
| 10 | #include "core/file_sys/vfs_offset.h" | 11 | #include "core/file_sys/vfs_offset.h" |
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 3529166ac..d3007d981 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp | |||
| @@ -170,6 +170,10 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting | |||
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | NCA::NCA(VirtualFile file_) : file(std::move(file_)) { | 172 | NCA::NCA(VirtualFile file_) : file(std::move(file_)) { |
| 173 | if (file == nullptr) { | ||
| 174 | status = Loader::ResultStatus::ErrorInvalidFormat; | ||
| 175 | return; | ||
| 176 | } | ||
| 173 | if (sizeof(NCAHeader) != file->ReadObject(&header)) | 177 | if (sizeof(NCAHeader) != file->ReadObject(&header)) |
| 174 | LOG_ERROR(Loader, "File reader errored out during header read."); | 178 | LOG_ERROR(Loader, "File reader errored out during header read."); |
| 175 | 179 | ||
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index a8879d9a8..5cfd5031a 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "common/common_funcs.h" | 12 | #include "common/common_funcs.h" |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/swap.h" | 14 | #include "common/swap.h" |
| 15 | #include "control_metadata.h" | ||
| 15 | #include "core/crypto/key_manager.h" | 16 | #include "core/crypto/key_manager.h" |
| 16 | #include "core/file_sys/partition_filesystem.h" | 17 | #include "core/file_sys/partition_filesystem.h" |
| 17 | #include "core/loader/loader.h" | 18 | #include "core/loader/loader.h" |
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index cc3b745f7..6582cc240 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h | |||
| @@ -62,6 +62,13 @@ enum class Language : u8 { | |||
| 62 | Chinese = 14, | 62 | Chinese = 14, |
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| 65 | static constexpr std::array<const char*, 15> LANGUAGE_NAMES = { | ||
| 66 | "AmericanEnglish", "BritishEnglish", "Japanese", | ||
| 67 | "French", "German", "LatinAmericanSpanish", | ||
| 68 | "Spanish", "Italian", "Dutch", | ||
| 69 | "CanadianFrench", "Portugese", "Russian", | ||
| 70 | "Korean", "Taiwanese", "Chinese"}; | ||
| 71 | |||
| 65 | // A class representing the format used by NX metadata files, typically named Control.nacp. | 72 | // A class representing the format used by NX metadata files, typically named Control.nacp. |
| 66 | // These store application name, dev name, title id, and other miscellaneous data. | 73 | // These store application name, dev name, title id, and other miscellaneous data. |
| 67 | class NACP { | 74 | class NACP { |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 9a8cdd0ff..915d525b0 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "common/file_util.h" | 7 | #include "common/file_util.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/file_sys/content_archive.h" | 9 | #include "core/file_sys/content_archive.h" |
| 10 | #include "core/file_sys/control_metadata.h" | ||
| 10 | #include "core/gdbstub/gdbstub.h" | 11 | #include "core/gdbstub/gdbstub.h" |
| 11 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
| 12 | #include "core/hle/kernel/resource_limit.h" | 13 | #include "core/hle/kernel/resource_limit.h" |
| @@ -17,8 +18,50 @@ | |||
| 17 | 18 | ||
| 18 | namespace Loader { | 19 | namespace Loader { |
| 19 | 20 | ||
| 20 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file) | 21 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_) |
| 21 | : AppLoader(std::move(file)) {} | 22 | : AppLoader(std::move(file_)) { |
| 23 | const auto dir = file->GetContainingDirectory(); | ||
| 24 | |||
| 25 | // Icon | ||
| 26 | FileSys::VirtualFile icon_file = nullptr; | ||
| 27 | for (const auto& language : FileSys::LANGUAGE_NAMES) { | ||
| 28 | icon_file = dir->GetFile("icon_" + std::string(language) + ".dat"); | ||
| 29 | if (icon_file != nullptr) { | ||
| 30 | icon_data = icon_file->ReadAllBytes(); | ||
| 31 | break; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | if (icon_data.empty()) { | ||
| 36 | // Any png, jpeg, or bmp file | ||
| 37 | const auto& files = dir->GetFiles(); | ||
| 38 | const auto icon_iter = | ||
| 39 | std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { | ||
| 40 | return file->GetExtension() == "png" || file->GetExtension() == "jpg" || | ||
| 41 | file->GetExtension() == "bmp" || file->GetExtension() == "jpeg"; | ||
| 42 | }); | ||
| 43 | if (icon_iter != files.end()) | ||
| 44 | icon_data = (*icon_iter)->ReadAllBytes(); | ||
| 45 | } | ||
| 46 | |||
| 47 | // Metadata | ||
| 48 | FileSys::VirtualFile nacp_file = dir->GetFile("control.nacp"); | ||
| 49 | if (nacp_file == nullptr) { | ||
| 50 | const auto& files = dir->GetFiles(); | ||
| 51 | const auto nacp_iter = | ||
| 52 | std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { | ||
| 53 | return file->GetExtension() == "nacp"; | ||
| 54 | }); | ||
| 55 | if (nacp_iter != files.end()) | ||
| 56 | nacp_file = *nacp_iter; | ||
| 57 | } | ||
| 58 | |||
| 59 | if (nacp_file != nullptr) { | ||
| 60 | FileSys::NACP nacp(nacp_file); | ||
| 61 | title_id = nacp.GetTitleId(); | ||
| 62 | name = nacp.GetApplicationName(); | ||
| 63 | } | ||
| 64 | } | ||
| 22 | 65 | ||
| 23 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory( | 66 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory( |
| 24 | FileSys::VirtualDir directory) | 67 | FileSys::VirtualDir directory) |
| @@ -105,4 +148,25 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile | |||
| 105 | return ResultStatus::Success; | 148 | return ResultStatus::Success; |
| 106 | } | 149 | } |
| 107 | 150 | ||
| 151 | ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) { | ||
| 152 | if (icon_data.empty()) | ||
| 153 | return ResultStatus::ErrorNotUsed; | ||
| 154 | buffer = icon_data; | ||
| 155 | return ResultStatus::Success; | ||
| 156 | } | ||
| 157 | |||
| 158 | ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) { | ||
| 159 | if (name.empty()) | ||
| 160 | return ResultStatus::ErrorNotUsed; | ||
| 161 | out_program_id = title_id; | ||
| 162 | return ResultStatus::Success; | ||
| 163 | } | ||
| 164 | |||
| 165 | ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) { | ||
| 166 | if (name.empty()) | ||
| 167 | return ResultStatus::ErrorNotUsed; | ||
| 168 | title = name; | ||
| 169 | return ResultStatus::Success; | ||
| 170 | } | ||
| 171 | |||
| 108 | } // namespace Loader | 172 | } // namespace Loader |
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 7d5433563..b20804f75 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h | |||
| @@ -39,11 +39,18 @@ public: | |||
| 39 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 39 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; |
| 40 | 40 | ||
| 41 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 41 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 42 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | ||
| 43 | ResultStatus ReadProgramId(u64& out_program_id) override; | ||
| 44 | ResultStatus ReadTitle(std::string& title) override; | ||
| 42 | 45 | ||
| 43 | private: | 46 | private: |
| 44 | FileSys::ProgramMetadata metadata; | 47 | FileSys::ProgramMetadata metadata; |
| 45 | FileSys::VirtualFile romfs; | 48 | FileSys::VirtualFile romfs; |
| 46 | FileSys::VirtualDir dir; | 49 | FileSys::VirtualDir dir; |
| 50 | |||
| 51 | std::vector<u8> icon_data; | ||
| 52 | std::string name; | ||
| 53 | u64 title_id{}; | ||
| 47 | }; | 54 | }; |
| 48 | 55 | ||
| 49 | } // namespace Loader | 56 | } // namespace Loader |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 57e6c0365..0781fb8c1 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -68,7 +68,7 @@ FileType GuessFromFilename(const std::string& name) { | |||
| 68 | return FileType::Unknown; | 68 | return FileType::Unknown; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | const char* GetFileTypeString(FileType type) { | 71 | std::string GetFileTypeString(FileType type) { |
| 72 | switch (type) { | 72 | switch (type) { |
| 73 | case FileType::ELF: | 73 | case FileType::ELF: |
| 74 | return "ELF"; | 74 | return "ELF"; |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index e69ab85ef..7bd0adedb 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -61,7 +61,7 @@ FileType GuessFromFilename(const std::string& name); | |||
| 61 | /** | 61 | /** |
| 62 | * Convert a FileType into a string which can be displayed to the user. | 62 | * Convert a FileType into a string which can be displayed to the user. |
| 63 | */ | 63 | */ |
| 64 | const char* GetFileTypeString(FileType type); | 64 | std::string GetFileTypeString(FileType type); |
| 65 | 65 | ||
| 66 | /// Return type for functions in Loader namespace | 66 | /// Return type for functions in Loader namespace |
| 67 | enum class ResultStatus { | 67 | enum class ResultStatus { |
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index dbc67c0b5..46f5cd393 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp | |||
| @@ -77,8 +77,8 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { | |||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { | 79 | ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { |
| 80 | if (nca == nullptr) | 80 | if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) |
| 81 | return ResultStatus::ErrorNotLoaded; | 81 | return ResultStatus::ErrorInvalidFormat; |
| 82 | out_program_id = nca->GetTitleId(); | 82 | out_program_id = nca->GetTitleId(); |
| 83 | return ResultStatus::Success; | 83 | return ResultStatus::Success; |
| 84 | } | 84 | } |
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 0fd2d0417..7f7d8ea0b 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h | |||
| @@ -33,7 +33,6 @@ public: | |||
| 33 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 33 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; |
| 34 | 34 | ||
| 35 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 35 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 36 | |||
| 37 | ResultStatus ReadProgramId(u64& out_program_id) override; | 36 | ResultStatus ReadProgramId(u64& out_program_id) override; |
| 38 | 37 | ||
| 39 | ~AppLoader_NCA(); | 38 | ~AppLoader_NCA(); |
| @@ -41,6 +40,7 @@ public: | |||
| 41 | private: | 40 | private: |
| 42 | FileSys::ProgramMetadata metadata; | 41 | FileSys::ProgramMetadata metadata; |
| 43 | 42 | ||
| 43 | FileSys::NCAHeader header; | ||
| 44 | std::unique_ptr<FileSys::NCA> nca; | 44 | std::unique_ptr<FileSys::NCA> nca; |
| 45 | std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader; | 45 | std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader; |
| 46 | }; | 46 | }; |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index eb4dee2c2..d3fe24419 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -26,7 +26,25 @@ namespace Loader { | |||
| 26 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) | 26 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) |
| 27 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), | 27 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), |
| 28 | nca_loader(std::make_unique<AppLoader_NCA>( | 28 | nca_loader(std::make_unique<AppLoader_NCA>( |
| 29 | xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {} | 29 | xci->GetNCAFileByType(FileSys::NCAContentType::Program))) { |
| 30 | if (xci->GetStatus() != ResultStatus::Success) | ||
| 31 | return; | ||
| 32 | const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); | ||
| 33 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) | ||
| 34 | return; | ||
| 35 | const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS()); | ||
| 36 | if (romfs == nullptr) | ||
| 37 | return; | ||
| 38 | for (const auto& language : FileSys::LANGUAGE_NAMES) { | ||
| 39 | icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat"); | ||
| 40 | if (icon_file != nullptr) | ||
| 41 | break; | ||
| 42 | } | ||
| 43 | const auto nacp_raw = romfs->GetFile("control.nacp"); | ||
| 44 | if (nacp_raw == nullptr) | ||
| 45 | return; | ||
| 46 | nacp_file = std::make_shared<FileSys::NACP>(nacp_raw); | ||
| 47 | } | ||
| 30 | 48 | ||
| 31 | AppLoader_XCI::~AppLoader_XCI() = default; | 49 | AppLoader_XCI::~AppLoader_XCI() = default; |
| 32 | 50 | ||
| @@ -71,4 +89,17 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) { | |||
| 71 | return nca_loader->ReadProgramId(out_program_id); | 89 | return nca_loader->ReadProgramId(out_program_id); |
| 72 | } | 90 | } |
| 73 | 91 | ||
| 92 | ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { | ||
| 93 | if (icon_file == nullptr) | ||
| 94 | return ResultStatus::ErrorInvalidFormat; | ||
| 95 | buffer = icon_file->ReadAllBytes(); | ||
| 96 | return ResultStatus::Success; | ||
| 97 | } | ||
| 98 | |||
| 99 | ResultStatus AppLoader_XCI::ReadTitle(std::string& title) { | ||
| 100 | if (nacp_file == nullptr) | ||
| 101 | return ResultStatus::ErrorInvalidFormat; | ||
| 102 | title = nacp_file->GetApplicationName(); | ||
| 103 | return ResultStatus::Success; | ||
| 104 | } | ||
| 74 | } // namespace Loader | 105 | } // namespace Loader |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 0dbcfbdf8..973833050 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -33,12 +33,17 @@ public: | |||
| 33 | 33 | ||
| 34 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 34 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 35 | ResultStatus ReadProgramId(u64& out_program_id) override; | 35 | ResultStatus ReadProgramId(u64& out_program_id) override; |
| 36 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | ||
| 37 | ResultStatus ReadTitle(std::string& title) override; | ||
| 36 | 38 | ||
| 37 | private: | 39 | private: |
| 38 | FileSys::ProgramMetadata metadata; | 40 | FileSys::ProgramMetadata metadata; |
| 39 | 41 | ||
| 40 | std::unique_ptr<FileSys::XCI> xci; | 42 | std::unique_ptr<FileSys::XCI> xci; |
| 41 | std::unique_ptr<AppLoader_NCA> nca_loader; | 43 | std::unique_ptr<AppLoader_NCA> nca_loader; |
| 44 | |||
| 45 | FileSys::VirtualFile icon_file; | ||
| 46 | std::shared_ptr<FileSys::NACP> nacp_file; | ||
| 42 | }; | 47 | }; |
| 43 | 48 | ||
| 44 | } // namespace Loader | 49 | } // namespace Loader |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 475556806..46ed232d8 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -17,6 +17,8 @@ add_executable(yuzu | |||
| 17 | configuration/configure_debug.h | 17 | configuration/configure_debug.h |
| 18 | configuration/configure_dialog.cpp | 18 | configuration/configure_dialog.cpp |
| 19 | configuration/configure_dialog.h | 19 | configuration/configure_dialog.h |
| 20 | configuration/configure_gamelist.cpp | ||
| 21 | configuration/configure_gamelist.h | ||
| 20 | configuration/configure_general.cpp | 22 | configuration/configure_general.cpp |
| 21 | configuration/configure_general.h | 23 | configuration/configure_general.h |
| 22 | configuration/configure_graphics.cpp | 24 | configuration/configure_graphics.cpp |
| @@ -59,6 +61,7 @@ set(UIS | |||
| 59 | configuration/configure.ui | 61 | configuration/configure.ui |
| 60 | configuration/configure_audio.ui | 62 | configuration/configure_audio.ui |
| 61 | configuration/configure_debug.ui | 63 | configuration/configure_debug.ui |
| 64 | configuration/configure_gamelist.ui | ||
| 62 | configuration/configure_general.ui | 65 | configuration/configure_general.ui |
| 63 | configuration/configure_graphics.ui | 66 | configuration/configure_graphics.ui |
| 64 | configuration/configure_input.ui | 67 | configuration/configure_input.ui |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index bf469ee73..0bd46dbac 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -122,6 +122,13 @@ void Config::ReadValues() { | |||
| 122 | qt_config->beginGroup("UI"); | 122 | qt_config->beginGroup("UI"); |
| 123 | UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); | 123 | UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); |
| 124 | 124 | ||
| 125 | qt_config->beginGroup("UIGameList"); | ||
| 126 | UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool(); | ||
| 127 | UISettings::values.icon_size = qt_config->value("icon_size", 48).toUInt(); | ||
| 128 | UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 0).toUInt(); | ||
| 129 | UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 3).toUInt(); | ||
| 130 | qt_config->endGroup(); | ||
| 131 | |||
| 125 | qt_config->beginGroup("UILayout"); | 132 | qt_config->beginGroup("UILayout"); |
| 126 | UISettings::values.geometry = qt_config->value("geometry").toByteArray(); | 133 | UISettings::values.geometry = qt_config->value("geometry").toByteArray(); |
| 127 | UISettings::values.state = qt_config->value("state").toByteArray(); | 134 | UISettings::values.state = qt_config->value("state").toByteArray(); |
| @@ -234,6 +241,13 @@ void Config::SaveValues() { | |||
| 234 | qt_config->beginGroup("UI"); | 241 | qt_config->beginGroup("UI"); |
| 235 | qt_config->setValue("theme", UISettings::values.theme); | 242 | qt_config->setValue("theme", UISettings::values.theme); |
| 236 | 243 | ||
| 244 | qt_config->beginGroup("UIGameList"); | ||
| 245 | qt_config->setValue("show_unknown", UISettings::values.show_unknown); | ||
| 246 | qt_config->setValue("icon_size", UISettings::values.icon_size); | ||
| 247 | qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id); | ||
| 248 | qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id); | ||
| 249 | qt_config->endGroup(); | ||
| 250 | |||
| 237 | qt_config->beginGroup("UILayout"); | 251 | qt_config->beginGroup("UILayout"); |
| 238 | qt_config->setValue("geometry", UISettings::values.geometry); | 252 | qt_config->setValue("geometry", UISettings::values.geometry); |
| 239 | qt_config->setValue("state", UISettings::values.state); | 253 | qt_config->setValue("state", UISettings::values.state); |
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index c8e0b88af..20f120134 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui | |||
| @@ -24,6 +24,11 @@ | |||
| 24 | <string>General</string> | 24 | <string>General</string> |
| 25 | </attribute> | 25 | </attribute> |
| 26 | </widget> | 26 | </widget> |
| 27 | <widget class="ConfigureGameList" name="gameListTab"> | ||
| 28 | <attribute name="title"> | ||
| 29 | <string>Game List</string> | ||
| 30 | </attribute> | ||
| 31 | </widget> | ||
| 27 | <widget class="ConfigureSystem" name="systemTab"> | 32 | <widget class="ConfigureSystem" name="systemTab"> |
| 28 | <attribute name="title"> | 33 | <attribute name="title"> |
| 29 | <string>System</string> | 34 | <string>System</string> |
| @@ -67,6 +72,12 @@ | |||
| 67 | <header>configuration/configure_general.h</header> | 72 | <header>configuration/configure_general.h</header> |
| 68 | <container>1</container> | 73 | <container>1</container> |
| 69 | </customwidget> | 74 | </customwidget> |
| 75 | <customwidget> | ||
| 76 | <class>ConfigureGameList</class> | ||
| 77 | <extends>QWidget</extends> | ||
| 78 | <header>configuration/configure_gamelist.h</header> | ||
| 79 | <container>1</container> | ||
| 80 | </customwidget> | ||
| 70 | <customwidget> | 81 | <customwidget> |
| 71 | <class>ConfigureSystem</class> | 82 | <class>ConfigureSystem</class> |
| 72 | <extends>QWidget</extends> | 83 | <extends>QWidget</extends> |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index cc4b326ae..daa4cc0d9 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -21,6 +21,7 @@ void ConfigureDialog::setConfiguration() {} | |||
| 21 | 21 | ||
| 22 | void ConfigureDialog::applyConfiguration() { | 22 | void ConfigureDialog::applyConfiguration() { |
| 23 | ui->generalTab->applyConfiguration(); | 23 | ui->generalTab->applyConfiguration(); |
| 24 | ui->gameListTab->applyConfiguration(); | ||
| 24 | ui->systemTab->applyConfiguration(); | 25 | ui->systemTab->applyConfiguration(); |
| 25 | ui->inputTab->applyConfiguration(); | 26 | ui->inputTab->applyConfiguration(); |
| 26 | ui->graphicsTab->applyConfiguration(); | 27 | ui->graphicsTab->applyConfiguration(); |
diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp new file mode 100644 index 000000000..1ae3423cf --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.cpp | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/settings.h" | ||
| 7 | #include "ui_configure_gamelist.h" | ||
| 8 | #include "ui_settings.h" | ||
| 9 | #include "yuzu/configuration/configure_gamelist.h" | ||
| 10 | |||
| 11 | ConfigureGameList::ConfigureGameList(QWidget* parent) | ||
| 12 | : QWidget(parent), ui(new Ui::ConfigureGameList) { | ||
| 13 | ui->setupUi(this); | ||
| 14 | |||
| 15 | static const std::vector<std::pair<u32, std::string>> default_icon_sizes{ | ||
| 16 | std::make_pair(0, "None"), std::make_pair(32, "Small"), | ||
| 17 | std::make_pair(64, "Standard"), std::make_pair(128, "Large"), | ||
| 18 | std::make_pair(256, "Full Size"), | ||
| 19 | }; | ||
| 20 | |||
| 21 | for (const auto& size : default_icon_sizes) { | ||
| 22 | ui->icon_size_combobox->addItem(QString::fromStdString(size.second + " (" + | ||
| 23 | std::to_string(size.first) + "x" + | ||
| 24 | std::to_string(size.first) + ")"), | ||
| 25 | size.first); | ||
| 26 | } | ||
| 27 | |||
| 28 | static const std::vector<std::string> row_text_names{ | ||
| 29 | "Filename", | ||
| 30 | "Filetype", | ||
| 31 | "Title ID", | ||
| 32 | "Title Name", | ||
| 33 | }; | ||
| 34 | |||
| 35 | for (size_t i = 0; i < row_text_names.size(); ++i) { | ||
| 36 | ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]), | ||
| 37 | QVariant::fromValue(i)); | ||
| 38 | ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]), | ||
| 39 | QVariant::fromValue(i)); | ||
| 40 | } | ||
| 41 | |||
| 42 | this->setConfiguration(); | ||
| 43 | } | ||
| 44 | |||
| 45 | ConfigureGameList::~ConfigureGameList() {} | ||
| 46 | |||
| 47 | void ConfigureGameList::setConfiguration() { | ||
| 48 | ui->show_unknown->setChecked(UISettings::values.show_unknown); | ||
| 49 | ui->icon_size_combobox->setCurrentIndex( | ||
| 50 | ui->icon_size_combobox->findData(UISettings::values.icon_size)); | ||
| 51 | ui->row_1_text_combobox->setCurrentIndex( | ||
| 52 | ui->row_1_text_combobox->findData(UISettings::values.row_1_text_id)); | ||
| 53 | ui->row_2_text_combobox->setCurrentIndex( | ||
| 54 | ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id)); | ||
| 55 | } | ||
| 56 | |||
| 57 | void ConfigureGameList::applyConfiguration() { | ||
| 58 | UISettings::values.show_unknown = ui->show_unknown->isChecked(); | ||
| 59 | UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); | ||
| 60 | UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); | ||
| 61 | UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt(); | ||
| 62 | Settings::Apply(); | ||
| 63 | } | ||
diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_gamelist.h new file mode 100644 index 000000000..94fba6373 --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <QWidget> | ||
| 9 | |||
| 10 | namespace Ui { | ||
| 11 | class ConfigureGameList; | ||
| 12 | } | ||
| 13 | |||
| 14 | class ConfigureGameList : public QWidget { | ||
| 15 | Q_OBJECT | ||
| 16 | |||
| 17 | public: | ||
| 18 | explicit ConfigureGameList(QWidget* parent = nullptr); | ||
| 19 | ~ConfigureGameList(); | ||
| 20 | |||
| 21 | void applyConfiguration(); | ||
| 22 | |||
| 23 | private: | ||
| 24 | void setConfiguration(); | ||
| 25 | |||
| 26 | private: | ||
| 27 | std::unique_ptr<Ui::ConfigureGameList> ui; | ||
| 28 | }; | ||
diff --git a/src/yuzu/configuration/configure_gamelist.ui b/src/yuzu/configuration/configure_gamelist.ui new file mode 100644 index 000000000..7471fdb60 --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.ui | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ConfigureGameList</class> | ||
| 4 | <widget class="QWidget" name="ConfigureGeneral"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>300</width> | ||
| 10 | <height>377</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Form</string> | ||
| 15 | </property> | ||
| 16 | <layout class="QHBoxLayout" name="HorizontalLayout"> | ||
| 17 | <item> | ||
| 18 | <layout class="QVBoxLayout" name="VerticalLayout"> | ||
| 19 | <item> | ||
| 20 | <widget class="QGroupBox" name="GeneralGroupBox"> | ||
| 21 | <property name="title"> | ||
| 22 | <string>General</string> | ||
| 23 | </property> | ||
| 24 | <layout class="QHBoxLayout" name="GeneralHorizontalLayout"> | ||
| 25 | <item> | ||
| 26 | <layout class="QVBoxLayout" name="GeneralVerticalLayout"> | ||
| 27 | <item> | ||
| 28 | <widget class="QCheckBox" name="show_unknown"> | ||
| 29 | <property name="text"> | ||
| 30 | <string>Show files with type 'Unknown'</string> | ||
| 31 | </property> | ||
| 32 | </widget> | ||
| 33 | </item> | ||
| 34 | </layout> | ||
| 35 | </item> | ||
| 36 | </layout> | ||
| 37 | </widget> | ||
| 38 | </item> | ||
| 39 | <item> | ||
| 40 | <widget class="QGroupBox" name="IconSizeGroupBox"> | ||
| 41 | <property name="title"> | ||
| 42 | <string>Icon Size</string> | ||
| 43 | </property> | ||
| 44 | <layout class="QHBoxLayout" name="icon_size_qhbox_layout"> | ||
| 45 | <item> | ||
| 46 | <layout class="QVBoxLayout" name="icon_size_qvbox_layout"> | ||
| 47 | <item> | ||
| 48 | <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2"> | ||
| 49 | <item> | ||
| 50 | <widget class="QLabel" name="icon_size_label"> | ||
| 51 | <property name="text"> | ||
| 52 | <string>Icon Size:</string> | ||
| 53 | </property> | ||
| 54 | </widget> | ||
| 55 | </item> | ||
| 56 | <item> | ||
| 57 | <widget class="QComboBox" name="icon_size_combobox"/> | ||
| 58 | </item> | ||
| 59 | </layout> | ||
| 60 | </item> | ||
| 61 | </layout> | ||
| 62 | </item> | ||
| 63 | </layout> | ||
| 64 | </widget> | ||
| 65 | </item> | ||
| 66 | <item> | ||
| 67 | <widget class="QGroupBox" name="RowGroupBox"> | ||
| 68 | <property name="title"> | ||
| 69 | <string>Row Text</string> | ||
| 70 | </property> | ||
| 71 | <layout class="QHBoxLayout" name="RowHorizontalLayout"> | ||
| 72 | <item> | ||
| 73 | <layout class="QVBoxLayout" name="RowVerticalLayout"> | ||
| 74 | <item> | ||
| 75 | <layout class="QHBoxLayout" name="row_1_qhbox_layout"> | ||
| 76 | <item> | ||
| 77 | <widget class="QLabel" name="row_1_label"> | ||
| 78 | <property name="text"> | ||
| 79 | <string>Row 1 Text:</string> | ||
| 80 | </property> | ||
| 81 | </widget> | ||
| 82 | </item> | ||
| 83 | <item> | ||
| 84 | <widget class="QComboBox" name="row_1_text_combobox"/> | ||
| 85 | </item> | ||
| 86 | </layout> | ||
| 87 | </item> | ||
| 88 | <item> | ||
| 89 | <layout class="QHBoxLayout" name="row_2_qhbox_layout"> | ||
| 90 | <item> | ||
| 91 | <widget class="QLabel" name="row_2_label"> | ||
| 92 | <property name="text"> | ||
| 93 | <string>Row 2 Text:</string> | ||
| 94 | </property> | ||
| 95 | </widget> | ||
| 96 | </item> | ||
| 97 | <item> | ||
| 98 | <widget class="QComboBox" name="row_2_text_combobox"/> | ||
| 99 | </item> | ||
| 100 | </layout> | ||
| 101 | </item> | ||
| 102 | </layout> | ||
| 103 | </item> | ||
| 104 | </layout> | ||
| 105 | </widget> | ||
| 106 | </item> | ||
| 107 | <item> | ||
| 108 | <spacer name="verticalSpacer"> | ||
| 109 | <property name="orientation"> | ||
| 110 | <enum>Qt::Vertical</enum> | ||
| 111 | </property> | ||
| 112 | <property name="sizeHint" stdset="0"> | ||
| 113 | <size> | ||
| 114 | <width>20</width> | ||
| 115 | <height>40</height> | ||
| 116 | </size> | ||
| 117 | </property> | ||
| 118 | </spacer> | ||
| 119 | </item> | ||
| 120 | </layout> | ||
| 121 | </item> | ||
| 122 | </layout> | ||
| 123 | </widget> | ||
| 124 | <resources/> | ||
| 125 | <connections/> | ||
| 126 | </ui> | ||
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 24f38a3c7..5f47f5a2b 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -9,9 +9,12 @@ | |||
| 9 | #include <QKeyEvent> | 9 | #include <QKeyEvent> |
| 10 | #include <QMenu> | 10 | #include <QMenu> |
| 11 | #include <QThreadPool> | 11 | #include <QThreadPool> |
| 12 | #include <boost/container/flat_map.hpp> | ||
| 12 | #include "common/common_paths.h" | 13 | #include "common/common_paths.h" |
| 13 | #include "common/logging/log.h" | 14 | #include "common/logging/log.h" |
| 14 | #include "common/string_util.h" | 15 | #include "common/string_util.h" |
| 16 | #include "core/file_sys/content_archive.h" | ||
| 17 | #include "core/file_sys/control_metadata.h" | ||
| 15 | #include "core/file_sys/vfs_real.h" | 18 | #include "core/file_sys/vfs_real.h" |
| 16 | #include "core/loader/loader.h" | 19 | #include "core/loader/loader.h" |
| 17 | #include "game_list.h" | 20 | #include "game_list.h" |
| @@ -398,8 +401,32 @@ void GameList::RefreshGameDirectory() { | |||
| 398 | } | 401 | } |
| 399 | 402 | ||
| 400 | void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { | 403 | void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { |
| 401 | const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory, | 404 | boost::container::flat_map<u64, std::shared_ptr<FileSys::NCA>> nca_control_map; |
| 402 | const std::string& virtual_name) -> bool { | 405 | |
| 406 | const auto nca_control_callback = | ||
| 407 | [this, &nca_control_map](u64* num_entries_out, const std::string& directory, | ||
| 408 | const std::string& virtual_name) -> bool { | ||
| 409 | std::string physical_name = directory + DIR_SEP + virtual_name; | ||
| 410 | |||
| 411 | if (stop_processing) | ||
| 412 | return false; // Breaks the callback loop. | ||
| 413 | |||
| 414 | bool is_dir = FileUtil::IsDirectory(physical_name); | ||
| 415 | QFileInfo file_info(physical_name.c_str()); | ||
| 416 | if (!is_dir && file_info.suffix().toStdString() == "nca") { | ||
| 417 | auto nca = std::make_shared<FileSys::NCA>( | ||
| 418 | std::make_shared<FileSys::RealVfsFile>(physical_name)); | ||
| 419 | if (nca->GetType() == FileSys::NCAContentType::Control) | ||
| 420 | nca_control_map.insert_or_assign(nca->GetTitleId(), nca); | ||
| 421 | } | ||
| 422 | return true; | ||
| 423 | }; | ||
| 424 | |||
| 425 | FileUtil::ForeachDirectoryEntry(nullptr, dir_path, nca_control_callback); | ||
| 426 | |||
| 427 | const auto callback = [this, recursion, | ||
| 428 | &nca_control_map](u64* num_entries_out, const std::string& directory, | ||
| 429 | const std::string& virtual_name) -> bool { | ||
| 403 | std::string physical_name = directory + DIR_SEP + virtual_name; | 430 | std::string physical_name = directory + DIR_SEP + virtual_name; |
| 404 | 431 | ||
| 405 | if (stop_processing) | 432 | if (stop_processing) |
| @@ -410,17 +437,50 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign | |||
| 410 | (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { | 437 | (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { |
| 411 | std::unique_ptr<Loader::AppLoader> loader = | 438 | std::unique_ptr<Loader::AppLoader> loader = |
| 412 | Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name)); | 439 | Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name)); |
| 413 | if (!loader) | 440 | if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown || |
| 441 | loader->GetFileType() == Loader::FileType::Error) && | ||
| 442 | !UISettings::values.show_unknown)) | ||
| 414 | return true; | 443 | return true; |
| 415 | 444 | ||
| 416 | std::vector<u8> smdh; | 445 | std::vector<u8> icon; |
| 417 | loader->ReadIcon(smdh); | 446 | const auto res1 = loader->ReadIcon(icon); |
| 418 | 447 | ||
| 419 | u64 program_id = 0; | 448 | u64 program_id; |
| 420 | loader->ReadProgramId(program_id); | 449 | const auto res2 = loader->ReadProgramId(program_id); |
| 450 | |||
| 451 | std::string name = " "; | ||
| 452 | const auto res3 = loader->ReadTitle(name); | ||
| 453 | |||
| 454 | if ((res1 == Loader::ResultStatus::ErrorNotUsed || | ||
| 455 | res1 == Loader::ResultStatus::ErrorNotImplemented) && | ||
| 456 | (res3 == Loader::ResultStatus::ErrorNotUsed || | ||
| 457 | res3 == Loader::ResultStatus::ErrorNotImplemented) && | ||
| 458 | res2 == Loader::ResultStatus::Success) { | ||
| 459 | // Use from metadata pool. | ||
| 460 | if (nca_control_map.find(program_id) != nca_control_map.end()) { | ||
| 461 | const auto nca = nca_control_map[program_id]; | ||
| 462 | const auto control_dir = nca->GetSubdirectories()[0]; | ||
| 463 | |||
| 464 | const auto nacp_file = control_dir->GetFile("control.nacp"); | ||
| 465 | FileSys::NACP nacp(nacp_file); | ||
| 466 | name = nacp.GetApplicationName(); | ||
| 467 | |||
| 468 | FileSys::VirtualFile icon_file = nullptr; | ||
| 469 | for (const auto& language : FileSys::LANGUAGE_NAMES) { | ||
| 470 | icon_file = control_dir->GetFile("icon_" + std::string(language) + ".dat"); | ||
| 471 | if (icon_file != nullptr) { | ||
| 472 | icon = icon_file->ReadAllBytes(); | ||
| 473 | break; | ||
| 474 | } | ||
| 475 | } | ||
| 476 | } | ||
| 477 | } | ||
| 421 | 478 | ||
| 422 | emit EntryReady({ | 479 | emit EntryReady({ |
| 423 | new GameListItemPath(FormatGameName(physical_name), smdh, program_id), | 480 | new GameListItemPath( |
| 481 | FormatGameName(physical_name), icon, QString::fromStdString(name), | ||
| 482 | QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())), | ||
| 483 | program_id), | ||
| 424 | new GameListItem( | 484 | new GameListItem( |
| 425 | QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), | 485 | QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), |
| 426 | new GameListItemSize(FileUtil::GetSize(physical_name)), | 486 | new GameListItemSize(FileUtil::GetSize(physical_name)), |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index aa69a098f..a22025e67 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <QStandardItem> | 11 | #include <QStandardItem> |
| 12 | #include <QString> | 12 | #include <QString> |
| 13 | #include "common/string_util.h" | 13 | #include "common/string_util.h" |
| 14 | #include "ui_settings.h" | ||
| 14 | #include "yuzu/util/util.h" | 15 | #include "yuzu/util/util.h" |
| 15 | 16 | ||
| 16 | /** | 17 | /** |
| @@ -18,8 +19,7 @@ | |||
| 18 | * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24) | 19 | * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24) |
| 19 | * @return QPixmap default icon | 20 | * @return QPixmap default icon |
| 20 | */ | 21 | */ |
| 21 | static QPixmap GetDefaultIcon(bool large) { | 22 | static QPixmap GetDefaultIcon(u32 size) { |
| 22 | int size = large ? 48 : 24; | ||
| 23 | QPixmap icon(size, size); | 23 | QPixmap icon(size, size); |
| 24 | icon.fill(Qt::transparent); | 24 | icon.fill(Qt::transparent); |
| 25 | return icon; | 25 | return icon; |
| @@ -44,11 +44,25 @@ public: | |||
| 44 | static const int FullPathRole = Qt::UserRole + 1; | 44 | static const int FullPathRole = Qt::UserRole + 1; |
| 45 | static const int TitleRole = Qt::UserRole + 2; | 45 | static const int TitleRole = Qt::UserRole + 2; |
| 46 | static const int ProgramIdRole = Qt::UserRole + 3; | 46 | static const int ProgramIdRole = Qt::UserRole + 3; |
| 47 | static const int FileTypeRole = Qt::UserRole + 4; | ||
| 47 | 48 | ||
| 48 | GameListItemPath() = default; | 49 | GameListItemPath() = default; |
| 49 | GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data, u64 program_id) { | 50 | GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data, |
| 51 | const QString& game_name, const QString& game_type, u64 program_id) | ||
| 52 | : GameListItem() { | ||
| 50 | setData(game_path, FullPathRole); | 53 | setData(game_path, FullPathRole); |
| 54 | setData(game_name, TitleRole); | ||
| 51 | setData(qulonglong(program_id), ProgramIdRole); | 55 | setData(qulonglong(program_id), ProgramIdRole); |
| 56 | setData(game_type, FileTypeRole); | ||
| 57 | |||
| 58 | QPixmap picture; | ||
| 59 | u32 size = UISettings::values.icon_size; | ||
| 60 | if (!picture.loadFromData(picture_data.data(), picture_data.size())) | ||
| 61 | picture = GetDefaultIcon(size); | ||
| 62 | |||
| 63 | picture = picture.scaled(size, size); | ||
| 64 | |||
| 65 | setData(picture, Qt::DecorationRole); | ||
| 52 | } | 66 | } |
| 53 | 67 | ||
| 54 | QVariant data(int role) const override { | 68 | QVariant data(int role) const override { |
| @@ -57,7 +71,23 @@ public: | |||
| 57 | Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename, | 71 | Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename, |
| 58 | nullptr); | 72 | nullptr); |
| 59 | QString title = data(TitleRole).toString(); | 73 | QString title = data(TitleRole).toString(); |
| 60 | return QString::fromStdString(filename) + (title.isEmpty() ? "" : "\n " + title); | 74 | |
| 75 | std::vector<QString> row_data{ | ||
| 76 | QString::fromStdString(filename), | ||
| 77 | data(FileTypeRole).toString(), | ||
| 78 | QString::fromStdString(fmt::format("0x{:016X}", data(ProgramIdRole).toULongLong())), | ||
| 79 | data(TitleRole).toString(), | ||
| 80 | }; | ||
| 81 | |||
| 82 | auto row1 = row_data.at(UISettings::values.row_1_text_id); | ||
| 83 | auto row2 = row_data.at(UISettings::values.row_2_text_id); | ||
| 84 | |||
| 85 | if (row1.isEmpty() || row1 == row2) | ||
| 86 | return row2; | ||
| 87 | if (row2.isEmpty()) | ||
| 88 | return row1; | ||
| 89 | |||
| 90 | return row1 + "\n " + row2; | ||
| 61 | } else { | 91 | } else { |
| 62 | return GameListItem::data(role); | 92 | return GameListItem::data(role); |
| 63 | } | 93 | } |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 17ed62c72..a6241e63e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -768,6 +768,7 @@ void GMainWindow::OnConfigure() { | |||
| 768 | configureDialog.applyConfiguration(); | 768 | configureDialog.applyConfiguration(); |
| 769 | if (UISettings::values.theme != old_theme) | 769 | if (UISettings::values.theme != old_theme) |
| 770 | UpdateUITheme(); | 770 | UpdateUITheme(); |
| 771 | game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); | ||
| 771 | config->Save(); | 772 | config->Save(); |
| 772 | } | 773 | } |
| 773 | } | 774 | } |
diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h index 2286c2559..051494bc5 100644 --- a/src/yuzu/ui_settings.h +++ b/src/yuzu/ui_settings.h | |||
| @@ -54,6 +54,12 @@ struct Values { | |||
| 54 | 54 | ||
| 55 | // logging | 55 | // logging |
| 56 | bool show_console; | 56 | bool show_console; |
| 57 | |||
| 58 | // Game List | ||
| 59 | bool show_unknown; | ||
| 60 | uint32_t icon_size; | ||
| 61 | uint8_t row_1_text_id; | ||
| 62 | uint8_t row_2_text_id; | ||
| 57 | }; | 63 | }; |
| 58 | 64 | ||
| 59 | extern Values values; | 65 | extern Values values; |