diff --git a/.ci/license-header.sh b/.ci/license-header.sh index 70a842e01d..6b19f91185 100755 --- a/.ci/license-header.sh +++ b/.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" ;; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dfb311b327..a9fa5314b7 100644 --- a/src/CMakeLists.txt +++ b/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() diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 65f5b1ee2b..f0522c07d2 100644 --- a/src/qt_common/CMakeLists.txt +++ b/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) diff --git a/src/qt_common/abstract/frontend.cpp b/src/qt_common/abstract/frontend.cpp index 620256c2d8..05eb550095 100644 --- a/src/qt_common/abstract/frontend.cpp +++ b/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 #include "frontend.h" -#include "qt_common/qt_common.h" - -#ifdef YUZU_QT_WIDGETS -#include -#endif - -#include -#include 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(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 diff --git a/src/qt_common/abstract/frontend.h b/src/qt_common/abstract/frontend.h index 40ef80cbb7..9b70f6849e 100644 --- a/src/qt_common/abstract/frontend.h +++ b/src/qt_common/abstract/frontend.h @@ -7,11 +7,7 @@ #include #include "qt_common/qt_common.h" -#ifdef YUZU_QT_WIDGETS #include -#include -#include -#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 = {}); diff --git a/src/qt_common/abstract/progress.cpp b/src/qt_common/abstract/progress.cpp new file mode 100644 index 0000000000..c9185a756d --- /dev/null +++ b/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) +{} + +} diff --git a/src/qt_common/abstract/progress.h b/src/qt_common/abstract/progress.h new file mode 100644 index 0000000000..b6f2975c1e --- /dev/null +++ b/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 +#include + +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 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 diff --git a/src/qt_common/abstract/qt_progress_dialog.cpp b/src/qt_common/abstract/qt_progress_dialog.cpp deleted file mode 100644 index b4bf74c8bd..0000000000 --- a/src/qt_common/abstract/qt_progress_dialog.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "qt_progress_dialog.h" diff --git a/src/qt_common/abstract/qt_progress_dialog.h b/src/qt_common/abstract/qt_progress_dialog.h deleted file mode 100644 index 17f6817ffa..0000000000 --- a/src/qt_common/abstract/qt_progress_dialog.h +++ /dev/null @@ -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 - -#ifdef YUZU_QT_WIDGETS -#include -#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 diff --git a/src/qt_common/config/qt_config.cpp b/src/qt_common/config/qt_config.cpp index c5a8f62745..2ae03ae3b8 100644 --- a/src/qt_common/config/qt_config.cpp +++ b/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& 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]; } diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index af4e4ffa61..8954bf09f2 100644 --- a/src/qt_common/qt_common.cpp +++ b/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 #include #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 -#include - #include #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 system = nullptr; std::shared_ptr 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(); rootObject = root; diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index a2700427ab..80620e9420 100644 --- a/src/qt_common/qt_common.h +++ b/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 system; extern std::shared_ptr 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); diff --git a/src/qt_common/util/content.cpp b/src/qt_common/util/content.cpp index 9ba5ab264c..dd095a40a4 100644 --- a/src/qt_common/util/content.cpp +++ b/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 @@ -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 " "dump and install firmware, 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((processed_size * 100) / total_size)); - return progress.wasCanceled(); + QGuiApplication::processEvents(); + progress->setValue(static_cast((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(((i) / static_cast(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((processed_size * 10) / total_size)); - return progress.wasCanceled(); + QGuiApplication::processEvents(); + progress->setValue(90 + static_cast((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((processed_size * 100) / total_size)); - return progress.wasCanceled(); + QGuiApplication::processEvents(); + progress->setValue(static_cast((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((processed_size * 100) / total_size)); - return progress.wasCanceled(); - }; + QGuiApplication::processEvents(); + progress->setValue(static_cast((processed_size * 100) / total_size)); + return progress->wasCanceled(); }; - const std::vector result - = ContentManager::VerifyInstalledContents(*QtCommon::system, - *QtCommon::provider, - QtProgressCallback); - progress.close(); + const std::vector 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 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::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 diff --git a/src/qt_common/util/content.h b/src/qt_common/util/content.h index 6e8642083f..38dbc170ce 100644 --- a/src/qt_common/util/content.h +++ b/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, diff --git a/src/qt_common/util/game.cpp b/src/qt_common/util/game.cpp index 34fbd04ff9..3e07b9d6b5 100644 --- a/src/qt_common/util/game.cpp +++ b/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); diff --git a/src/qt_common/util/path.cpp b/src/qt_common/util/path.cpp index 73689058c6..257cd00514 100644 --- a/src/qt_common/util/path.cpp +++ b/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 #include #include +#include #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "qt_common/abstract/frontend.h" -#include +#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 diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 99fb2fec15..982c0eb196 100644 --- a/src/yuzu/CMakeLists.txt +++ b/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") diff --git a/src/yuzu/libqt_common.cpp b/src/yuzu/libqt_common.cpp new file mode 100644 index 0000000000..6da75033af --- /dev/null +++ b/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 +#include +#include +#include +#include + +#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 newProgressDialog(const QString& labelText, const QString& cancelButtonText, + int minimum, int maximum, Qt::WindowFlags f) { + return std::make_unique(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 diff --git a/src/yuzu/libqt_common.h b/src/yuzu/libqt_common.h new file mode 100644 index 0000000000..9fb0add154 --- /dev/null +++ b/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 + +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; +}; + +} diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index 399b3bd976..aaac46bffb 100644 --- a/src/yuzu/main_window.cpp +++ b/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{