[qt] frontend abstraction and message box early handling

Signed-off-by: crueter <crueter@eden-emu.dev>
This commit is contained in:
crueter 2025-07-23 21:10:17 -04:00
parent 53760a52bb
commit 3772615324
Signed by: crueter
GPG key ID: 425ACD2D4830EBC6
8 changed files with 136 additions and 47 deletions

View file

@ -221,6 +221,7 @@ if (YUZU_ROOM_STANDALONE)
endif() endif()
if (ENABLE_QT) if (ENABLE_QT)
add_definitions(-DYUZU_QT_WIDGETS)
add_subdirectory(qt_common) add_subdirectory(qt_common)
add_subdirectory(yuzu) add_subdirectory(yuzu)
endif() endif()

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,8 @@
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-FileCopyrightText: 2023 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
find_package(Qt6 REQUIRED COMPONENTS Core)
add_library(qt_common STATIC add_library(qt_common STATIC
qt_common.h qt_common.h
qt_common.cpp qt_common.cpp
@ -15,10 +17,12 @@ add_library(qt_common STATIC
shared_translation.h shared_translation.h
qt_path_util.h qt_path_util.cpp qt_path_util.h qt_path_util.cpp
qt_game_util.h qt_game_util.cpp qt_game_util.h qt_game_util.cpp
qt_frontend_util.h qt_frontend_util.cpp
) )
create_target_directory_groups(qt_common) 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) if (NOT WIN32)
target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})

View file

@ -5,6 +5,7 @@
#include "common/fs/fs.h" #include "common/fs/fs.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/filesystem.h"
#include "frontend_common/firmware_manager.h"
#include "uisettings.h" #include "uisettings.h"
#include <QGuiApplication> #include <QGuiApplication>
@ -13,6 +14,10 @@
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include <QFile> #include <QFile>
#include <QMessageBox>
#include "qt_frontend_util.h"
#include <JlCompress.h> #include <JlCompress.h>
#if !defined(WIN32) && !defined(__APPLE__) #if !defined(WIN32) && !defined(__APPLE__)
@ -22,7 +27,6 @@
#endif #endif
namespace QtCommon { namespace QtCommon {
MetadataResult ResetMetadata() MetadataResult ResetMetadata()
{ {
if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir)
@ -87,8 +91,24 @@ FirmwareInstallResult InstallFirmware(
bool recursive, bool recursive,
std::function<bool(std::size_t, std::size_t)> QtProgressCallback, std::function<bool(std::size_t, std::size_t)> QtProgressCallback,
Core::System* system, 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()); 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 // 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) { 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. // Locate and erase the content of nand/system/Content/registered/*.nca, if any.
auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory();
if (sysnand_content_vdir->IsWritable() if (sysnand_content_vdir->IsWritable()
&& !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) {
return FirmwareInstallResult::FailedDelete; result = FirmwareInstallResult::FailedDelete;
icon = QMessageBox::Critical;
ShowMessage();
return result;
} }
LOG_INFO(Frontend, LOG_INFO(Frontend,
@ -159,17 +185,35 @@ FirmwareInstallResult InstallFirmware(
20 20
+ static_cast<int>(((i) / static_cast<float>(out.size())) + static_cast<int>(((i) / static_cast<float>(out.size()))
* 70.0))) { * 70.0))) {
return FirmwareInstallResult::FailedCorrupted; result = FirmwareInstallResult::FailedCorrupted;
icon = QMessageBox::Warning;
ShowMessage();
return result;
} }
} }
if (!success) { if (!success) {
return FirmwareInstallResult::FailedCopy; result = FirmwareInstallResult::FailedCopy;
icon = QMessageBox::Critical;
ShowMessage();
return result;
} }
// Re-scan VFS for the newly placed firmware files. // Re-scan VFS for the newly placed firmware files.
system->GetFileSystemController().CreateFactories(*vfs); 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) QString UnzipFirmwareToTmp(const QString& location)
@ -195,5 +239,4 @@ QString UnzipFirmwareToTmp(const QString& location)
return qCacheDir; return qCacheDir;
} }
} // namespace QtCommon } // namespace QtCommon

