From 49670ebb0ff8187323a04350494998bc273b2e04 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 23 Jul 2025 21:10:17 -0400 Subject: [PATCH] [qt] frontend abstraction and message box early handling Signed-off-by: crueter --- src/CMakeLists.txt | 1 + src/frontend_common/firmware_manager.h | 5 ++- src/qt_common/CMakeLists.txt | 6 ++- src/qt_common/qt_common.cpp | 59 ++++++++++++++++++++++---- src/qt_common/qt_common.h | 34 +++++++-------- src/qt_common/qt_frontend_util.cpp | 25 +++++++++++ src/qt_common/qt_frontend_util.h | 29 +++++++++++++ src/yuzu/main.cpp | 24 +++-------- 8 files changed, 136 insertions(+), 47 deletions(-) create mode 100644 src/qt_common/qt_frontend_util.cpp create mode 100644 src/qt_common/qt_frontend_util.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0032b20029..184b049d06 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,7 @@ if (YUZU_ROOM_STANDALONE) endif() if (ENABLE_QT) + add_definitions(-DYUZU_QT_WIDGETS) add_subdirectory(qt_common) add_subdirectory(yuzu) endif() diff --git a/src/frontend_common/firmware_manager.h b/src/frontend_common/firmware_manager.h index 20f3b41478..23fce59eb3 100644 --- a/src/frontend_common/firmware_manager.h +++ b/src/frontend_common/firmware_manager.h @@ -7,6 +7,7 @@ #include "common/common_types.h" #include "core/core.h" #include "core/file_sys/nca_metadata.h" +#include "core/file_sys/content_archive.h" #include "core/file_sys/registered_cache.h" #include "core/hle/service/filesystem/filesystem.h" #include @@ -143,6 +144,8 @@ inline std::pair GetFirmwareVersion return {firmware_data, result}; } + +// TODO(crueter): GET AS STRING } -#endif // FIRMWARE_MANAGER_H +#endif diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index d6ef427ba6..0c9bb54b11 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) + add_library(qt_common STATIC qt_common.h qt_common.cpp @@ -15,10 +17,12 @@ add_library(qt_common STATIC shared_translation.h qt_path_util.h qt_path_util.cpp qt_game_util.h qt_game_util.cpp + qt_frontend_util.h qt_frontend_util.cpp ) create_target_directory_groups(qt_common) -target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 54c79c93e1..c7b75a196d 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -5,6 +5,7 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "core/hle/service/filesystem/filesystem.h" +#include "frontend_common/firmware_manager.h" #include "uisettings.h" #include @@ -13,6 +14,10 @@ #include "core/frontend/emu_window.h" #include + +#include +#include "qt_frontend_util.h" + #include #if !defined(WIN32) && !defined(__APPLE__) @@ -22,7 +27,6 @@ #endif namespace QtCommon { - MetadataResult ResetMetadata() { if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) @@ -87,8 +91,24 @@ FirmwareInstallResult InstallFirmware( bool recursive, std::function QtProgressCallback, Core::System* system, - FileSys::VfsFilesystem* vfs) + FileSys::VfsFilesystem* vfs, + QWidget* parent) { + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Failed"; + static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + + QMessageBox::Icon icon; + FirmwareInstallResult result; + + const auto ShowMessage = [&]() { + QtCommon::Frontend::ShowMessage(icon, + failedTitle, + GetFirmwareInstallResultString(result), + buttons, + parent); + }; + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in @@ -121,14 +141,20 @@ FirmwareInstallResult InstallFirmware( } if (out.size() <= 0) { - return FirmwareInstallResult::NoNCAs; + result = FirmwareInstallResult::NoNCAs; + icon = QMessageBox::Warning; + ShowMessage(); + return result; } // Locate and erase the content of nand/system/Content/registered/*.nca, if any. auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - return FirmwareInstallResult::FailedDelete; + result = FirmwareInstallResult::FailedDelete; + icon = QMessageBox::Critical; + ShowMessage(); + return result; } LOG_INFO(Frontend, @@ -159,17 +185,35 @@ FirmwareInstallResult InstallFirmware( 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { - return FirmwareInstallResult::FailedCorrupted; + result = FirmwareInstallResult::FailedCorrupted; + icon = QMessageBox::Warning; + ShowMessage(); + return result; } } if (!success) { - return FirmwareInstallResult::FailedCopy; + result = FirmwareInstallResult::FailedCopy; + icon = QMessageBox::Critical; + ShowMessage(); + return result; } // Re-scan VFS for the newly placed firmware files. system->GetFileSystemController().CreateFactories(*vfs); - return FirmwareInstallResult::Success; + + const auto pair = FirmwareManager::GetFirmwareVersion(*system); + const auto firmware_data = pair.first; + const std::string display_version(firmware_data.display_version.data()); + + result = FirmwareInstallResult::Success; + QtCommon::Frontend::ShowMessage(QMessageBox::Information, + qApp->tr(successTitle), + qApp->tr(GetFirmwareInstallResultString(result)) + .arg(QString::fromStdString(display_version)), + buttons, + parent); + return result; } QString UnzipFirmwareToTmp(const QString& location) @@ -195,5 +239,4 @@ QString UnzipFirmwareToTmp(const QString& location) return qCacheDir; } - } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index b3ca99e65a..ef9b5577f1 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -13,7 +13,6 @@ #include namespace QtCommon { - static constexpr std::array METADATA_RESULTS = { "The operation completed successfully.", "The metadata cache couldn't be deleted. It might be in use or non-existent.", @@ -41,15 +40,14 @@ inline constexpr const char *GetResetMetadataResultString(MetadataResult result) return METADATA_RESULTS.at(static_cast(result)); } -static constexpr std::array FIRMWARE_RESULTS = { - "", - "", - "Unable to locate potential firmware NCA files", - "Failed to delete one or more firmware files.", - "One or more firmware files failed to copy into NAND.", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." - "Restart Eden or re-install firmware." -}; +static constexpr std::array FIRMWARE_RESULTS + = {"Successfully installed firmware version %1", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware."}; enum class FirmwareInstallResult { Success, @@ -60,11 +58,13 @@ enum class FirmwareInstallResult { FailedCorrupted, }; -FirmwareInstallResult InstallFirmware(const QString &location, - bool recursive, - std::function QtProgressCallback, - Core::System *system, - FileSys::VfsFilesystem *vfs); +FirmwareInstallResult InstallFirmware( + const QString &location, + bool recursive, + std::function QtProgressCallback, + Core::System *system, + FileSys::VfsFilesystem *vfs, + QWidget *parent = nullptr); QString UnzipFirmwareToTmp(const QString &location); @@ -75,8 +75,6 @@ inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResul Core::Frontend::WindowSystemType GetWindowSystemType(); -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); - - +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); } // namespace QtCommon #endif diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp new file mode 100644 index 0000000000..6cbe82e000 --- /dev/null +++ b/src/qt_common/qt_frontend_util.cpp @@ -0,0 +1,25 @@ +#include "qt_frontend_util.h" + +namespace QtCommon::Frontend { +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons, + QWidget *parent) +{ +#ifdef YUZU_QT_WIDGETS + QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); + return static_cast(box->exec()); +#endif +} + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons, + QWidget *parent) +{ + return ShowMessage(icon, qApp->tr(title), qApp->tr(text), buttons, parent); +} + +} // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h new file mode 100644 index 0000000000..8508e29f18 --- /dev/null +++ b/src/qt_common/qt_frontend_util.h @@ -0,0 +1,29 @@ +#ifndef QT_FRONTEND_UTIL_H +#define QT_FRONTEND_UTIL_H + +#include +#include + +#ifdef YUZU_QT_WIDGETS +#include +#endif + +/** + * manages common functionality e.g. message boxes and such for Qt/QML + */ +namespace QtCommon::Frontend { +Q_NAMESPACE + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + QWidget *parent = nullptr); + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + QWidget *parent = nullptr); +} // namespace QtCommon::Frontend +#endif // QT_FRONTEND_UTIL_H diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 86e0755ce8..19110781bf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2611,6 +2611,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } +// TODO(crueter): Transfer ts to showmessage void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); @@ -2680,6 +2681,8 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& } // TODO(crueter): All this can be transfered to qt_common +// Aldoe I need to decide re: message boxes for QML +// translations_common? strings_common? qt_strings? who knows QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { switch (type) { case InstalledEntryType::Game: @@ -4218,28 +4221,11 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get()); - const char* resultMessage = QtCommon::GetFirmwareInstallResultString(result); + auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get(), this); progress.close(); - QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this); - - switch (result) { - case QtCommon::FirmwareInstallResult::NoNCAs: - case QtCommon::FirmwareInstallResult::FailedCorrupted: - box->setIcon(QMessageBox::Icon::Warning); - box->exec(); - return; - case QtCommon::FirmwareInstallResult::FailedCopy: - case QtCommon::FirmwareInstallResult::FailedDelete: - box->setIcon(QMessageBox::Icon::Critical); - box->exec(); - return; - default: - box->deleteLater(); - break; - } + if (result != QtCommon::FirmwareInstallResult::Success) return; auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size));