Browse Source

[desktop] Port some QtCommon changes from QML branch

- Linker now resolves implementation differences
- Remove unneeded ifdefs
- Better abstractions overall

Signed-off-by: crueter <crueter@eden-emu.dev>
pull/3703/head
crueter 3 days ago
parent
commit
174e8234e3
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 4
      .ci/license-header.sh
  2. 1
      src/CMakeLists.txt
  3. 6
      src/qt_common/CMakeLists.txt
  4. 64
      src/qt_common/abstract/frontend.cpp
  5. 164
      src/qt_common/abstract/frontend.h
  6. 17
      src/qt_common/abstract/progress.cpp
  7. 45
      src/qt_common/abstract/progress.h
  8. 4
      src/qt_common/abstract/qt_progress_dialog.cpp
  9. 47
      src/qt_common/abstract/qt_progress_dialog.h
  10. 10
      src/qt_common/config/qt_config.cpp
  11. 13
      src/qt_common/qt_common.cpp
  12. 8
      src/qt_common/qt_common.h
  13. 162
      src/qt_common/util/content.cpp
  14. 2
      src/qt_common/util/content.h
  15. 24
      src/qt_common/util/game.cpp
  16. 18
      src/qt_common/util/path.cpp
  17. 1
      src/yuzu/CMakeLists.txt
  18. 119
      src/yuzu/libqt_common.cpp
  19. 37
      src/yuzu/libqt_common.h
  20. 3
      src/yuzu/main_window.cpp

4
.ci/license-header.sh

@ -115,7 +115,7 @@ for file in $FILES; do
*.cmake|*.sh|*CMakeLists.txt)
begin="#"
;;
*.kt*|*.cpp|*.h)
*.kt*|*.cpp|*.h|*.qml)
begin="//"
;;
*)
@ -193,7 +193,7 @@ if [ "$UPDATE" = "true" ]; then
begin="#"
shell=true
;;
*.kt*|*.cpp|*.h)
*)
begin="//"
shell="false"
;;

1
src/CMakeLists.txt

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

6
src/qt_common/CMakeLists.txt