View file

@ -13,7 +13,6 @@
#include <core/file_sys/vfs/vfs_real.h> #include <core/file_sys/vfs/vfs_real.h>
namespace QtCommon { namespace QtCommon {
static constexpr std::array<const char *, 3> METADATA_RESULTS = { static constexpr std::array<const char *, 3> METADATA_RESULTS = {
"The operation completed successfully.", "The operation completed successfully.",
"The metadata cache couldn't be deleted. It might be in use or non-existent.", "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<std::size_t>(result)); return METADATA_RESULTS.at(static_cast<std::size_t>(result));
} }
static constexpr std::array<const char *, 6> FIRMWARE_RESULTS = { static constexpr std::array<const char *, 6> FIRMWARE_RESULTS
"", = {"Successfully installed firmware version %1",
"", "",
"Unable to locate potential firmware NCA files", "Unable to locate potential firmware NCA files",
"Failed to delete one or more firmware files.", "Failed to delete one or more firmware files.",
"One or more firmware files failed to copy into NAND.", "One or more firmware files failed to copy into NAND.",
"Firmware installation cancelled, firmware may be in a bad state or corrupted." "Firmware installation cancelled, firmware may be in a bad state or corrupted."
"Restart Eden or re-install firmware." "Restart Eden or re-install firmware."};
};
enum class FirmwareInstallResult { enum class FirmwareInstallResult {
Success, Success,
@ -60,11 +58,13 @@ enum class FirmwareInstallResult {
FailedCorrupted, FailedCorrupted,
}; };
FirmwareInstallResult InstallFirmware(const QString &location, FirmwareInstallResult InstallFirmware(
const QString &location,
bool recursive, bool recursive,
std::function<bool(std::size_t, std::size_t)> QtProgressCallback, std::function<bool(std::size_t, std::size_t)> QtProgressCallback,
Core::System *system, Core::System *system,
FileSys::VfsFilesystem *vfs); FileSys::VfsFilesystem *vfs,
QWidget *parent = nullptr);
QString UnzipFirmwareToTmp(const QString &location); QString UnzipFirmwareToTmp(const QString &location);
@ -76,7 +76,5 @@ inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResul
Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::WindowSystemType GetWindowSystemType();
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window);
} // namespace QtCommon } // namespace QtCommon
#endif #endif

View file

@ -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<QMessageBox::StandardButton>(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

View file

@ -0,0 +1,29 @@
#ifndef QT_FRONTEND_UTIL_H
#define QT_FRONTEND_UTIL_H
#include <QGuiApplication>
#include <QMessageBox>
#ifdef YUZU_QT_WIDGETS
#include <QWidget>
#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

View file

@ -2518,6 +2518,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); QDesktopServices::openUrl(QUrl::fromLocalFile(qpath));
} }
// TODO(crueter): Transfer ts to showmessage
void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
if (!QtCommon::PathUtil::OpenShaderCache(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.")); 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."));
@ -2587,6 +2588,8 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog&
} }
// TODO(crueter): All this can be transfered to qt_common // 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 { QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const {
switch (type) { switch (type) {
case InstalledEntryType::Game: case InstalledEntryType::Game:
@ -4117,28 +4120,11 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) {
return progress.wasCanceled(); return progress.wasCanceled();
}; };
auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get()); auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get(), this);
const char* resultMessage = QtCommon::GetFirmwareInstallResultString(result);
progress.close(); progress.close();
QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this); if (result != QtCommon::FirmwareInstallResult::Success) return;
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;
}
auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) {
progress.setValue(90 + static_cast<int>((processed_size * 10) / total_size)); progress.setValue(90 + static_cast<int>((processed_size * 10) / total_size));