diff options
Diffstat (limited to 'src/yuzu')
22 files changed, 424 insertions, 396 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 7e883991a..3ea7b55d0 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -155,6 +155,10 @@ target_compile_definitions(yuzu PRIVATE # Use QStringBuilder for string concatenation to reduce # the overall number of temporary strings created. -DQT_USE_QSTRINGBUILDER + + # Disable implicit conversions from/to C strings + -DQT_NO_CAST_FROM_ASCII + -DQT_NO_CAST_TO_ASCII ) if (YUZU_ENABLE_COMPATIBILITY_REPORTING) diff --git a/src/yuzu/applets/error.cpp b/src/yuzu/applets/error.cpp index 106dde9e2..08ed57355 100644 --- a/src/yuzu/applets/error.cpp +++ b/src/yuzu/applets/error.cpp @@ -29,11 +29,13 @@ void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, std::function<void()> finished) const { this->callback = std::move(finished); + + const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count()); emit MainWindowDisplayError( tr("An error occured on %1 at %2.\nPlease try again or contact the " "developer of the software.\n\nError Code: %3-%4 (0x%5)") - .arg(QDateTime::fromSecsSinceEpoch(time.count()).toString("dddd, MMMM d, yyyy")) - .arg(QDateTime::fromSecsSinceEpoch(time.count()).toString("h:mm:ss A")) + .arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy"))) + .arg(date_time.toString(QStringLiteral("h:mm:ss A"))) .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) .arg(error.description, 4, 10, QChar::fromLatin1('0')) .arg(error.raw, 8, 16, QChar::fromLatin1('0'))); diff --git a/src/yuzu/applets/profile_select.cpp b/src/yuzu/applets/profile_select.cpp index 7fbc9deeb..42e26b978 100644 --- a/src/yuzu/applets/profile_select.cpp +++ b/src/yuzu/applets/profile_select.cpp @@ -27,20 +27,20 @@ constexpr std::array<u8, 107> backup_jpeg{ 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, }; -QString FormatUserEntryText(const QString& username, Service::Account::UUID uuid) { +QString FormatUserEntryText(const QString& username, Common::UUID uuid) { return QtProfileSelectionDialog::tr( "%1\n%2", "%1 is the profile username, %2 is the formatted UUID (e.g. " "00112233-4455-6677-8899-AABBCCDDEEFF))") .arg(username, QString::fromStdString(uuid.FormatSwitch())); } -QString GetImagePath(Service::Account::UUID uuid) { +QString GetImagePath(Common::UUID uuid) { const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; return QString::fromStdString(path); } -QPixmap GetIcon(Service::Account::UUID uuid) { +QPixmap GetIcon(Common::UUID uuid) { QPixmap icon{GetImagePath(uuid)}; if (!icon) { @@ -154,12 +154,12 @@ QtProfileSelector::QtProfileSelector(GMainWindow& parent) { QtProfileSelector::~QtProfileSelector() = default; void QtProfileSelector::SelectProfile( - std::function<void(std::optional<Service::Account::UUID>)> callback) const { + std::function<void(std::optional<Common::UUID>)> callback) const { this->callback = std::move(callback); emit MainWindowSelectProfile(); } -void QtProfileSelector::MainWindowFinishedSelection(std::optional<Service::Account::UUID> uuid) { +void QtProfileSelector::MainWindowFinishedSelection(std::optional<Common::UUID> uuid) { // Acquire the HLE mutex std::lock_guard lock{HLE::g_hle_lock}; callback(uuid); diff --git a/src/yuzu/applets/profile_select.h b/src/yuzu/applets/profile_select.h index 1c2922e54..c5b90a78e 100644 --- a/src/yuzu/applets/profile_select.h +++ b/src/yuzu/applets/profile_select.h @@ -9,6 +9,7 @@ #include <QList> #include <QTreeView> #include "core/frontend/applets/profile_select.h" +#include "core/hle/service/acc/profile_manager.h" class GMainWindow; class QDialogButtonBox; @@ -60,14 +61,13 @@ public: explicit QtProfileSelector(GMainWindow& parent); ~QtProfileSelector() override; - void SelectProfile( - std::function<void(std::optional<Service::Account::UUID>)> callback) const override; + void SelectProfile(std::function<void(std::optional<Common::UUID>)> callback) const override; signals: void MainWindowSelectProfile() const; private: - void MainWindowFinishedSelection(std::optional<Service::Account::UUID> uuid); + void MainWindowFinishedSelection(std::optional<Common::UUID> uuid); - mutable std::function<void(std::optional<Service::Account::UUID>)> callback; + mutable std::function<void(std::optional<Common::UUID>)> callback; }; diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp index f3eb29b25..5223ec977 100644 --- a/src/yuzu/applets/software_keyboard.cpp +++ b/src/yuzu/applets/software_keyboard.cpp @@ -18,23 +18,30 @@ QtSoftwareKeyboardValidator::QtSoftwareKeyboardValidator( : parameters(std::move(parameters)) {} QValidator::State QtSoftwareKeyboardValidator::validate(QString& input, int& pos) const { - if (input.size() > parameters.max_length) + if (input.size() > static_cast<s64>(parameters.max_length)) { return Invalid; - if (parameters.disable_space && input.contains(' ')) + } + if (parameters.disable_space && input.contains(QLatin1Char{' '})) { return Invalid; - if (parameters.disable_address && input.contains('@')) + } + if (parameters.disable_address && input.contains(QLatin1Char{'@'})) { return Invalid; - if (parameters.disable_percent && input.contains('%')) + } + if (parameters.disable_percent && input.contains(QLatin1Char{'%'})) { return Invalid; - if (parameters.disable_slash && (input.contains('/') || input.contains('\\'))) + } + if (parameters.disable_slash && + (input.contains(QLatin1Char{'/'}) || input.contains(QLatin1Char{'\\'}))) { return Invalid; + } if (parameters.disable_number && std::any_of(input.begin(), input.end(), [](QChar c) { return c.isDigit(); })) { return Invalid; } - if (parameters.disable_download_code && - std::any_of(input.begin(), input.end(), [](QChar c) { return c == 'O' || c == 'I'; })) { + if (parameters.disable_download_code && std::any_of(input.begin(), input.end(), [](QChar c) { + return c == QLatin1Char{'O'} || c == QLatin1Char{'I'}; + })) { return Invalid; } @@ -142,7 +149,7 @@ void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, void QtSoftwareKeyboard::MainWindowFinishedText(std::optional<std::u16string> text) { // Acquire the HLE mutex std::lock_guard lock{HLE::g_hle_lock}; - text_output(text); + text_output(std::move(text)); } void QtSoftwareKeyboard::MainWindowFinishedCheckDialog() { diff --git a/src/yuzu/applets/software_keyboard.h b/src/yuzu/applets/software_keyboard.h index c63720ba4..78c5a042b 100644 --- a/src/yuzu/applets/software_keyboard.h +++ b/src/yuzu/applets/software_keyboard.h @@ -6,7 +6,6 @@ #include <QDialog> #include <QValidator> -#include "common/assert.h" #include "core/frontend/applets/software_keyboard.h" class GMainWindow; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index c2783d684..afec33b61 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -26,6 +26,8 @@ EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {} +EmuThread::~EmuThread() = default; + void EmuThread::run() { render_window->MakeCurrent(); @@ -91,25 +93,25 @@ void EmuThread::run() { class GGLContext : public Core::Frontend::GraphicsContext { public: - explicit GGLContext(QOpenGLContext* shared_context) - : context{std::make_unique<QOpenGLContext>(shared_context)} { - surface.setFormat(shared_context->format()); - surface.create(); + explicit GGLContext(QOpenGLContext* shared_context) : shared_context{shared_context} { + context.setFormat(shared_context->format()); + context.setShareContext(shared_context); + context.create(); } void MakeCurrent() override { - context->makeCurrent(&surface); + context.makeCurrent(shared_context->surface()); } void DoneCurrent() override { - context->doneCurrent(); + context.doneCurrent(); } void SwapBuffers() override {} private: - std::unique_ptr<QOpenGLContext> context; - QOffscreenSurface surface; + QOpenGLContext* shared_context; + QOpenGLContext context; }; // This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL @@ -185,7 +187,7 @@ private: bool do_painting; }; -GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) +GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread) : QWidget(parent), emu_thread(emu_thread) { setWindowTitle(QStringLiteral("yuzu %1 | %2-%3") .arg(QString::fromUtf8(Common::g_build_name), @@ -194,8 +196,7 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) setAttribute(Qt::WA_AcceptTouchEvents); InputCommon::Init(); - connect(this, &GRenderWindow::FirstFrameDisplayed, static_cast<GMainWindow*>(parent), - &GMainWindow::OnLoadComplete); + connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); } GRenderWindow::~GRenderWindow() { @@ -247,9 +248,9 @@ void GRenderWindow::PollEvents() {} void GRenderWindow::OnFramebufferSizeChanged() { // Screen changes potentially incur a change in screen DPI, hence we should update the // framebuffer size - qreal pixelRatio = GetWindowPixelRatio(); - unsigned width = child->QPaintDevice::width() * pixelRatio; - unsigned height = child->QPaintDevice::height() * pixelRatio; + const qreal pixel_ratio = GetWindowPixelRatio(); + const u32 width = child->QPaintDevice::width() * pixel_ratio; + const u32 height = child->QPaintDevice::height() * pixel_ratio; UpdateCurrentFramebufferLayout(width, height); } @@ -266,7 +267,7 @@ void GRenderWindow::ForwardKeyReleaseEvent(QKeyEvent* event) { } void GRenderWindow::BackupGeometry() { - geometry = ((QWidget*)this)->saveGeometry(); + geometry = QWidget::saveGeometry(); } void GRenderWindow::RestoreGeometry() { @@ -283,10 +284,11 @@ void GRenderWindow::restoreGeometry(const QByteArray& geometry) { QByteArray GRenderWindow::saveGeometry() { // If we are a top-level widget, store the current geometry // otherwise, store the last backup - if (parent() == nullptr) - return ((QWidget*)this)->saveGeometry(); - else - return geometry; + if (parent() == nullptr) { + return QWidget::saveGeometry(); + } + + return geometry; } qreal GRenderWindow::GetWindowPixelRatio() const { @@ -294,10 +296,10 @@ qreal GRenderWindow::GetWindowPixelRatio() const { return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f; } -std::pair<unsigned, unsigned> GRenderWindow::ScaleTouch(const QPointF pos) const { +std::pair<u32, u32> GRenderWindow::ScaleTouch(const QPointF pos) const { const qreal pixel_ratio = GetWindowPixelRatio(); - return {static_cast<unsigned>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})), - static_cast<unsigned>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))}; + return {static_cast<u32>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})), + static_cast<u32>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))}; } void GRenderWindow::closeEvent(QCloseEvent* event) { @@ -353,12 +355,12 @@ void GRenderWindow::focusOutEvent(QFocusEvent* event) { InputCommon::GetKeyboard()->ReleaseAllKeys(); } -void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) { +void GRenderWindow::OnClientAreaResized(u32 width, u32 height) { NotifyClientAreaSizeChanged(std::make_pair(width, height)); } std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const { - return std::make_unique<GGLContext>(shared_context.get()); + return std::make_unique<GGLContext>(context.get()); } void GRenderWindow::InitRenderTarget() { @@ -394,7 +396,7 @@ void GRenderWindow::InitRenderTarget() { context->setShareContext(shared_context.get()); context->setFormat(fmt); context->create(); - fmt.setSwapInterval(false); + fmt.setSwapInterval(0); child = new GGLWidgetInternal(this, shared_context.get()); container = QWidget::createWindowContainer(child, this); @@ -424,24 +426,29 @@ void GRenderWindow::InitRenderTarget() { BackupGeometry(); } -void GRenderWindow::CaptureScreenshot(u16 res_scale, const QString& screenshot_path) { +void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) { auto& renderer = Core::System::GetInstance().Renderer(); - if (!res_scale) + if (res_scale == 0) { res_scale = VideoCore::GetResolutionScaleFactor(renderer); + } const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)}; screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); - renderer.RequestScreenshot(screenshot_image.bits(), - [=] { - screenshot_image.mirrored(false, true).save(screenshot_path); - LOG_INFO(Frontend, "The screenshot is saved."); - }, - layout); + renderer.RequestScreenshot( + screenshot_image.bits(), + [=] { + const std::string std_screenshot_path = screenshot_path.toStdString(); + if (screenshot_image.mirrored(false, true).save(screenshot_path)) { + LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path); + } else { + LOG_ERROR(Frontend, "Failed to save screenshot to \"{}\"", std_screenshot_path); + } + }, + layout); } -void GRenderWindow::OnMinimalClientAreaChangeRequest( - const std::pair<unsigned, unsigned>& minimal_size) { +void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) { setMinimumSize(minimal_size.first, minimal_size.second); } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 3df33aca1..2fc64895f 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -27,11 +27,12 @@ namespace VideoCore { enum class LoadCallbackStage; } -class EmuThread : public QThread { +class EmuThread final : public QThread { Q_OBJECT public: explicit EmuThread(GRenderWindow* render_window); + ~EmuThread() override; /** * Start emulation (on new thread) @@ -114,7 +115,7 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow { Q_OBJECT public: - GRenderWindow(QWidget* parent, EmuThread* emu_thread); + GRenderWindow(GMainWindow* parent, EmuThread* emu_thread); ~GRenderWindow() override; // EmuWindow implementation @@ -133,17 +134,17 @@ public: QByteArray saveGeometry(); // overridden qreal GetWindowPixelRatio() const; - std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const; + std::pair<u32, u32> ScaleTouch(QPointF pos) const; void closeEvent(QCloseEvent* event) override; bool event(QEvent* event) override; void focusOutEvent(QFocusEvent* event) override; - void OnClientAreaResized(unsigned width, unsigned height); + void OnClientAreaResized(u32 width, u32 height); void InitRenderTarget(); - void CaptureScreenshot(u16 res_scale, const QString& screenshot_path); + void CaptureScreenshot(u32 res_scale, const QString& screenshot_path); public slots: void moveContext(); // overridden @@ -162,8 +163,7 @@ private: void TouchUpdateEvent(const QTouchEvent* event); void TouchEndEvent(); - void OnMinimalClientAreaChangeRequest( - const std::pair<unsigned, unsigned>& minimal_size) override; + void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override; QWidget* container = nullptr; GGLWidgetInternal* child = nullptr; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index db27da23e..b1942bedc 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -645,6 +645,8 @@ void Config::ReadUIGamelistValues() { UISettings::values.icon_size = ReadSetting(QStringLiteral("icon_size"), 64).toUInt(); UISettings::values.row_1_text_id = ReadSetting(QStringLiteral("row_1_text_id"), 3).toUInt(); UISettings::values.row_2_text_id = ReadSetting(QStringLiteral("row_2_text_id"), 2).toUInt(); + UISettings::values.cache_game_list = + ReadSetting(QStringLiteral("cache_game_list"), true).toBool(); qt_config->endGroup(); } @@ -1009,6 +1011,7 @@ void Config::SaveUIGamelistValues() { WriteSetting(QStringLiteral("icon_size"), UISettings::values.icon_size, 64); WriteSetting(QStringLiteral("row_1_text_id"), UISettings::values.row_1_text_id, 3); WriteSetting(QStringLiteral("row_2_text_id"), UISettings::values.row_2_text_id, 2); + WriteSetting(QStringLiteral("cache_game_list"), UISettings::values.cache_game_list, true); qt_config->endGroup(); } diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 32c05b797..8086f9d6b 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -25,9 +25,6 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry) adjustSize(); ui->selectorList->setCurrentRow(0); - - // Synchronise lists upon initialisation - ui->hotkeysTab->EmitHotkeysChanged(); } ConfigureDialog::~ConfigureDialog() = default; diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index a7a8752e5..9fb970c21 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -31,22 +31,6 @@ ConfigureHotkeys::ConfigureHotkeys(QWidget* parent) ConfigureHotkeys::~ConfigureHotkeys() = default; -void ConfigureHotkeys::EmitHotkeysChanged() { - emit HotkeysChanged(GetUsedKeyList()); -} - -QList<QKeySequence> ConfigureHotkeys::GetUsedKeyList() const { - QList<QKeySequence> list; - for (int r = 0; r < model->rowCount(); r++) { - const QStandardItem* parent = model->item(r, 0); - for (int r2 = 0; r2 < parent->rowCount(); r2++) { - const QStandardItem* keyseq = parent->child(r2, 1); - list << QKeySequence::fromString(keyseq->text(), QKeySequence::NativeText); - } - } - return list; -} - void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { for (const auto& group : registry.hotkey_groups) { auto* parent_item = new QStandardItem(group.first); @@ -83,16 +67,29 @@ void ConfigureHotkeys::Configure(QModelIndex index) { } if (IsUsedKey(key_sequence) && key_sequence != QKeySequence(previous_key.toString())) { - QMessageBox::critical(this, tr("Error in inputted key"), - tr("You're using a key that's already bound.")); + QMessageBox::warning(this, tr("Conflicting Key Sequence"), + tr("The entered key sequence is already assigned to another hotkey.")); } else { model->setData(index, key_sequence.toString(QKeySequence::NativeText)); - EmitHotkeysChanged(); } } bool ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) const { - return GetUsedKeyList().contains(key_sequence); + for (int r = 0; r < model->rowCount(); r++) { + const QStandardItem* const parent = model->item(r, 0); + + for (int r2 = 0; r2 < parent->rowCount(); r2++) { + const QStandardItem* const key_seq_item = parent->child(r2, 1); + const auto key_seq_str = key_seq_item->text(); + const auto key_seq = QKeySequence::fromString(key_seq_str, QKeySequence::NativeText); + + if (key_sequence == key_seq) { + return true; + } + } + } + + return false; } void ConfigureHotkeys::applyConfiguration(HotkeyRegistry& registry) { @@ -114,7 +111,6 @@ void ConfigureHotkeys::applyConfiguration(HotkeyRegistry& registry) { } registry.SaveHotkeys(); - Settings::Apply(); } void ConfigureHotkeys::retranslateUi() { diff --git a/src/yuzu/configuration/configure_hotkeys.h b/src/yuzu/configuration/configure_hotkeys.h index 73fb8a175..e77d73c35 100644 --- a/src/yuzu/configuration/configure_hotkeys.h +++ b/src/yuzu/configuration/configure_hotkeys.h @@ -24,8 +24,6 @@ public: void applyConfiguration(HotkeyRegistry& registry); void retranslateUi(); - void EmitHotkeysChanged(); - /** * Populates the hotkey list widget using data from the provided registry. * Called everytime the Configure dialog is opened. @@ -33,13 +31,9 @@ public: */ void Populate(const HotkeyRegistry& registry); -signals: - void HotkeysChanged(QList<QKeySequence> new_key_list); - private: void Configure(QModelIndex index); bool IsUsedKey(QKeySequence key_sequence) const; - QList<QKeySequence> GetUsedKeyList() const; std::unique_ptr<Ui::ConfigureHotkeys> ui; diff --git a/src/yuzu/configuration/configure_per_general.cpp b/src/yuzu/configuration/configure_per_general.cpp index 2bdfc8e5a..c3e68fdf5 100644 --- a/src/yuzu/configuration/configure_per_general.cpp +++ b/src/yuzu/configuration/configure_per_general.cpp @@ -13,6 +13,8 @@ #include <QTimer> #include <QTreeView> +#include "common/common_paths.h" +#include "common/file_util.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/xts_archive.h" @@ -79,6 +81,14 @@ void ConfigurePerGameGeneral::applyConfiguration() { disabled_addons.push_back(item.front()->text().toStdString()); } + auto current = Settings::values.disabled_addons[title_id]; + std::sort(disabled_addons.begin(), disabled_addons.end()); + std::sort(current.begin(), current.end()); + if (disabled_addons != current) { + FileUtil::Delete(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP + + "game_list" + DIR_SEP + fmt::format("{:016X}.pv.txt", title_id)); + } + Settings::values.disabled_addons[title_id] = disabled_addons; } diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp index 002a51780..6d7d04c98 100644 --- a/src/yuzu/configuration/configure_profile_manager.cpp +++ b/src/yuzu/configuration/configure_profile_manager.cpp @@ -33,14 +33,13 @@ constexpr std::array<u8, 107> backup_jpeg{ 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, }; -QString GetImagePath(Service::Account::UUID uuid) { +QString GetImagePath(Common::UUID uuid) { const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; return QString::fromStdString(path); } -QString GetAccountUsername(const Service::Account::ProfileManager& manager, - Service::Account::UUID uuid) { +QString GetAccountUsername(const Service::Account::ProfileManager& manager, Common::UUID uuid) { Service::Account::ProfileBase profile; if (!manager.GetProfileBase(uuid, profile)) { return {}; @@ -51,14 +50,14 @@ QString GetAccountUsername(const Service::Account::ProfileManager& manager, return QString::fromStdString(text); } -QString FormatUserEntryText(const QString& username, Service::Account::UUID uuid) { +QString FormatUserEntryText(const QString& username, Common::UUID uuid) { return ConfigureProfileManager::tr("%1\n%2", "%1 is the profile username, %2 is the formatted UUID (e.g. " "00112233-4455-6677-8899-AABBCCDDEEFF))") .arg(username, QString::fromStdString(uuid.FormatSwitch())); } -QPixmap GetIcon(Service::Account::UUID uuid) { +QPixmap GetIcon(Common::UUID uuid) { QPixmap icon{GetImagePath(uuid)}; if (!icon) { @@ -190,7 +189,7 @@ void ConfigureProfileManager::AddUser() { return; } - const auto uuid = Service::Account::UUID::Generate(); + const auto uuid = Common::UUID::Generate(); profile_manager->CreateNewUser(uuid, username.toStdString()); item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index ff18ace40..e588b21f2 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -16,28 +16,8 @@ #include "ui_configure_system.h" #include "yuzu/configuration/configure_system.h" -namespace { -constexpr std::array<int, 12> days_in_month = {{ - 31, - 29, - 31, - 30, - 31, - 30, - 31, - 31, - 30, - 31, - 30, - 31, -}}; -} // Anonymous namespace - ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) { ui->setupUi(this); - connect(ui->combo_birthmonth, - static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, - &ConfigureSystem::UpdateBirthdayComboBox); connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, &ConfigureSystem::RefreshConsoleID); @@ -101,31 +81,6 @@ void ConfigureSystem::applyConfiguration() { Settings::Apply(); } -void ConfigureSystem::UpdateBirthdayComboBox(int birthmonth_index) { - if (birthmonth_index < 0 || birthmonth_index >= 12) - return; - - // store current day selection - int birthday_index = ui->combo_birthday->currentIndex(); - - // get number of days in the new selected month - int days = days_in_month[birthmonth_index]; - - // if the selected day is out of range, - // reset it to 1st - if (birthday_index < 0 || birthday_index >= days) - birthday_index = 0; - - // update the day combo box - ui->combo_birthday->clear(); - for (int i = 1; i <= days; ++i) { - ui->combo_birthday->addItem(QString::number(i)); - } - - // restore the day selection - ui->combo_birthday->setCurrentIndex(birthday_index); -} - void ConfigureSystem::RefreshConsoleID() { QMessageBox::StandardButton reply; QString warning_text = tr("This will replace your current virtual Switch with a new one. " diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h index cf1e54de5..41d03c56f 100644 --- a/src/yuzu/configuration/configure_system.h +++ b/src/yuzu/configuration/configure_system.h @@ -26,14 +26,11 @@ public: private: void ReadSystemSettings(); - void UpdateBirthdayComboBox(int birthmonth_index); void RefreshConsoleID(); std::unique_ptr<Ui::ConfigureSystem> ui; bool enabled = false; - int birthmonth = 0; - int birthday = 0; int language_index = 0; int sound_index = 0; }; diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui index 073327298..65745a2f8 100644 --- a/src/yuzu/configuration/configure_system.ui +++ b/src/yuzu/configuration/configure_system.ui @@ -22,14 +22,21 @@ <string>System Settings</string> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="0"> + <item row="1" column="0"> <widget class="QLabel" name="label_sound"> <property name="text"> <string>Sound output mode</string> </property> </widget> </item> - <item row="1" column="1"> + <item row="2" column="0"> + <widget class="QLabel" name="label_console_id"> + <property name="text"> + <string>Console ID:</string> + </property> + </widget> + </item> + <item row="0" column="1"> <widget class="QComboBox" name="combo_language"> <property name="toolTip"> <string>Note: this can be overridden when region setting is auto-select</string> @@ -121,108 +128,14 @@ </item> </widget> </item> - <item row="0" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout_birthday2"> - <item> - <widget class="QComboBox" name="combo_birthmonth"> - <item> - <property name="text"> - <string>January</string> - </property> - </item> - <item> - <property name="text"> - <string>February</string> - </property> - </item> - <item> - <property name="text"> - <string>March</string> - </property> - </item> - <item> - <property name="text"> - <string>April</string> - </property> - </item> - <item> - <property name="text"> - <string>May</string> - </property> - </item> - <item> - <property name="text"> - <string>June</string> - </property> - </item> - <item> - <property name="text"> - <string>July</string> - </property> - </item> - <item> - <property name="text"> - <string>August</string> - </property> - </item> - <item> - <property name="text"> - <string>September</string> - </property> - </item> - <item> - <property name="text"> - <string>October</string> - </property> - </item> - <item> - <property name="text"> - <string>November</string> - </property> - </item> - <item> - <property name="text"> - <string>December</string> - </property> - </item> - </widget> - </item> - <item> - <widget class="QComboBox" name="combo_birthday"/> - </item> - </layout> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_console_id"> - <property name="text"> - <string>Console ID:</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="label_birthday"> - <property name="text"> - <string>Birthday</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QPushButton" name="button_regenerate_console_id"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="layoutDirection"> - <enum>Qt::RightToLeft</enum> - </property> + <item row="4" column="0"> + <widget class="QCheckBox" name="rng_seed_checkbox"> <property name="text"> - <string>Regenerate</string> + <string>RNG Seed</string> </property> </widget> </item> - <item row="2" column="1"> + <item row="1" column="1"> <widget class="QComboBox" name="combo_sound"> <item> <property name="text"> @@ -241,49 +154,37 @@ </item> </widget> </item> - <item row="5" column="0"> - <widget class="QCheckBox" name="rng_seed_checkbox"> - <property name="text"> - <string>RNG Seed</string> - </property> - </widget> - </item> - <item row="1" column="0"> + <item row="0" column="0"> <widget class="QLabel" name="label_language"> <property name="text"> <string>Language</string> </property> </widget> </item> - <item row="5" column="1"> - <widget class="QLineEdit" name="rng_seed_edit"> + <item row="2" column="1"> + <widget class="QPushButton" name="button_regenerate_console_id"> <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="font"> - <font> - <family>Lucida Console</family> - </font> - </property> - <property name="inputMask"> - <string notr="true">HHHHHHHH</string> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> </property> - <property name="maxLength"> - <number>8</number> + <property name="text"> + <string>Regenerate</string> </property> </widget> </item> - <item row="4" column="0"> + <item row="3" column="0"> <widget class="QCheckBox" name="custom_rtc_checkbox"> <property name="text"> <string>Custom RTC</string> </property> </widget> </item> - <item row="4" column="1"> + <item row="3" column="1"> <widget class="QDateTimeEdit" name="custom_rtc_edit"> <property name="minimumDate"> <date> @@ -297,6 +198,27 @@ </property> </widget> </item> + <item row="4" column="1"> + <widget class="QLineEdit" name="rng_seed_edit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <family>Lucida Console</family> + </font> + </property> + <property name="inputMask"> + <string notr="true">HHHHHHHH</string> + </property> + <property name="maxLength"> + <number>8</number> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 82d2826ba..4f30e9147 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -8,7 +8,9 @@ #include <vector> #include <QDir> +#include <QFile> #include <QFileInfo> +#include <QSettings> #include "common/common_paths.h" #include "common/file_util.h" @@ -30,13 +32,108 @@ #include "yuzu/ui_settings.h" namespace { + +QString GetGameListCachedObject(const std::string& filename, const std::string& ext, + const std::function<QString()>& generator) { + if (!UISettings::values.cache_game_list || filename == "0000000000000000") { + return generator(); + } + + const auto path = FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP + "game_list" + + DIR_SEP + filename + '.' + ext; + + FileUtil::CreateFullPath(path); + + if (!FileUtil::Exists(path)) { + const auto str = generator(); + + QFile file{QString::fromStdString(path)}; + if (file.open(QFile::WriteOnly)) { + file.write(str.toUtf8()); + } + + return str; + } + + QFile file{QString::fromStdString(path)}; + if (file.open(QFile::ReadOnly)) { + return QString::fromUtf8(file.readAll()); + } + + return generator(); +} + +std::pair<std::vector<u8>, std::string> GetGameListCachedObject( + const std::string& filename, const std::string& ext, + const std::function<std::pair<std::vector<u8>, std::string>()>& generator) { + if (!UISettings::values.cache_game_list || filename == "0000000000000000") { + return generator(); + } + + const auto path1 = FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP + "game_list" + + DIR_SEP + filename + ".jpeg"; + const auto path2 = FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP + "game_list" + + DIR_SEP + filename + ".appname.txt"; + + FileUtil::CreateFullPath(path1); + + if (!FileUtil::Exists(path1) || !FileUtil::Exists(path2)) { + const auto [icon, nacp] = generator(); + + QFile file1{QString::fromStdString(path1)}; + if (!file1.open(QFile::WriteOnly)) { + LOG_ERROR(Frontend, "Failed to open cache file."); + return generator(); + } + + if (!file1.resize(icon.size())) { + LOG_ERROR(Frontend, "Failed to resize cache file to necessary size."); + return generator(); + } + + if (file1.write(reinterpret_cast<const char*>(icon.data()), icon.size()) != icon.size()) { + LOG_ERROR(Frontend, "Failed to write data to cache file."); + return generator(); + } + + QFile file2{QString::fromStdString(path2)}; + if (file2.open(QFile::WriteOnly)) { + file2.write(nacp.data(), nacp.size()); + } + + return std::make_pair(icon, nacp); + } + + QFile file1(QString::fromStdString(path1)); + QFile file2(QString::fromStdString(path2)); + + if (!file1.open(QFile::ReadOnly)) { + LOG_ERROR(Frontend, "Failed to open cache file for reading."); + return generator(); + } + + if (!file2.open(QFile::ReadOnly)) { + LOG_ERROR(Frontend, "Failed to open cache file for reading."); + return generator(); + } + + std::vector<u8> vec(file1.size()); + if (file1.read(reinterpret_cast<char*>(vec.data()), vec.size()) != + static_cast<s64>(vec.size())) { + return generator(); + } + + const auto data = file2.readAll(); + return std::make_pair(vec, data.toStdString()); +} + void GetMetadataFromControlNCA(const FileSys::PatchManager& patch_manager, const FileSys::NCA& nca, std::vector<u8>& icon, std::string& name) { - auto [nacp, icon_file] = patch_manager.ParseControlNCA(nca); - if (icon_file != nullptr) - icon = icon_file->ReadAllBytes(); - if (nacp != nullptr) - name = nacp->GetApplicationName(); + std::tie(icon, name) = GetGameListCachedObject( + fmt::format("{:016X}", patch_manager.GetTitleID()), {}, [&patch_manager, &nca] { + const auto [nacp, icon_f] = patch_manager.ParseControlNCA(nca); + return std::make_pair(icon_f->ReadAllBytes(), nacp->GetApplicationName()); + }); } bool HasSupportedFileExtension(const std::string& file_name) { @@ -114,8 +211,11 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri }; if (UISettings::values.show_add_ons) { - list.insert( - 2, new GameListItem(FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()))); + const auto patch_versions = GetGameListCachedObject( + fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] { + return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); + }); + list.insert(2, new GameListItem(patch_versions)); } return list; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a59abf6e8..f8a0daebd 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -281,7 +281,7 @@ void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) { NXInputWebEngineView web_browser_view(this); - // Scope to contain the QProgressDialog for initalization + // Scope to contain the QProgressDialog for initialization { QProgressDialog progress(this); progress.setMinimumDuration(200); @@ -301,7 +301,7 @@ void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view QWebEngineScript nx_shim; nx_shim.setSourceCode(GetNXShimInjectionScript()); nx_shim.setWorldId(QWebEngineScript::MainWorld); - nx_shim.setName("nx_inject.js"); + nx_shim.setName(QStringLiteral("nx_inject.js")); nx_shim.setInjectionPoint(QWebEngineScript::DocumentCreation); nx_shim.setRunsOnSubFrames(true); web_browser_view.page()->profile()->scripts()->insert(nx_shim); @@ -347,7 +347,7 @@ void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view const auto fire_js_keypress = [&web_browser_view](u32 key_code) { web_browser_view.page()->runJavaScript( QStringLiteral("document.dispatchEvent(new KeyboardEvent('keydown', {'key': %1}));") - .arg(QString::fromStdString(std::to_string(key_code)))); + .arg(key_code)); }; QMessageBox::information( @@ -468,7 +468,7 @@ void GMainWindow::InitializeWidgets() { statusBar()->addPermanentWidget(label, 0); } statusBar()->setVisible(true); - setStyleSheet("QStatusBar::item{border: none;}"); + setStyleSheet(QStringLiteral("QStatusBar::item{border: none;}")); } void GMainWindow::InitializeDebugWidgets() { @@ -518,58 +518,67 @@ void GMainWindow::InitializeRecentFileMenuActions() { void GMainWindow::InitializeHotkeys() { hotkey_registry.LoadHotkeys(); - ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Load File")); + const QString main_window = QStringLiteral("Main Window"); + const QString load_file = QStringLiteral("Load File"); + const QString exit_yuzu = QStringLiteral("Exit yuzu"); + const QString stop_emulation = QStringLiteral("Stop Emulation"); + const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar"); + const QString toggle_status_bar = QStringLiteral("Toggle Status Bar"); + const QString fullscreen = QStringLiteral("Fullscreen"); + + ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file)); ui.action_Load_File->setShortcutContext( - hotkey_registry.GetShortcutContext("Main Window", "Load File")); + hotkey_registry.GetShortcutContext(main_window, load_file)); - ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Exit yuzu")); - ui.action_Exit->setShortcutContext( - hotkey_registry.GetShortcutContext("Main Window", "Exit yuzu")); + ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu)); + ui.action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu)); - ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Stop Emulation")); + ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation)); ui.action_Stop->setShortcutContext( - hotkey_registry.GetShortcutContext("Main Window", "Stop Emulation")); + hotkey_registry.GetShortcutContext(main_window, stop_emulation)); ui.action_Show_Filter_Bar->setShortcut( - hotkey_registry.GetKeySequence("Main Window", "Toggle Filter Bar")); + hotkey_registry.GetKeySequence(main_window, toggle_filter_bar)); ui.action_Show_Filter_Bar->setShortcutContext( - hotkey_registry.GetShortcutContext("Main Window", "Toggle Filter Bar")); + hotkey_registry.GetShortcutContext(main_window, toggle_filter_bar)); ui.action_Show_Status_Bar->setShortcut( - hotkey_registry.GetKeySequence("Main Window", "Toggle Status Bar")); + hotkey_registry.GetKeySequence(main_window, toggle_status_bar)); ui.action_Show_Status_Bar->setShortcutContext( - hotkey_registry.GetShortcutContext("Main Window", "Toggle Status Bar")); - - connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, - this, &GMainWindow::OnMenuLoadFile); - connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause Emulation", this), - &QShortcut::activated, this, [&] { - if (emulation_running) { - if (emu_thread->IsRunning()) { - OnPauseGame(); - } else { - OnStartGame(); - } + hotkey_registry.GetShortcutContext(main_window, toggle_status_bar)); + + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), + &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); + connect( + hotkey_registry.GetHotkey(main_window, QStringLiteral("Continue/Pause Emulation"), this), + &QShortcut::activated, this, [&] { + if (emulation_running) { + if (emu_thread->IsRunning()) { + OnPauseGame(); + } else { + OnStartGame(); } - }); - connect(hotkey_registry.GetHotkey("Main Window", "Restart Emulation", this), + } + }); + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Restart Emulation"), this), &QShortcut::activated, this, [this] { - if (!Core::System::GetInstance().IsPoweredOn()) + if (!Core::System::GetInstance().IsPoweredOn()) { return; - BootGame(QString(game_path)); + } + BootGame(game_path); }); - connect(hotkey_registry.GetHotkey("Main Window", "Fullscreen", render_window), + connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window), &QShortcut::activated, ui.action_Fullscreen, &QAction::trigger); - connect(hotkey_registry.GetHotkey("Main Window", "Fullscreen", render_window), + connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window), &QShortcut::activatedAmbiguously, ui.action_Fullscreen, &QAction::trigger); - connect(hotkey_registry.GetHotkey("Main Window", "Exit Fullscreen", this), + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this), &QShortcut::activated, this, [&] { if (emulation_running) { ui.action_Fullscreen->setChecked(false); ToggleFullscreen(); } }); - connect(hotkey_registry.GetHotkey("Main Window", "Toggle Speed Limit", this), + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this), &QShortcut::activated, this, [&] { Settings::values.use_frame_limit = !Settings::values.use_frame_limit; UpdateStatusBar(); @@ -578,33 +587,33 @@ void GMainWindow::InitializeHotkeys() { // MSVC occurs and we make it a requirement (see: // https://developercommunity.visualstudio.com/content/problem/93922/constexprs-are-trying-to-be-captured-in-lambda-fun.html) static constexpr u16 SPEED_LIMIT_STEP = 5; - connect(hotkey_registry.GetHotkey("Main Window", "Increase Speed Limit", this), + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this), &QShortcut::activated, this, [&] { if (Settings::values.frame_limit < 9999 - SPEED_LIMIT_STEP) { Settings::values.frame_limit += SPEED_LIMIT_STEP; UpdateStatusBar(); } }); - connect(hotkey_registry.GetHotkey("Main Window", "Decrease Speed Limit", this), + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this), &QShortcut::activated, this, [&] { if (Settings::values.frame_limit > SPEED_LIMIT_STEP) { Settings::values.frame_limit -= SPEED_LIMIT_STEP; UpdateStatusBar(); } }); - connect(hotkey_registry.GetHotkey("Main Window", "Load Amiibo", this), &QShortcut::activated, - this, [&] { + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load Amiibo"), this), + &QShortcut::activated, this, [&] { if (ui.action_Load_Amiibo->isEnabled()) { OnLoadAmiibo(); } }); - connect(hotkey_registry.GetHotkey("Main Window", "Capture Screenshot", this), + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Capture Screenshot"), this), &QShortcut::activated, this, [&] { if (emu_thread->IsRunning()) { OnCaptureScreenshot(); } }); - connect(hotkey_registry.GetHotkey("Main Window", "Change Docked Mode", this), + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Change Docked Mode"), this), &QShortcut::activated, this, [&] { Settings::values.use_docked_mode = !Settings::values.use_docked_mode; OnDockedModeChanged(!Settings::values.use_docked_mode, @@ -705,7 +714,9 @@ void GMainWindow::ConnectMenuEvents() { // Fullscreen ui.action_Fullscreen->setShortcut( - hotkey_registry.GetHotkey("Main Window", "Fullscreen", this)->key()); + hotkey_registry + .GetHotkey(QStringLiteral("Main Window"), QStringLiteral("Fullscreen"), this) + ->key()); connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); // Movie @@ -742,25 +753,33 @@ void GMainWindow::OnDisplayTitleBars(bool show) { QStringList GMainWindow::GetUnsupportedGLExtensions() { QStringList unsupported_ext; - if (!GLAD_GL_ARB_direct_state_access) - unsupported_ext.append("ARB_direct_state_access"); - if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) - unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev"); - if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) - unsupported_ext.append("ARB_texture_mirror_clamp_to_edge"); - if (!GLAD_GL_ARB_multi_bind) - unsupported_ext.append("ARB_multi_bind"); + if (!GLAD_GL_ARB_direct_state_access) { + unsupported_ext.append(QStringLiteral("ARB_direct_state_access")); + } + if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) { + unsupported_ext.append(QStringLiteral("ARB_vertex_type_10f_11f_11f_rev")); + } + if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) { + unsupported_ext.append(QStringLiteral("ARB_texture_mirror_clamp_to_edge")); + } + if (!GLAD_GL_ARB_multi_bind) { + unsupported_ext.append(QStringLiteral("ARB_multi_bind")); + } // Extensions required to support some texture formats. - if (!GLAD_GL_EXT_texture_compression_s3tc) - unsupported_ext.append("EXT_texture_compression_s3tc"); - if (!GLAD_GL_ARB_texture_compression_rgtc) - unsupported_ext.append("ARB_texture_compression_rgtc"); - if (!GLAD_GL_ARB_depth_buffer_float) - unsupported_ext.append("ARB_depth_buffer_float"); - - for (const QString& ext : unsupported_ext) + if (!GLAD_GL_EXT_texture_compression_s3tc) { + unsupported_ext.append(QStringLiteral("EXT_texture_compression_s3tc")); + } + if (!GLAD_GL_ARB_texture_compression_rgtc) { + unsupported_ext.append(QStringLiteral("ARB_texture_compression_rgtc")); + } + if (!GLAD_GL_ARB_depth_buffer_float) { + unsupported_ext.append(QStringLiteral("ARB_depth_buffer_float")); + } + + for (const QString& ext : unsupported_ext) { LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext.toStdString()); + } return unsupported_ext; } @@ -782,13 +801,13 @@ bool GMainWindow::LoadROM(const QString& filename) { } } - QStringList unsupported_gl_extensions = GetUnsupportedGLExtensions(); + const QStringList unsupported_gl_extensions = GetUnsupportedGLExtensions(); if (!unsupported_gl_extensions.empty()) { QMessageBox::critical(this, tr("Error while initializing OpenGL Core!"), tr("Your GPU may not support one or more required OpenGL" "extensions. Please ensure you have the latest graphics " "driver.<br><br>Unsupported extensions:<br>") + - unsupported_gl_extensions.join("<br>")); + unsupported_gl_extensions.join(QStringLiteral("<br>"))); return false; } @@ -1007,7 +1026,7 @@ void GMainWindow::UpdateRecentFiles() { std::min(UISettings::values.recent_files.size(), max_recent_files_item); for (int i = 0; i < num_recent_files; i++) { - const QString text = QString("&%1. %2").arg(i + 1).arg( + const QString text = QStringLiteral("&%1. %2").arg(i + 1).arg( QFileInfo(UISettings::values.recent_files[i]).fileName()); actions_recent_files[i]->setText(text); actions_recent_files[i]->setData(UISettings::values.recent_files[i]); @@ -1029,10 +1048,10 @@ void GMainWindow::OnGameListLoadFile(QString game_path) { void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target) { std::string path; - std::string open_target; + QString open_target; switch (target) { case GameListOpenTarget::SaveData: { - open_target = "Save Data"; + open_target = tr("Save Data"); const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); ASSERT(program_id != 0); @@ -1069,7 +1088,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target break; } case GameListOpenTarget::ModData: { - open_target = "Mod Data"; + open_target = tr("Mod Data"); const auto load_dir = FileUtil::GetUserPath(FileUtil::UserPath::LoadDir); path = fmt::format("{}{:016X}", load_dir, program_id); break; @@ -1079,27 +1098,26 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target } const QString qpath = QString::fromStdString(path); - const QDir dir(qpath); if (!dir.exists()) { - QMessageBox::warning(this, - tr("Error Opening %1 Folder").arg(QString::fromStdString(open_target)), + QMessageBox::warning(this, tr("Error Opening %1 Folder").arg(open_target), tr("Folder does not exist!")); return; } - LOG_INFO(Frontend, "Opening {} path for program_id={:016x}", open_target, program_id); + LOG_INFO(Frontend, "Opening {} path for program_id={:016x}", open_target.toStdString(), + program_id); QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { ASSERT(program_id != 0); + const QString shader_dir = + QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)); const QString tranferable_shader_cache_folder_path = - QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)) + "opengl" + - DIR_SEP + "transferable"; - + shader_dir + QStringLiteral("opengl") + QDir::separator() + QStringLiteral("transferable"); const QString transferable_shader_cache_file_path = - tranferable_shader_cache_folder_path + DIR_SEP + + tranferable_shader_cache_folder_path + QDir::separator() + QString::fromStdString(fmt::format("{:016X}.bin", program_id)); if (!QFile::exists(transferable_shader_cache_file_path)) { @@ -1216,20 +1234,21 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa return; } - bool ok; + bool ok = false; + const QStringList selections{tr("Full"), tr("Skeleton")}; const auto res = QInputDialog::getItem( this, tr("Select RomFS Dump Mode"), tr("Please select the how you would like the RomFS dumped.<br>Full will copy all of the " "files into the new directory while <br>skeleton will only create the directory " "structure."), - {"Full", "Skeleton"}, 0, false, &ok); + selections, 0, false, &ok); if (!ok) { failed(); vfs->DeleteDirectory(path); return; } - const auto full = res == "Full"; + const auto full = res == selections.constFirst(); const auto entry_size = CalculateRomFSEntrySize(extracted, full); QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, @@ -1259,10 +1278,11 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); QString directory; - if (it != compatibility_list.end()) + if (it != compatibility_list.end()) { directory = it->second.second; + } - QDesktopServices::openUrl(QUrl("https://yuzu-emu.org/game/" + directory)); + QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory)); } void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { @@ -1293,7 +1313,9 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { void GMainWindow::OnMenuLoadFile() { const QString extensions = - QString("*.").append(GameList::supported_file_extensions.join(" *.")).append(" main"); + QStringLiteral("*.") + .append(GameList::supported_file_extensions.join(QStringLiteral(" *."))) + .append(QStringLiteral(" main")); const QString file_filter = tr("Switch Executable (%1);;All Files (*.*)", "%1 is an identifier for the Switch executable file extensions.") .arg(extensions); @@ -1317,9 +1339,9 @@ void GMainWindow::OnMenuLoadFolder() { } const QDir dir{dir_path}; - const QStringList matching_main = dir.entryList(QStringList("main"), QDir::Files); + const QStringList matching_main = dir.entryList({QStringLiteral("main")}, QDir::Files); if (matching_main.size() == 1) { - BootGame(dir.path() + DIR_SEP + matching_main[0]); + BootGame(dir.path() + QDir::separator() + matching_main[0]); } else { QMessageBox::warning(this, tr("Invalid Directory Selected"), tr("The directory you have selected does not contain a 'main' file.")); @@ -1374,6 +1396,8 @@ void GMainWindow::OnMenuInstallToNAND() { tr("The file was successfully installed.")); game_list->PopulateAsync(UISettings::values.game_directory_path, UISettings::values.game_directory_deepscan); + FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + + DIR_SEP + "game_list"); }; const auto failed = [this]() { @@ -1391,11 +1415,10 @@ void GMainWindow::OnMenuInstallToNAND() { QMessageBox::Yes; }; - if (filename.endsWith("xci", Qt::CaseInsensitive) || - filename.endsWith("nsp", Qt::CaseInsensitive)) { - + if (filename.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || + filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { std::shared_ptr<FileSys::NSP> nsp; - if (filename.endsWith("nsp", Qt::CaseInsensitive)) { + if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { nsp = std::make_shared<FileSys::NSP>( vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); if (nsp->IsExtractedType()) @@ -1690,9 +1713,9 @@ void GMainWindow::OnConfigure() { } void GMainWindow::OnLoadAmiibo() { - const QString extensions{"*.bin"}; + const QString extensions{QStringLiteral("*.bin")}; const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions); - const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), "", file_filter); + const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), {}, file_filter); if (filename.isEmpty()) { return; @@ -1754,7 +1777,7 @@ void GMainWindow::OnCaptureScreenshot() { QFileDialog png_dialog(this, tr("Capture Screenshot"), UISettings::values.screenshot_path, tr("PNG Image (*.png)")); png_dialog.setAcceptMode(QFileDialog::AcceptSave); - png_dialog.setDefaultSuffix("png"); + png_dialog.setDefaultSuffix(QStringLiteral("png")); if (png_dialog.exec()) { const QString path = png_dialog.selectedFiles().first(); if (!path.isEmpty()) { @@ -1817,17 +1840,17 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det "data, or other bugs."); switch (result) { case Core::System::ResultStatus::ErrorSystemFiles: { - QString message = "yuzu was unable to locate a Switch system archive"; + QString message = tr("yuzu was unable to locate a Switch system archive"); if (!details.empty()) { - message.append(tr(": %1. ").arg(details.c_str())); + message.append(tr(": %1. ").arg(QString::fromStdString(details))); } else { - message.append(". "); + message.append(tr(". ")); } message.append(common_message); answer = QMessageBox::question(this, tr("System Archive Not Found"), message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - status_message = "System Archive Missing"; + status_message = tr("System Archive Missing"); break; } @@ -1836,7 +1859,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det message.append(common_message); answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - status_message = "Shared Font Missing"; + status_message = tr("Shared Font Missing"); break; } @@ -1852,7 +1875,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det "Continuing emulation may result in crashes, corrupted save data, or other " "bugs."), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - status_message = "Fatal Error encountered"; + status_message = tr("Fatal Error encountered"); break; } @@ -1903,18 +1926,19 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { }; QString errors; - - if (!pdm.HasFuses()) + if (!pdm.HasFuses()) { errors += tr("- Missing fuses - Cannot derive SBK\n"); - if (!pdm.HasBoot0()) + } + if (!pdm.HasBoot0()) { errors += tr("- Missing BOOT0 - Cannot derive master keys\n"); - if (!pdm.HasPackage2()) + } + if (!pdm.HasPackage2()) { errors += tr("- Missing BCPKG2-1-Normal-Main - Cannot derive general keys\n"); - if (!pdm.HasProdInfo()) + } + if (!pdm.HasProdInfo()) { errors += tr("- Missing PRODINFO - Cannot derive title keys\n"); - + } if (!errors.isEmpty()) { - QMessageBox::warning( this, tr("Warning Missing Derivation Components"), tr("The following are missing from your configuration that may hinder key " @@ -1964,13 +1988,15 @@ std::optional<u64> GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProv std::vector<u64> romfs_tids; romfs_tids.push_back(program_id); - for (const auto& entry : dlc_match) + for (const auto& entry : dlc_match) { romfs_tids.push_back(entry.title_id); + } if (romfs_tids.size() > 1) { - QStringList list{"Base"}; - for (std::size_t i = 1; i < romfs_tids.size(); ++i) + QStringList list{QStringLiteral("Base")}; + for (std::size_t i = 1; i < romfs_tids.size(); ++i) { list.push_back(QStringLiteral("DLC %1").arg(romfs_tids[i] & 0x7FF)); + } bool ok; const auto res = QInputDialog::getItem( @@ -2082,26 +2108,32 @@ void GMainWindow::filterBarSetChecked(bool state) { } void GMainWindow::UpdateUITheme() { + const QString default_icons = QStringLiteral(":/icons/default"); + const QString& current_theme = UISettings::values.theme; + const bool is_default_theme = current_theme == QString::fromUtf8(UISettings::themes[0].second); QStringList theme_paths(default_theme_paths); - if (UISettings::values.theme != UISettings::themes[0].second && - !UISettings::values.theme.isEmpty()) { - const QString theme_uri(":" + UISettings::values.theme + "/style.qss"); + + if (is_default_theme || current_theme.isEmpty()) { + qApp->setStyleSheet({}); + setStyleSheet({}); + theme_paths.append(default_icons); + QIcon::setThemeName(default_icons); + } else { + const QString theme_uri(QLatin1Char{':'} + current_theme + QStringLiteral("/style.qss")); QFile f(theme_uri); if (f.open(QFile::ReadOnly | QFile::Text)) { QTextStream ts(&f); qApp->setStyleSheet(ts.readAll()); - GMainWindow::setStyleSheet(ts.readAll()); + setStyleSheet(ts.readAll()); } else { LOG_ERROR(Frontend, "Unable to set style, stylesheet file not found"); } - theme_paths.append(QStringList{":/icons/default", ":/icons/" + UISettings::values.theme}); - QIcon::setThemeName(":/icons/" + UISettings::values.theme); - } else { - qApp->setStyleSheet(""); - GMainWindow::setStyleSheet(""); - theme_paths.append(QStringList{":/icons/default"}); - QIcon::setThemeName(":/icons/default"); + + const QString theme_name = QStringLiteral(":/icons/") + current_theme; + theme_paths.append({default_icons, theme_name}); + QIcon::setThemeName(theme_name); } + QIcon::setThemeSearchPaths(theme_paths); emit UpdateThemedIcons(); } @@ -2129,8 +2161,8 @@ int main(int argc, char* argv[]) { SCOPE_EXIT({ MicroProfileShutdown(); }); // Init settings params - QCoreApplication::setOrganizationName("yuzu team"); - QCoreApplication::setApplicationName("yuzu"); + QCoreApplication::setOrganizationName(QStringLiteral("yuzu team")); + QCoreApplication::setApplicationName(QStringLiteral("yuzu")); // Enables the core to make the qt created contexts current on std::threads QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 7bf82e665..1137bbc7a 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -104,7 +104,7 @@ signals: void ErrorDisplayFinished(); - void ProfileSelectorFinishedSelection(std::optional<Service::Account::UUID> uuid); + void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); void SoftwareKeyboardFinishedCheckDialog(); diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h index dbd318e20..a62cd6911 100644 --- a/src/yuzu/ui_settings.h +++ b/src/yuzu/ui_settings.h @@ -79,6 +79,7 @@ struct Values { uint8_t row_1_text_id; uint8_t row_2_text_id; std::atomic_bool is_game_list_reload_pending{false}; + bool cache_game_list; }; extern Values values; diff --git a/src/yuzu/util/sequence_dialog/sequence_dialog.cpp b/src/yuzu/util/sequence_dialog/sequence_dialog.cpp index d3edf6ec3..bb5f74ec4 100644 --- a/src/yuzu/util/sequence_dialog/sequence_dialog.cpp +++ b/src/yuzu/util/sequence_dialog/sequence_dialog.cpp @@ -9,16 +9,19 @@ SequenceDialog::SequenceDialog(QWidget* parent) : QDialog(parent) { setWindowTitle(tr("Enter a hotkey")); - auto* layout = new QVBoxLayout(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + key_sequence = new QKeySequenceEdit; - layout->addWidget(key_sequence); - auto* buttons = - new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal); + + auto* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); buttons->setCenterButtons(true); + + auto* const layout = new QVBoxLayout(this); + layout->addWidget(key_sequence); layout->addWidget(buttons); + connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); } SequenceDialog::~SequenceDialog() = default; |