@ -1,6 +1,8 @@
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
set(CMAKE_AUTOMOC ON)
add_library(qt_common STATIC
qt_common.h
qt_common.cpp
@ -26,7 +28,7 @@ add_library(qt_common STATIC
util/mod.h util/mod.cpp
abstract/frontend.h abstract/frontend.cpp
abstract/qt_progress_dialog.h abstract/qt_progress_dialog.cpp
abstract/progress.h abstract/progress.cpp
qt_string_lookup.h
qt_compat.h
@ -93,3 +95,5 @@ if (UNIX AND NOT APPLE)
target_link_libraries(qt_common PRIVATE Qt6::GuiPrivate)
endif()
endif()
create_target_directory_groups(qt_common)

64
src/qt_common/abstract/frontend.cpp

@ -1,75 +1,27 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <QLineEdit>
#include "frontend.h"
#include "qt_common/qt_common.h"
#ifdef YUZU_QT_WIDGETS
#include <QFileDialog>
#endif
#include <QAbstractButton>
#include <QInputDialog>
namespace QtCommon::Frontend {
StandardButton ShowMessage(Icon icon, const QString& title, const QString& text,
StandardButtons buttons, QObject* parent) {
#ifdef YUZU_QT_WIDGETS
QMessageBox* box = new QMessageBox(icon, title, text, buttons, (QWidget*)parent);
return static_cast<QMessageBox::StandardButton>(box->exec());
#endif
// TODO(crueter): If Qt Widgets is disabled...
// need a way to reference icon/buttons too
}
const QString GetOpenFileName(const QString& title, const QString& dir, const QString& filter,
QString* selectedFilter, Options options) {
#ifdef YUZU_QT_WIDGETS
return QFileDialog::getOpenFileName(rootObject, title, dir, filter, selectedFilter, options);
#endif
QString* selectedFilter) {
return QFileDialog::getOpenFileName(rootObject, title, dir, filter, selectedFilter);
}
const QStringList GetOpenFileNames(const QString& title, const QString& dir, const QString& filter,
QString* selectedFilter, Options options) {
#ifdef YUZU_QT_WIDGETS
return QFileDialog::getOpenFileNames(rootObject, title, dir, filter, selectedFilter, options);
#endif
QString* selectedFilter) {
return QFileDialog::getOpenFileNames(rootObject, title, dir, filter, selectedFilter);
}
const QString GetSaveFileName(const QString& title, const QString& dir, const QString& filter,
QString* selectedFilter, Options options) {
#ifdef YUZU_QT_WIDGETS
return QFileDialog::getSaveFileName(rootObject, title, dir, filter, selectedFilter, options);
#endif
}
const QString GetExistingDirectory(const QString& caption, const QString& dir, Options options) {
#ifdef YUZU_QT_WIDGETS
return QFileDialog::getExistingDirectory(rootObject, caption, dir, options);
#endif
}
int Choice(const QString& title, const QString& caption, const QStringList& options) {
QMessageBox box(rootObject);
box.setText(caption);
box.setWindowTitle(title);
for (const QString& opt : options) {
box.addButton(opt, QMessageBox::AcceptRole);
}
box.addButton(QMessageBox::Cancel);
box.exec();
auto button = box.clickedButton();
return options.indexOf(button->text());
QString* selectedFilter) {
return QFileDialog::getSaveFileName(rootObject, title, dir, filter, selectedFilter);
}
const QString GetTextInput(const QString& title, const QString& caption,
const QString& defaultText) {
return QInputDialog::getText(rootObject, title, caption, QLineEdit::Normal, defaultText);
const QString GetExistingDirectory(const QString& caption, const QString& dir) {
return QFileDialog::getExistingDirectory(rootObject, caption, dir);
}
} // namespace QtCommon::Frontend

164
src/qt_common/abstract/frontend.h

@ -7,11 +7,7 @@
#include <QGuiApplication>
#include "qt_common/qt_common.h"
#ifdef YUZU_QT_WIDGETS
#include <QFileDialog>
#include <QWidget>
#include <QMessageBox>
#endif
/**
* manages common functionality e.g. message boxes and such for Qt/QML
@ -20,60 +16,39 @@ namespace QtCommon::Frontend {
Q_NAMESPACE
#ifdef YUZU_QT_WIDGETS
using Options = QFileDialog::Options;
using Option = QFileDialog::Option;
using StandardButton = QMessageBox::StandardButton;
using StandardButtons = QMessageBox::StandardButtons;
using Icon = QMessageBox::Icon;
#else
enum Option {
ShowDirsOnly = 0x00000001,
DontResolveSymlinks = 0x00000002,
DontConfirmOverwrite = 0x00000004,
DontUseNativeDialog = 0x00000008,
ReadOnly = 0x00000010,
HideNameFilterDetails = 0x00000020,
DontUseCustomDirectoryIcons = 0x00000040
};
Q_ENUM_NS(Option)
Q_DECLARE_FLAGS(Options, Option)
Q_FLAG_NS(Options)
enum StandardButton {
// keep this in sync with QDialogButtonBox::StandardButton and QPlatformDialogHelper::StandardButton
NoButton = 0x00000000,
Ok = 0x00000400,
Save = 0x00000800,
SaveAll = 0x00001000,
Open = 0x00002000,
Yes = 0x00004000,
YesToAll = 0x00008000,
No = 0x00010000,
NoToAll = 0x00020000,
Abort = 0x00040000,
Retry = 0x00080000,
Ignore = 0x00100000,
Close = 0x00200000,
Cancel = 0x00400000,
Discard = 0x00800000,
Help = 0x01000000,
Apply = 0x02000000,
Reset = 0x04000000,
RestoreDefaults = 0x08000000,
FirstButton = Ok, // internal
LastButton = RestoreDefaults, // internal
YesAll = YesToAll, // obsolete
NoAll = NoToAll, // obsolete
Default = 0x00000100, // obsolete
Escape = 0x00000200, // obsolete
FlagMask = 0x00000300, // obsolete
ButtonMask = ~FlagMask // obsolete
// keep this in sync with QDialogButtonBox::StandardButton and
// QPlatformDialogHelper::StandardButton
NoButton = 0x00000000,
Ok = 0x00000400,
Save = 0x00000800,
SaveAll = 0x00001000,
Open = 0x00002000,
Yes = 0x00004000,
YesToAll = 0x00008000,
No = 0x00010000,
NoToAll = 0x00020000,
Abort = 0x00040000,
Retry = 0x00080000,
Ignore = 0x00100000,
Close = 0x00200000,
Cancel = 0x00400000,
Discard = 0x00800000,
Help = 0x01000000,
Apply = 0x02000000,
Reset = 0x04000000,
RestoreDefaults = 0x08000000,
FirstButton = Ok, // internal
LastButton = RestoreDefaults, // internal
YesAll = YesToAll, // obsolete
NoAll = NoToAll, // obsolete
Default = 0x00000100, // obsolete
Escape = 0x00000200, // obsolete
FlagMask = 0x00000300, // obsolete
ButtonMask = ~FlagMask // obsolete
};
Q_ENUM_NS(StandardButton)
@ -83,7 +58,7 @@ typedef StandardButton Button;
Q_DECLARE_FLAGS(StandardButtons, StandardButton)
Q_FLAG_NS(StandardButtons)
enum Icon {
enum class Icon {
// keep this in sync with QMessageDialogOptions::StandardIcon
NoIcon = 0,
Information = 1,
@ -93,29 +68,26 @@ enum Icon {
};
Q_ENUM_NS(Icon)
#endif
// TODO(crueter) widgets-less impl, choices et al.
StandardButton ShowMessage(Icon icon,
const QString &title,
const QString &text,
StandardButton ShowMessage(Icon icon, const QString& title, const QString& text,
StandardButtons buttons = StandardButton::NoButton,
QObject *parent = nullptr);
#define UTIL_OVERRIDES(level) \
inline StandardButton level(QObject *parent, \
const QString &title, \
const QString &text, \
StandardButtons buttons = StandardButton::Ok) \
{ \
return ShowMessage(Icon::level, title, text, buttons, parent); \
} \
inline StandardButton level(const QString title, \
const QString &text, \
StandardButtons buttons \
= StandardButton::Ok) \
{ \
return ShowMessage(Icon::level, title, text, buttons, rootObject); \
QObject* parent = nullptr);
#define UTIL_OVERRIDES(level) \
inline StandardButton level(QObject* parent, const QString& title, const QString& text, \
StandardButtons buttons) { \
return ShowMessage(Icon::level, title, text, buttons, parent); \
} \
inline StandardButton level(QObject* parent, const QString& title, const QString& text, \
int buttons = StandardButton::Ok) { \
return ShowMessage(Icon::level, title, text, StandardButtons(buttons), parent); \
} \
inline StandardButton level(const QString title, const QString& text, \
StandardButtons buttons) { \
return ShowMessage(Icon::level, title, text, buttons, rootObject); \
} \
inline StandardButton level(const QString& title, const QString& text, \
int buttons = StandardButton::Ok) { \
return ShowMessage(Icon::level, title, text, StandardButtons(buttons), rootObject); \
}
UTIL_OVERRIDES(Information)
@ -123,27 +95,17 @@ UTIL_OVERRIDES(Warning)
UTIL_OVERRIDES(Critical)
UTIL_OVERRIDES(Question)
const QString GetOpenFileName(const QString &title,
const QString &dir,
const QString &filter,
QString *selectedFilter = nullptr,
Options options = Options());
const QStringList GetOpenFileNames(const QString &title,
const QString &dir,
const QString &filter,
QString *selectedFilter = nullptr,
Options options = Options());
const QString GetSaveFileName(const QString &title,
const QString &dir,
const QString &filter,
QString *selectedFilter = nullptr,
Options options = Options());
const QString GetExistingDirectory(const QString &caption = QString(),
const QString &dir = QString(),
Options options = Option::ShowDirsOnly);
const QString GetOpenFileName(const QString& title, const QString& dir, const QString& filter,
QString* selectedFilter = nullptr);
const QStringList GetOpenFileNames(const QString& title, const QString& dir, const QString& filter,
QString* selectedFilter = nullptr);
const QString GetSaveFileName(const QString& title, const QString& dir, const QString& filter,
QString* selectedFilter = nullptr);
const QString GetExistingDirectory(const QString& caption = QString(),
const QString& dir = QString());
int Choice(const QString& title = QString(), const QString& caption = QString(),
const QStringList& options = {});

17
src/qt_common/abstract/progress.cpp

@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "progress.h"
namespace QtCommon::Frontend {
QtProgressDialog::QtProgressDialog(const QString&,
const QString&,
int,
int,
QObject* parent,
Qt::WindowFlags)
: QObject(parent)
{}
}

45
src/qt_common/abstract/progress.h

@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <memory>
#include <QObject>
namespace QtCommon::Frontend {
class QtProgressDialog : public QObject {
Q_OBJECT
public:
QtProgressDialog(const QString& labelText, const QString& cancelButtonText, int minimum,
int maximum, QObject* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
virtual ~QtProgressDialog() = default;
virtual bool wasCanceled() const = 0;
virtual void setWindowModality(Qt::WindowModality modality) = 0;
virtual void setMinimumDuration(int durationMs) = 0;
virtual void setAutoClose(bool autoClose) = 0;
virtual void setAutoReset(bool autoReset) = 0;
public slots:
virtual void setTitle(QString title) = 0;
virtual void setLabelText(QString text) = 0;
virtual void setMinimum(int min) = 0;
virtual void setMaximum(int max) = 0;
virtual void setValue(int value) = 0;
virtual bool close() = 0;
virtual void show() = 0;
};
std::unique_ptr<QtProgressDialog> newProgressDialog(const QString& labelText,
const QString& cancelButtonText, int minimum,
int maximum,
Qt::WindowFlags f = Qt::WindowFlags());
QtProgressDialog* newProgressDialogPtr(const QString& labelText, const QString& cancelButtonText,
int minimum, int maximum,
Qt::WindowFlags f = Qt::WindowFlags());
} // namespace QtCommon::Frontend

4
src/qt_common/abstract/qt_progress_dialog.cpp

@ -1,4 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "qt_progress_dialog.h"

47
src/qt_common/abstract/qt_progress_dialog.h

@ -1,47 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef QT_PROGRESS_DIALOG_H
#define QT_PROGRESS_DIALOG_H
#include <QWindow>
#ifdef YUZU_QT_WIDGETS
#include <QProgressDialog>
#endif
namespace QtCommon::Frontend {
#ifdef YUZU_QT_WIDGETS
using QtProgressDialog = QProgressDialog;
// TODO(crueter): QML impl
#else
class QtProgressDialog
{
public:
QtProgressDialog(const QString &labelText,
const QString &cancelButtonText,
int minimum,
int maximum,
QObject *parent = nullptr,
Qt::WindowFlags f = Qt::WindowFlags());
bool wasCanceled() const;
void setWindowModality(Qt::WindowModality modality);
void setMinimumDuration(int durationMs);
void setAutoClose(bool autoClose);
void setAutoReset(bool autoReset);
public slots:
void setLabelText(QString &text);
void setRange(int min, int max);
void setValue(int progress);
bool close();
void show();
};
#endif // YUZU_QT_WIDGETS
}
#endif // QT_PROGRESS_DIALOG_H

10
src/qt_common/config/qt_config.cpp

@ -319,7 +319,7 @@ void QtConfig::ReadUIGamelistValues() {
}
void QtConfig::ReadUILayoutValues() {
BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
BeginGroup(Settings::TranslateCategory(Settings::Category::UiLayout));
ReadCategory(Settings::Category::UiLayout);
@ -578,10 +578,10 @@ void QtConfig::SaveMultiplayerValues() {
}
std::vector<Settings::BasicSetting*>& QtConfig::FindRelevantList(Settings::Category category) {
auto& map = Settings::values.linkage.by_category;
if (map.contains(category)) {
return Settings::values.linkage.by_category[category];
}
auto& list = Settings::values.linkage.by_category[category];
if (!list.empty())
return list;
return UISettings::values.linkage.by_category[category];
}

13
src/qt_common/qt_common.cpp

@ -3,19 +3,14 @@
#include "qt_common.h"
#include "common/fs/fs.h"
#include "common/fs/ryujinx_compat.h"
#include <QGuiApplication>
#include <QStringLiteral>
#include "common/logging/log.h"
#include "core/frontend/emu_window.h"
#include "qt_common/abstract/frontend.h"
#include "qt_common/qt_string_lookup.h"
#include <QFile>
#include <QMessageBox>
#include <JlCompress.h>
#if !defined(WIN32) && !defined(__APPLE__)
@ -27,11 +22,7 @@
namespace QtCommon {
#ifdef YUZU_QT_WIDGETS
QWidget* rootObject = nullptr;
#else
QObject* rootObject = nullptr;
#endif
std::unique_ptr<Core::System> system = nullptr;
std::shared_ptr<FileSys::RealVfsFilesystem> vfs = nullptr;
@ -118,11 +109,7 @@ const QString tr(const std::string& str)
return QGuiApplication::tr(str.c_str());
}
#ifdef YUZU_QT_WIDGETS
void Init(QWidget* root)
#else
void Init(QObject* root)
#endif
{
system = std::make_unique<Core::System>();
rootObject = root;

8
src/qt_common/qt_common.h

@ -14,11 +14,7 @@
namespace QtCommon {
#ifdef YUZU_QT_WIDGETS
extern QWidget *rootObject;
#else
extern QObject *rootObject;
#endif
extern std::unique_ptr<Core::System> system;
extern std::shared_ptr<FileSys::RealVfsFilesystem> vfs;
@ -30,11 +26,7 @@ Core::Frontend::WindowSystemType GetWindowSystemType();
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window);
#ifdef YUZU_QT_WIDGETS
void Init(QWidget *root);
#else
void Init(QObject *root);
#endif
const QString tr(const char *str);
const QString tr(const std::string &str);

162
src/qt_common/util/content.cpp

@ -12,7 +12,7 @@
#include "compress.h"
#include "qt_common/abstract/frontend.h"
#include "qt_common/abstract/qt_progress_dialog.h"
#include "qt_common/abstract/progress.h"
#include "qt_common/qt_common.h"
#include <QFuture>
@ -22,20 +22,18 @@
namespace QtCommon::Content {
bool CheckGameFirmware(u64 program_id, QObject* parent)
bool CheckGameFirmware(u64 program_id)
{
if (FirmwareManager::GameRequiresFirmware(program_id)
&& !FirmwareManager::CheckFirmwarePresence(*system)) {
auto result = QtCommon::Frontend::ShowMessage(
QMessageBox::Warning,
auto result = QtCommon::Frontend::Warning(
tr("Game Requires Firmware"),
tr("The game you are trying to launch requires firmware to boot or to get past the "
"opening menu. Please <a href='https://yuzu-mirror.github.io/help/quickstart'>"
"dump and install firmware</a>, or press \"OK\" to launch anyways."),
QMessageBox::Ok | QMessageBox::Cancel,
parent);
QtCommon::Frontend::Ok | QtCommon::Frontend::Cancel);
return result == QMessageBox::Ok;
return result == QtCommon::Frontend::Ok;
}
return true;
@ -43,26 +41,23 @@ bool CheckGameFirmware(u64 program_id, QObject* parent)
void InstallFirmware(const QString& location, bool recursive)
{
QtCommon::Frontend::QtProgressDialog progress(tr("Installing Firmware..."),
tr("Cancel"),
0,
100,
rootObject);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(100);
progress.setAutoClose(false);
progress.setAutoReset(false);
progress.show();
// Initialize a progress dialog.
auto progress = QtCommon::Frontend::newProgressDialog(tr("Installing Firmware..."),
tr("Cancel"), 0, 100);
progress->show();
QGuiApplication::processEvents();
// Declare progress callback.
auto callback = [&](size_t total_size, size_t processed_size) {
progress.setValue(static_cast<int>((processed_size * 100) / total_size));
return progress.wasCanceled();
QGuiApplication::processEvents();
progress->setValue(static_cast<int>((processed_size * 100) / total_size));
return progress->wasCanceled();
};
QString failedTitle = tr("Firmware Install Failed");
QString successTitle = tr("Firmware Install Succeeded");
QMessageBox::Icon icon;
QtCommon::Frontend::Icon icon;
FirmwareInstallResult result;
const auto ShowMessage = [&]() {
@ -104,7 +99,7 @@ void InstallFirmware(const QString& location, bool recursive)
if (out.size() <= 0) {
result = FirmwareInstallResult::NoNCAs;
icon = QMessageBox::Warning;
icon = QtCommon::Frontend::Icon::Warning;
ShowMessage();
return;
}
@ -114,7 +109,7 @@ void InstallFirmware(const QString& location, bool recursive)
if (sysnand_content_vdir->IsWritable()
&& !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) {
result = FirmwareInstallResult::FailedDelete;
icon = QMessageBox::Critical;
icon = QtCommon::Frontend::Icon::Critical;
ShowMessage();
return;
}
@ -145,7 +140,7 @@ void InstallFirmware(const QString& location, bool recursive)
if (callback(100, 20 + static_cast<int>(((i) / static_cast<float>(out.size())) * 70.0))) {
result = FirmwareInstallResult::FailedCorrupted;
icon = QMessageBox::Warning;
icon = QtCommon::Frontend::Icon::Warning;
ShowMessage();
return;
}
@ -153,7 +148,7 @@ void InstallFirmware(const QString& location, bool recursive)
if (!success) {
result = FirmwareInstallResult::FailedCopy;
icon = QMessageBox::Critical;
icon = QtCommon::Frontend::Icon::Critical;
ShowMessage();
return;
}
@ -162,8 +157,9 @@ void InstallFirmware(const QString& location, bool recursive)
system->GetFileSystemController().CreateFactories(*vfs);
auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) {
progress.setValue(90 + static_cast<int>((processed_size * 10) / total_size));
return progress.wasCanceled();
QGuiApplication::processEvents();
progress->setValue(90 + static_cast<int>((processed_size * 10) / total_size));
return progress->wasCanceled();
};
auto results = ContentManager::VerifyInstalledContents(*QtCommon::system,
@ -174,14 +170,15 @@ void InstallFirmware(const QString& location, bool recursive)
if (results.size() > 0) {
const auto failed_names = QString::fromStdString(
fmt::format("{}", fmt::join(results, "\n")));
progress.close();
progress->close();
QtCommon::Frontend::Critical(
tr("Firmware integrity verification failed!"),
tr("Verification failed for the following files:\n\n%1").arg(failed_names));
return;
}
progress.close();
progress->close();
QGuiApplication::processEvents();
const auto pair = FirmwareManager::GetFirmwareVersion(*system);
const auto firmware_data = pair.first;
@ -221,19 +218,16 @@ QString UnzipFirmwareToTmp(const QString& location)
// Content //
void VerifyGameContents(const std::string& game_path)
{
QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."),
tr("Cancel"),
0,
100,
rootObject);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(100);
progress.setAutoClose(false);
progress.setAutoReset(false);
auto progress =
QtCommon::Frontend::newProgressDialog(tr("Verifying integrity..."), tr("Cancel"), 0, 100);
progress->show();
QGuiApplication::processEvents();
const auto callback = [&](size_t total_size, size_t processed_size) {
progress.setValue(static_cast<int>((processed_size * 100) / total_size));
return progress.wasCanceled();
QGuiApplication::processEvents();
progress->setValue(static_cast<int>((processed_size * 100) / total_size));
return progress->wasCanceled();
};
const auto result = ContentManager::VerifyGameContents(*system, game_path, callback);
@ -260,12 +254,8 @@ void VerifyGameContents(const std::string& game_path)
void InstallKeys()
{
const QString key_source_location
= QtCommon::Frontend::GetOpenFileName(tr("Select Dumped Keys Location"),
{},
QStringLiteral("Decryption Keys (*.keys)"),
{},
QtCommon::Frontend::Option::ReadOnly);
const QString key_source_location = QtCommon::Frontend::GetOpenFileName(
tr("Select Dumped Keys Location"), {}, QStringLiteral("Decryption Keys (*.keys)"), {});
if (key_source_location.isEmpty())
return;
@ -289,27 +279,22 @@ void InstallKeys()
void VerifyInstalledContents()
{
// Initialize a progress dialog.
QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."),
tr("Cancel"),
0,
100,
rootObject);
progress.setWindowModality(Qt::WindowModal);
progress.setMinimumDuration(100);
progress.setAutoClose(false);
progress.setAutoReset(false);
auto progress = QtCommon::Frontend::newProgressDialog(tr("Verifying integrity..."),
tr("Cancel"), 0, 100);
progress->show();
QGuiApplication::processEvents();
// Declare progress callback.
auto QtProgressCallback = [&](size_t total_size, size_t processed_size) {
progress.setValue(static_cast<int>((processed_size * 100) / total_size));
return progress.wasCanceled();
};
QGuiApplication::processEvents();
progress->setValue(static_cast<int>((processed_size * 100) / total_size));
return progress->wasCanceled(); };
const std::vector<std::string> result
= ContentManager::VerifyInstalledContents(*QtCommon::system,
*QtCommon::provider,
QtProgressCallback);
progress.close();
const std::vector<std::string> result = ContentManager::VerifyInstalledContents(
*QtCommon::system, *QtCommon::provider, QtProgressCallback);
progress->close();
if (result.empty()) {
QtCommon::Frontend::Information(tr("Integrity verification succeeded!"),
@ -374,28 +359,29 @@ void FixProfiles()
void ClearDataDir(FrontendCommon::DataManager::DataDir dir, const std::string& user_id)
{
auto result = QtCommon::Frontend::Warning(tr("Really clear data?"),
tr("Important data may be lost!"),
QMessageBox::Yes | QMessageBox::No);
using namespace QtCommon::Frontend;
auto result = Warning(tr("Really clear data?"),
tr("Important data may be lost!"),
Yes | No);
if (result != QMessageBox::Yes)
if (result != Yes)
return;
result = QtCommon::Frontend::Warning(
result = Warning(
tr("Are you REALLY sure?"),
tr("Once deleted, your data will NOT come back!\n"
"Only do this if you're 100% sure you want to delete this data."),
QMessageBox::Yes | QMessageBox::No);
Yes | No);
if (result != QMessageBox::Yes)
if (result != Yes)
return;
QtCommon::Frontend::QtProgressDialog dialog(tr("Clearing..."), QString(), 0, 0);
dialog.show();
auto dialog = newProgressDialog(tr("Clearing..."), QString(), 0, 0);
dialog->show();
FrontendCommon::DataManager::ClearDir(dir, user_id);
dialog.close();
dialog->close();
}
void ExportDataDir(FrontendCommon::DataManager::DataDir data_dir,
@ -413,18 +399,12 @@ void ExportDataDir(FrontendCommon::DataManager::DataDir data_dir,
if (zip_dump_location.isEmpty())
return;
QtProgressDialog* progress = new QtProgressDialog(
tr("Exporting data. This may take a while..."), tr("Cancel"), 0, 100, rootObject);
auto progress = QtCommon::Frontend::newProgressDialogPtr(
tr("Exporting data. This may take a while..."), tr("Cancel"), 0, 100);
progress->setWindowTitle(tr("Exporting"));
progress->setWindowModality(Qt::WindowModal);
progress->setMinimumDuration(100);
progress->setAutoClose(false);
progress->setAutoReset(false);
progress->setTitle(tr("Exporting"));
progress->show();
QGuiApplication::processEvents();
auto progress_callback = [=](size_t total_size, size_t processed_size) {
QMetaObject::invokeMethod(progress,
"setValue",
@ -485,23 +465,16 @@ void ImportDataDir(FrontendCommon::DataManager::DataDir data_dir,
"proceed?"),
StandardButton::Yes | StandardButton::No);
if (button != QMessageBox::Yes)
if (button != QtCommon::Frontend::Yes)
return;
QtProgressDialog* progress = new QtProgressDialog(
tr("Importing data. This may take a while..."), tr("Cancel"), 0, 100, rootObject);
QtProgressDialog* progress = newProgressDialogPtr(
tr("Importing data. This may take a while..."), tr("Cancel"), 0, 100);
progress->setWindowTitle(tr("Importing"));
progress->setWindowModality(Qt::WindowModal);
progress->setMinimumDuration(100);
progress->setAutoClose(false);
progress->setAutoReset(false);
progress->setTitle(tr("Importing"));
progress->show();
progress->setValue(0);
QGuiApplication::processEvents();
// to prevent GUI mangling we have to run this in a thread as well
// to prevent GUI mangling we have to run this in a thread as well
QFuture<bool> delete_future = QtConcurrent::run([=]() {
FrontendCommon::DataManager::ClearDir(data_dir, user_id);
return !progress->wasCanceled();
@ -532,7 +505,7 @@ void ImportDataDir(FrontendCommon::DataManager::DataDir data_dir,
QObject::connect(watcher, &QFutureWatcher<bool>::finished, rootObject, [=]() {
progress->close();
// this sucks
// this sucks
if (watcher->result()) {
Information(tr("Imported Successfully"), tr("Data was imported successfully."));
} else if (progress->wasCanceled()) {
@ -553,4 +526,5 @@ void ImportDataDir(FrontendCommon::DataManager::DataDir data_dir,
});
}
// TODO(crueter): Port InstallFirmware et al. from QML Branch
} // namespace QtCommon::Content

2
src/qt_common/util/content.h

@ -13,7 +13,7 @@
namespace QtCommon::Content {
//
bool CheckGameFirmware(u64 program_id, QObject *parent);
bool CheckGameFirmware(u64 program_id);
enum class FirmwareInstallResult {
Success,

24
src/qt_common/util/game.cpp

@ -403,29 +403,29 @@ void ResetMetadata(bool show_message) {
inline constexpr bool CreateShortcutMessagesGUI(ShortcutMessages imsg, const QString& game_title)
{
int result = 0;
QMessageBox::StandardButtons buttons;
using namespace QtCommon::Frontend;
int buttons;
switch (imsg) {
case ShortcutMessages::Fullscreen:
buttons = QMessageBox::Yes | QMessageBox::No;
result
= QtCommon::Frontend::Information(tr("Create Shortcut"),
tr("Do you want to launch the game in fullscreen?"),
buttons);
return result == QMessageBox::Yes;
buttons = Yes | No;
result = QtCommon::Frontend::Information(
tr("Create Shortcut"), tr("Do you want to launch the game in fullscreen?"), buttons);
return result == Yes;
case ShortcutMessages::Success:
QtCommon::Frontend::Information(tr("Shortcut Created"),
tr("Successfully created a shortcut to %1").arg(game_title));
QtCommon::Frontend::Information(
tr("Shortcut Created"), tr("Successfully created a shortcut to %1").arg(game_title));
return false;
case ShortcutMessages::Volatile:
buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel;
buttons = Ok | Cancel;
result = QtCommon::Frontend::Warning(
tr("Shortcut may be Volatile!"),
tr("This will create a shortcut to the current AppImage. This may "
"not work well if you update. Continue?"),
buttons);
return result == QMessageBox::Ok;
return result == Ok;
default:
buttons = QMessageBox::Ok;
buttons = Ok;
QtCommon::Frontend::Critical(tr("Failed to Create Shortcut"),
tr("Failed to create a shortcut to %1").arg(game_title),
buttons);

18
src/qt_common/util/path.cpp

@ -1,28 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "qt_common/util/path.h"
#include <QDesktopServices>
#include <QString>
#include <QUrl>
#include <fmt/format.h>
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "qt_common/abstract/frontend.h"
#include <fmt/format.h>
#include "qt_common/util/path.h"
namespace QtCommon::Path {
bool OpenShaderCache(u64 program_id, QObject *parent)
{
bool OpenShaderCache(u64 program_id, QObject* parent) {
const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)};
if (!Common::FS::CreateDirs(shader_cache_folder_path)) {
QtCommon::Frontend::ShowMessage(QMessageBox::Warning,
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::Ok,
parent);
QtCommon::Frontend::Warning(tr("Error Opening Shader Cache"),
tr("Failed to create or open shader cache for this title, "
"ensure your app data directory has write permissions."));
}
const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)};
@ -30,4 +26,4 @@ bool OpenShaderCache(u64 program_id, QObject *parent)
return QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path));
}
}
} // namespace QtCommon::Path

1
src/yuzu/CMakeLists.txt

@ -244,6 +244,7 @@ add_executable(yuzu
configuration/addon/mod_select_dialog.h configuration/addon/mod_select_dialog.cpp configuration/addon/mod_select_dialog.ui
render/performance_overlay.h render/performance_overlay.cpp render/performance_overlay.ui
libqt_common.h libqt_common.cpp
)
set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden")

119
src/yuzu/libqt_common.cpp

@ -0,0 +1,119 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <QFileDialog>
#include <QInputDialog>
#include <QMessageBox>
#include <QProgressDialog>
#include <QAbstractButton>
#include "libqt_common.h"
#include "qt_common/abstract/frontend.h"
#include "qt_common/abstract/progress.h"
#include "qt_common/qt_common.h"
namespace QtCommon::Frontend {
StandardButton ShowMessage(
Icon icon, const QString &title, const QString &text, StandardButtons buttons, QObject *parent)
{
QMessageBox *box = new QMessageBox(QMessageBox::Icon(int(icon)), title, text, QMessageBox::StandardButtons(int(buttons)), (QWidget *) parent);
return StandardButton(box->exec());
}
WidgetsProgressDialog::WidgetsProgressDialog(const QString& labelText,
const QString& cancelButtonText, int minimum,
int maximum, QWidget* parent, Qt::WindowFlags f)
: QtProgressDialog(labelText, cancelButtonText, minimum, maximum, parent, f),
m_dialog(new QProgressDialog(labelText, cancelButtonText, minimum, maximum, parent, f)) {
m_dialog->setAutoClose(false);
m_dialog->setAutoReset(false);
m_dialog->setMinimumDuration(100);
m_dialog->setWindowModality(Qt::WindowModal);
}
bool WidgetsProgressDialog::wasCanceled() const {
return m_dialog->wasCanceled();
}
void WidgetsProgressDialog::setWindowModality(Qt::WindowModality modality) {
m_dialog->setWindowModality(modality);
}
void WidgetsProgressDialog::setMinimumDuration(int durationMs) {
m_dialog->setMinimumDuration(durationMs);
}
void WidgetsProgressDialog::setAutoClose(bool autoClose) {
m_dialog->setAutoClose(autoClose);
}
void WidgetsProgressDialog::setAutoReset(bool autoReset) {
m_dialog->setAutoReset(autoReset);
}
void WidgetsProgressDialog::setTitle(QString title) {
m_dialog->setWindowTitle(title);
}
void WidgetsProgressDialog::setLabelText(QString text) {
m_dialog->setLabelText(text);
}
void WidgetsProgressDialog::setMinimum(int min) {
m_dialog->setMinimum(min);
}
void WidgetsProgressDialog::setMaximum(int max) {
m_dialog->setMaximum(max);
}
void WidgetsProgressDialog::setValue(int value) {
m_dialog->setValue(value);
}
bool WidgetsProgressDialog::close() {
m_dialog->close();
return true;
}
void WidgetsProgressDialog::show() {
m_dialog->show();
}
std::unique_ptr<QtProgressDialog> newProgressDialog(const QString& labelText, const QString& cancelButtonText,
int minimum, int maximum, Qt::WindowFlags f) {
return std::make_unique<WidgetsProgressDialog>(labelText, cancelButtonText, minimum, maximum,
(QWidget*)rootObject, f);
}
QtProgressDialog* newProgressDialogPtr(const QString& labelText, const QString& cancelButtonText,
int minimum, int maximum,
Qt::WindowFlags f) {
return new WidgetsProgressDialog(labelText, cancelButtonText, minimum, maximum,
(QWidget*)rootObject, f);
}
int Choice(const QString& title, const QString& caption, const QStringList& options) {
QMessageBox box(rootObject);
box.setText(caption);
box.setWindowTitle(title);
for (const QString& opt : options) {
box.addButton(opt, QMessageBox::AcceptRole);
}
box.addButton(QMessageBox::Cancel);
box.exec();
auto button = box.clickedButton();
return options.indexOf(button->text());
}
const QString GetTextInput(const QString& title, const QString& caption,
const QString& defaultText) {
return QInputDialog::getText(rootObject, title, caption, QLineEdit::Normal, defaultText);
}
} // namespace QtCommon::Frontend

37
src/yuzu/libqt_common.h

@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "qt_common/abstract/progress.h"
#include <QProgressDialog>
namespace QtCommon::Frontend {
class WidgetsProgressDialog : public QtProgressDialog {
Q_OBJECT
public:
WidgetsProgressDialog(const QString& labelText, const QString& cancelButtonText, int minimum,
int maximum, QWidget* parent = nullptr, Qt::WindowFlags f = {});
bool wasCanceled() const override;
void setWindowModality(Qt::WindowModality modality) override;
void setMinimumDuration(int durationMs) override;
void setAutoClose(bool autoClose) override;
void setAutoReset(bool autoReset) override;
public slots:
void setTitle(QString title) override;
void setLabelText(QString text) override;
void setMinimum(int min) override;
void setMaximum(int max) override;
void setValue(int value) override;
bool close() override;
void show() override;
private:
QProgressDialog* m_dialog;
};
}

3
src/yuzu/main_window.cpp

@ -1929,9 +1929,8 @@ bool MainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPar
/** firmware check */
if (!QtCommon::Content::CheckGameFirmware(params.program_id, this)) {
if (!QtCommon::Content::CheckGameFirmware(params.program_id))
return false;
}
/** Exec */
const Core::SystemResultStatus result{

Loading…
Cancel
Save