[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 115d0484a6
commit 49670ebb0f
Signed by: crueter
GPG key ID: 425ACD2D4830EBC6
8 changed files with 136 additions and 47 deletions

View file

@ -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()

File diff suppressed because one or more lines are too long

View file

@ -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})

View file

@ -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 <QGuiApplication>
@ -13,6 +14,10 @@
#include "core/frontend/emu_window.h"
#include <QFile>
#include <QMessageBox>
#include "qt_frontend_util.h"
#include <JlCompress.h>
#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<bool(std::size_t, std::size_t)> 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<int>(((i) / static_cast<float>(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

View file

@ -13,7 +13,6 @@
#include <core/file_sys/vfs/vfs_real.h>
namespace QtCommon {
static constexpr std::array<const char *, 3> 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<std::size_t>(result));
}
static constexpr std::array<const char *, 6> 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<const char *, 6> 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<bool(std::size_t, std::size_t)> QtProgressCallback,
Core::System *system,
FileSys::VfsFilesystem *vfs);
FirmwareInstallResult InstallFirmware(
const QString &location,
bool recursive,
std::function<bool(std::size_t, std::size_t)> 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

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

@ -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<int>((processed_size * 10) / total_size));