summaryrefslogtreecommitdiff
path: root/src/yuzu
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu')
-rw-r--r--src/yuzu/CMakeLists.txt3
-rw-r--r--src/yuzu/applets/qt_amiibo_settings.cpp260
-rw-r--r--src/yuzu/applets/qt_amiibo_settings.h83
-rw-r--r--src/yuzu/applets/qt_amiibo_settings.ui494
-rw-r--r--src/yuzu/compatdb.cpp1
-rw-r--r--src/yuzu/configuration/configure_profile_manager.cpp67
-rw-r--r--src/yuzu/configuration/configure_profile_manager.h27
-rw-r--r--src/yuzu/configuration/configure_profile_manager.ui6
-rw-r--r--src/yuzu/main.cpp29
-rw-r--r--src/yuzu/main.h9
10 files changed, 966 insertions, 13 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 5cc1fbf32..adad36221 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -18,6 +18,9 @@ add_executable(yuzu
about_dialog.cpp
about_dialog.h
aboutdialog.ui
+ applets/qt_amiibo_settings.cpp
+ applets/qt_amiibo_settings.h
+ applets/qt_amiibo_settings.ui
applets/qt_controller.cpp
applets/qt_controller.h
applets/qt_controller.ui
diff --git a/src/yuzu/applets/qt_amiibo_settings.cpp b/src/yuzu/applets/qt_amiibo_settings.cpp
new file mode 100644
index 000000000..efb7f6ecc
--- /dev/null
+++ b/src/yuzu/applets/qt_amiibo_settings.cpp
@@ -0,0 +1,260 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <algorithm>
+#include <thread>
+#include <fmt/format.h>
+#include <nlohmann/json.hpp>
+
+#include "common/assert.h"
+#include "common/string_util.h"
+#include "core/hle/service/nfp/nfp_device.h"
+#include "core/hle/service/nfp/nfp_result.h"
+#include "input_common/drivers/virtual_amiibo.h"
+#include "input_common/main.h"
+#include "ui_qt_amiibo_settings.h"
+#include "web_service/web_backend.h"
+#include "yuzu/applets/qt_amiibo_settings.h"
+#include "yuzu/main.h"
+
+QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent,
+ Core::Frontend::CabinetParameters parameters_,
+ InputCommon::InputSubsystem* input_subsystem_,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device_)
+ : QDialog(parent), ui(std::make_unique<Ui::QtAmiiboSettingsDialog>()),
+ input_subsystem{input_subsystem_}, nfp_device{std::move(nfp_device_)},
+ parameters(std::move(parameters_)) {
+ ui->setupUi(this);
+
+ LoadInfo();
+
+ resize(0, 0);
+}
+
+QtAmiiboSettingsDialog::~QtAmiiboSettingsDialog() = default;
+
+int QtAmiiboSettingsDialog::exec() {
+ if (!is_initalized) {
+ return QDialog::Rejected;
+ }
+ return QDialog::exec();
+}
+
+std::string QtAmiiboSettingsDialog::GetName() const {
+ return ui->amiiboCustomNameValue->text().toStdString();
+}
+
+void QtAmiiboSettingsDialog::LoadInfo() {
+ if (input_subsystem->GetVirtualAmiibo()->ReloadAmiibo() !=
+ InputCommon::VirtualAmiibo::Info::Success) {
+ return;
+ }
+
+ if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
+ nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
+ return;
+ }
+ nfp_device->Mount(Service::NFP::MountTarget::All);
+
+ LoadAmiiboInfo();
+ LoadAmiiboData();
+ LoadAmiiboGameInfo();
+
+ ui->amiiboDirectoryValue->setText(
+ QString::fromStdString(input_subsystem->GetVirtualAmiibo()->GetLastFilePath()));
+
+ SetSettingsDescription();
+ is_initalized = true;
+}
+
+void QtAmiiboSettingsDialog::LoadAmiiboInfo() {
+ Service::NFP::ModelInfo model_info{};
+ const auto model_result = nfp_device->GetModelInfo(model_info);
+
+ if (model_result.IsFailure()) {
+ ui->amiiboImageLabel->setVisible(false);
+ ui->amiiboInfoGroup->setVisible(false);
+ return;
+ }
+
+ const auto amiibo_id =
+ fmt::format("{:04x}{:02x}{:02x}{:04x}{:02x}02", Common::swap16(model_info.character_id),
+ model_info.character_variant, model_info.amiibo_type, model_info.model_number,
+ model_info.series);
+
+ LOG_DEBUG(Frontend, "Loading amiibo id {}", amiibo_id);
+ // Note: This function is not being used until we host the images on our server
+ // LoadAmiiboApiInfo(amiibo_id);
+ ui->amiiboImageLabel->setVisible(false);
+ ui->amiiboInfoGroup->setVisible(false);
+}
+
+void QtAmiiboSettingsDialog::LoadAmiiboApiInfo(std::string_view amiibo_id) {
+ // TODO: Host this data on our website
+ WebService::Client client{"https://amiiboapi.com", {}, {}};
+ WebService::Client image_client{"https://raw.githubusercontent.com", {}, {}};
+ const auto url_path = fmt::format("/api/amiibo/?id={}", amiibo_id);
+
+ const auto amiibo_json = client.GetJson(url_path, true).returned_data;
+ if (amiibo_json.empty()) {
+ ui->amiiboImageLabel->setVisible(false);
+ ui->amiiboInfoGroup->setVisible(false);
+ return;
+ }
+
+ std::string amiibo_series{};
+ std::string amiibo_name{};
+ std::string amiibo_image_url{};
+ std::string amiibo_type{};
+
+ const auto parsed_amiibo_json_json = nlohmann::json::parse(amiibo_json).at("amiibo");
+ parsed_amiibo_json_json.at("amiiboSeries").get_to(amiibo_series);
+ parsed_amiibo_json_json.at("name").get_to(amiibo_name);
+ parsed_amiibo_json_json.at("image").get_to(amiibo_image_url);
+ parsed_amiibo_json_json.at("type").get_to(amiibo_type);
+
+ ui->amiiboSeriesValue->setText(QString::fromStdString(amiibo_series));
+ ui->amiiboNameValue->setText(QString::fromStdString(amiibo_name));
+ ui->amiiboTypeValue->setText(QString::fromStdString(amiibo_type));
+
+ if (amiibo_image_url.size() < 34) {
+ ui->amiiboImageLabel->setVisible(false);
+ }
+
+ const auto image_url_path = amiibo_image_url.substr(34, amiibo_image_url.size() - 34);
+ const auto image_data = image_client.GetImage(image_url_path, true).returned_data;
+
+ if (image_data.empty()) {
+ ui->amiiboImageLabel->setVisible(false);
+ }
+
+ QPixmap pixmap;
+ pixmap.loadFromData(reinterpret_cast<const u8*>(image_data.data()),
+ static_cast<uint>(image_data.size()));
+ pixmap = pixmap.scaled(250, 350, Qt::AspectRatioMode::KeepAspectRatio,
+ Qt::TransformationMode::SmoothTransformation);
+ ui->amiiboImageLabel->setPixmap(pixmap);
+}
+
+void QtAmiiboSettingsDialog::LoadAmiiboData() {
+ Service::NFP::RegisterInfo register_info{};
+ Service::NFP::CommonInfo common_info{};
+ const auto register_result = nfp_device->GetRegisterInfo(register_info);
+ const auto common_result = nfp_device->GetCommonInfo(common_info);
+
+ if (register_result.IsFailure()) {
+ ui->creationDateValue->setDisabled(true);
+ ui->modificationDateValue->setDisabled(true);
+ ui->amiiboCustomNameValue->setReadOnly(false);
+ ui->amiiboOwnerValue->setReadOnly(false);
+ return;
+ }
+
+ if (parameters.mode == Service::NFP::CabinetMode::StartNicknameAndOwnerSettings) {
+ ui->creationDateValue->setDisabled(true);
+ ui->modificationDateValue->setDisabled(true);
+ }
+
+ const auto amiibo_name = std::string(register_info.amiibo_name.data());
+ const auto owner_name = Common::UTF16ToUTF8(register_info.mii_char_info.name.data());
+ const auto creation_date =
+ QDate(register_info.creation_date.year, register_info.creation_date.month,
+ register_info.creation_date.day);
+
+ ui->amiiboCustomNameValue->setText(QString::fromStdString(amiibo_name));
+ ui->amiiboOwnerValue->setText(QString::fromStdString(owner_name));
+ ui->amiiboCustomNameValue->setReadOnly(true);
+ ui->amiiboOwnerValue->setReadOnly(true);
+ ui->creationDateValue->setDate(creation_date);
+
+ if (common_result.IsFailure()) {
+ ui->modificationDateValue->setDisabled(true);
+ return;
+ }
+
+ const auto modification_date =
+ QDate(common_info.last_write_date.year, common_info.last_write_date.month,
+ common_info.last_write_date.day);
+ ui->modificationDateValue->setDate(modification_date);
+}
+
+void QtAmiiboSettingsDialog::LoadAmiiboGameInfo() {
+ u32 application_area_id{};
+ const auto application_result = nfp_device->GetApplicationAreaId(application_area_id);
+
+ if (application_result.IsFailure()) {
+ ui->gameIdValue->setVisible(false);
+ ui->gameIdLabel->setText(tr("No game data present"));
+ return;
+ }
+
+ SetGameDataName(application_area_id);
+}
+
+void QtAmiiboSettingsDialog::SetGameDataName(u32 application_area_id) {
+ static constexpr std::array<std::pair<u32, const char*>, 12> game_name_list = {
+ // 3ds, wii u
+ std::pair<u32, const char*>{0x10110E00, "Super Smash Bros (3DS/WiiU)"},
+ {0x00132600, "Mario & Luigi: Paper Jam"},
+ {0x0014F000, "Animal Crossing: Happy Home Designer"},
+ {0x00152600, "Chibi-Robo!: Zip Lash"},
+ {0x10161f00, "Mario Party 10"},
+ {0x1019C800, "The Legend of Zelda: Twilight Princess HD"},
+ // switch
+ {0x10162B00, "Splatoon 2"},
+ {0x1016e100, "Shovel Knight: Treasure Trove"},
+ {0x1019C800, "The Legend of Zelda: Breath of the Wild"},
+ {0x34F80200, "Super Smash Bros. Ultimate"},
+ {0x38600500, "Splatoon 3"},
+ {0x3B440400, "The Legend of Zelda: Link's Awakening"},
+ };
+
+ for (const auto& [game_id, game_name] : game_name_list) {
+ if (application_area_id == game_id) {
+ ui->gameIdValue->setText(QString::fromStdString(game_name));
+ return;
+ }
+ }
+
+ const auto application_area_string = fmt::format("{:016x}", application_area_id);
+ ui->gameIdValue->setText(QString::fromStdString(application_area_string));
+}
+
+void QtAmiiboSettingsDialog::SetSettingsDescription() {
+ switch (parameters.mode) {
+ case Service::NFP::CabinetMode::StartFormatter:
+ ui->cabinetActionDescriptionLabel->setText(
+ tr("The following amiibo data will be formatted:"));
+ break;
+ case Service::NFP::CabinetMode::StartGameDataEraser:
+ ui->cabinetActionDescriptionLabel->setText(tr("The following game data will removed:"));
+ break;
+ case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings:
+ ui->cabinetActionDescriptionLabel->setText(tr("Set nickname and owner:"));
+ break;
+ case Service::NFP::CabinetMode::StartRestorer:
+ ui->cabinetActionDescriptionLabel->setText(tr("Do you wish to restore this amiibo?"));
+ break;
+ }
+}
+
+QtAmiiboSettings::QtAmiiboSettings(GMainWindow& parent) {
+ connect(this, &QtAmiiboSettings::MainWindowShowAmiiboSettings, &parent,
+ &GMainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection);
+ connect(&parent, &GMainWindow::AmiiboSettingsFinished, this,
+ &QtAmiiboSettings::MainWindowFinished, Qt::QueuedConnection);
+}
+
+QtAmiiboSettings::~QtAmiiboSettings() = default;
+
+void QtAmiiboSettings::ShowCabinetApplet(
+ const Core::Frontend::CabinetCallback& callback_,
+ const Core::Frontend::CabinetParameters& parameters,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const {
+ callback = std::move(callback_);
+ emit MainWindowShowAmiiboSettings(parameters, nfp_device);
+}
+
+void QtAmiiboSettings::MainWindowFinished(bool is_success, const std::string& name) {
+ callback(is_success, name);
+}
diff --git a/src/yuzu/applets/qt_amiibo_settings.h b/src/yuzu/applets/qt_amiibo_settings.h
new file mode 100644
index 000000000..930c96739
--- /dev/null
+++ b/src/yuzu/applets/qt_amiibo_settings.h
@@ -0,0 +1,83 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <QDialog>
+#include "core/frontend/applets/cabinet.h"
+
+class GMainWindow;
+class QCheckBox;
+class QComboBox;
+class QDialogButtonBox;
+class QGroupBox;
+class QLabel;
+
+namespace InputCommon {
+class InputSubsystem;
+}
+
+namespace Ui {
+class QtAmiiboSettingsDialog;
+}
+
+namespace Service::NFP {
+class NfpDevice;
+} // namespace Service::NFP
+
+class QtAmiiboSettingsDialog final : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit QtAmiiboSettingsDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_,
+ InputCommon::InputSubsystem* input_subsystem_,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device_);
+ ~QtAmiiboSettingsDialog() override;
+
+ int exec() override;
+
+ std::string GetName() const;
+
+private:
+ void LoadInfo();
+ void LoadAmiiboInfo();
+ void LoadAmiiboApiInfo(std::string_view amiibo_id);
+ void LoadAmiiboData();
+ void LoadAmiiboGameInfo();
+ void SetGameDataName(u32 application_area_id);
+ void SetSettingsDescription();
+
+ std::unique_ptr<Ui::QtAmiiboSettingsDialog> ui;
+
+ InputCommon::InputSubsystem* input_subsystem;
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
+
+ // Parameters sent in from the backend HLE applet.
+ Core::Frontend::CabinetParameters parameters;
+
+ // If false amiibo settings failed to load
+ bool is_initalized{};
+};
+
+class QtAmiiboSettings final : public QObject, public Core::Frontend::CabinetApplet {
+ Q_OBJECT
+
+public:
+ explicit QtAmiiboSettings(GMainWindow& parent);
+ ~QtAmiiboSettings() override;
+
+ void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_,
+ const Core::Frontend::CabinetParameters& parameters,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override;
+
+signals:
+ void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const;
+
+private:
+ void MainWindowFinished(bool is_success, const std::string& name);
+
+ mutable Core::Frontend::CabinetCallback callback;
+};
diff --git a/src/yuzu/applets/qt_amiibo_settings.ui b/src/yuzu/applets/qt_amiibo_settings.ui
new file mode 100644
index 000000000..f377a6e61
--- /dev/null
+++ b/src/yuzu/applets/qt_amiibo_settings.ui
@@ -0,0 +1,494 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QtAmiiboSettingsDialog</class>
+ <widget class="QDialog" name="QtAmiiboSettingsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>839</width>
+ <height>500</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Amiibo Settings</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="mainControllerApplet" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_1" stretch="0,3,0">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="topControllerApplet" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <property name="leftMargin">
+ <number>20</number>
+ </property>
+ <property name="topMargin">
+ <number>15</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>15</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="cabinetActionDescriptionLabel">
+ <property name="font">
+ <font>
+ <pointsize>12</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="middleControllerApplet" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>20</number>
+ </property>
+ <property name="leftMargin">
+ <number>15</number>
+ </property>
+ <property name="rightMargin">
+ <number>15</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="amiiboImageLabel">
+ <property name="minimumSize">
+ <size>
+ <width>250</width>
+ <height>350</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>236</width>
+ <height>350</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>8</number>
+ </property>
+ <property name="bottomMargin">
+ <number>15</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="amiiboInfoGroup">
+ <property name="title">
+ <string>Amiibo Info</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <layout class="QGridLayout" name="gridLayout_1">
+ <item row="0" column="0">
+ <widget class="QLabel" name="amiiboSeriesLabel">
+ <property name="text">
+ <string>Series</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="amiiboSeriesValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="amiiboTypeLabel">
+ <property name="text">
+ <string>Type</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="amiiboTypeValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="amiiboNameLabel">
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="amiiboNameValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="amiiboDataGroup">
+ <property name="title">
+ <string>Amiibo Data</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="amiiboCustomNameLabel">
+ <property name="text">
+ <string>Custom Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="amiiboCustomNameValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maxLength">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="amiiboOwnerLabel">
+ <property name="text">
+ <string>Owner</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="amiiboOwnerValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maxLength">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="creationDateLabel">
+ <property name="text">
+ <string>Creation Date</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QDateTimeEdit" name="creationDateValue">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="minimumDate">
+ <date>
+ <year>1970</year>
+ <month>1</month>
+ <day>1</day>
+ </date>
+ </property>
+ <property name="displayFormat">
+ <string>dd/MM/yyyy</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="modificationDateLabel">
+ <property name="text">
+ <string>Modification Date</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QDateTimeEdit" name="modificationDateValue">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="minimumDate">
+ <date>
+ <year>1970</year>
+ <month>1</month>
+ <day>1</day>
+ </date>
+ </property>
+ <property name="displayFormat">
+ <string>dd/MM/yyyy </string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="gameDataGroup">
+ <property name="minimumSize">
+ <size>
+ <width>500</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Game Data</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QLabel" name="gameIdLabel">
+ <property name="text">
+ <string>Game Id</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="gameIdValue">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="MountAmiiboGroup">
+ <property name="minimumSize">
+ <size>
+ <width>500</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Mount Amiibo</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="3">
+ <widget class="QToolButton" name="amiiboDirectoryButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Maximum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>60</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="amiiboDirectoryLabel">
+ <property name="text">
+ <string>File Path</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLineEdit" name="amiiboDirectoryValue"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="bottomControllerApplet" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <property name="spacing">
+ <number>15</number>
+ </property>
+ <property name="leftMargin">
+ <number>15</number>
+ </property>
+ <property name="topMargin">
+ <number>8</number>
+ </property>
+ <property name="rightMargin">
+ <number>20</number>
+ </property>
+ <property name="bottomMargin">
+ <number>8</number>
+ </property>
+ <item alignment="Qt::AlignBottom">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>QtAmiiboSettingsDialog</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>QtAmiiboSettingsDialog</receiver>
+ <slot>reject()</slot>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index b03e71248..05f49c0d2 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -126,6 +126,7 @@ void CompatDB::Submit() {
break;
default:
LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
+ break;
}
}
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp
index 5c0217ba8..a47089988 100644
--- a/src/yuzu/configuration/configure_profile_manager.cpp
+++ b/src/yuzu/configuration/configure_profile_manager.cpp
@@ -2,6 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
+#include <functional>
+#include <QDialog>
+#include <QDialogButtonBox>
#include <QFileDialog>
#include <QGraphicsItem>
#include <QHeaderView>
@@ -108,9 +111,12 @@ ConfigureProfileManager::ConfigureProfileManager(const Core::System& system_, QW
connect(ui->pm_add, &QPushButton::clicked, this, &ConfigureProfileManager::AddUser);
connect(ui->pm_rename, &QPushButton::clicked, this, &ConfigureProfileManager::RenameUser);
- connect(ui->pm_remove, &QPushButton::clicked, this, &ConfigureProfileManager::DeleteUser);
+ connect(ui->pm_remove, &QPushButton::clicked, this,
+ &ConfigureProfileManager::ConfirmDeleteUser);
connect(ui->pm_set_image, &QPushButton::clicked, this, &ConfigureProfileManager::SetUserImage);
+ confirm_dialog = new ConfigureProfileManagerDeleteDialog(this);
+
scene = new QGraphicsScene;
ui->current_user_icon->setScene(scene);
@@ -230,26 +236,23 @@ void ConfigureProfileManager::RenameUser() {
UpdateCurrentUser();
}
-void ConfigureProfileManager::DeleteUser() {
+void ConfigureProfileManager::ConfirmDeleteUser() {
const auto index = tree_view->currentIndex().row();
const auto uuid = profile_manager->GetUser(index);
ASSERT(uuid);
const auto username = GetAccountUsername(*profile_manager, *uuid);
- const auto confirm = QMessageBox::question(
- this, tr("Confirm Delete"),
- tr("You are about to delete user with name \"%1\". Are you sure?").arg(username));
-
- if (confirm == QMessageBox::No) {
- return;
- }
+ confirm_dialog->SetInfo(username, *uuid, [this, uuid]() { DeleteUser(*uuid); });
+ confirm_dialog->show();
+}
+void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) {
if (Settings::values.current_user.GetValue() == tree_view->currentIndex().row()) {
Settings::values.current_user = 0;
}
UpdateCurrentUser();
- if (!profile_manager->RemoveUser(*uuid)) {
+ if (!profile_manager->RemoveUser(uuid)) {
return;
}
@@ -319,3 +322,47 @@ void ConfigureProfileManager::SetUserImage() {
new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)});
UpdateCurrentUser();
}
+
+ConfigureProfileManagerDeleteDialog::ConfigureProfileManagerDeleteDialog(QWidget* parent)
+ : QDialog{parent} {
+ auto dialog_vbox_layout = new QVBoxLayout(this);
+ dialog_button_box =
+ new QDialogButtonBox(QDialogButtonBox::Yes | QDialogButtonBox::No, Qt::Horizontal, parent);
+ auto label_message =
+ new QLabel(tr("Delete this user? All of the user's save data will be deleted."), this);
+ label_info = new QLabel(this);
+ auto dialog_hbox_layout_widget = new QWidget(this);
+ auto dialog_hbox_layout = new QHBoxLayout(dialog_hbox_layout_widget);
+ icon_scene = new QGraphicsScene(0, 0, 64, 64, this);
+ auto icon_view = new QGraphicsView(icon_scene, this);
+
+ dialog_hbox_layout_widget->setLayout(dialog_hbox_layout);
+ icon_view->setMaximumSize(64, 64);
+ icon_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ icon_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ this->setLayout(dialog_vbox_layout);
+ this->setWindowTitle(tr("Confirm Delete"));
+ this->setSizeGripEnabled(false);
+ dialog_vbox_layout->addWidget(label_message);
+ dialog_vbox_layout->addWidget(dialog_hbox_layout_widget);
+ dialog_vbox_layout->addWidget(dialog_button_box);
+ dialog_hbox_layout->addWidget(icon_view);
+ dialog_hbox_layout->addWidget(label_info);
+
+ connect(dialog_button_box, &QDialogButtonBox::rejected, this, [this]() { close(); });
+}
+
+ConfigureProfileManagerDeleteDialog::~ConfigureProfileManagerDeleteDialog() = default;
+
+void ConfigureProfileManagerDeleteDialog::SetInfo(const QString& username, const Common::UUID& uuid,
+ std::function<void()> accept_callback) {
+ label_info->setText(
+ tr("Name: %1\nUUID: %2").arg(username, QString::fromStdString(uuid.FormattedString())));
+ icon_scene->clear();
+ icon_scene->addPixmap(GetIcon(uuid));
+
+ connect(dialog_button_box, &QDialogButtonBox::accepted, this, [this, accept_callback]() {
+ close();
+ accept_callback();
+ });
+}
diff --git a/src/yuzu/configuration/configure_profile_manager.h b/src/yuzu/configuration/configure_profile_manager.h
index fe9033779..c4b1a334e 100644
--- a/src/yuzu/configuration/configure_profile_manager.h
+++ b/src/yuzu/configuration/configure_profile_manager.h
@@ -3,16 +3,24 @@
#pragma once
+#include <functional>
#include <memory>
+#include <QDialog>
#include <QList>
#include <QWidget>
+namespace Common {
+struct UUID;
+}
+
namespace Core {
class System;
}
class QGraphicsScene;
+class QDialogButtonBox;
+class QLabel;
class QStandardItem;
class QStandardItemModel;
class QTreeView;
@@ -26,6 +34,20 @@ namespace Ui {
class ConfigureProfileManager;
}
+class ConfigureProfileManagerDeleteDialog : public QDialog {
+public:
+ explicit ConfigureProfileManagerDeleteDialog(QWidget* parent);
+ ~ConfigureProfileManagerDeleteDialog();
+
+ void SetInfo(const QString& username, const Common::UUID& uuid,
+ std::function<void()> accept_callback);
+
+private:
+ QDialogButtonBox* dialog_button_box;
+ QGraphicsScene* icon_scene;
+ QLabel* label_info;
+};
+
class ConfigureProfileManager : public QWidget {
Q_OBJECT
@@ -47,7 +69,8 @@ private:
void SelectUser(const QModelIndex& index);
void AddUser();
void RenameUser();
- void DeleteUser();
+ void ConfirmDeleteUser();
+ void DeleteUser(const Common::UUID& uuid);
void SetUserImage();
QVBoxLayout* layout;
@@ -55,6 +78,8 @@ private:
QStandardItemModel* item_model;
QGraphicsScene* scene;
+ ConfigureProfileManagerDeleteDialog* confirm_dialog;
+
std::vector<QList<QStandardItem*>> list_items;
std::unique_ptr<Ui::ConfigureProfileManager> ui;
diff --git a/src/yuzu/configuration/configure_profile_manager.ui b/src/yuzu/configuration/configure_profile_manager.ui
index cfe7478c8..bd6dea4f4 100644
--- a/src/yuzu/configuration/configure_profile_manager.ui
+++ b/src/yuzu/configuration/configure_profile_manager.ui
@@ -57,6 +57,12 @@
<height>48</height>
</size>
</property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 032ff1cbc..4081af391 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -15,6 +15,7 @@
#endif
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
+#include "applets/qt_amiibo_settings.h"
#include "applets/qt_controller.h"
#include "applets/qt_error.h"
#include "applets/qt_profile_select.h"
@@ -26,6 +27,7 @@
#include "configuration/configure_tas.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_real.h"
+#include "core/frontend/applets/cabinet.h"
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/mii_edit.h"
@@ -361,11 +363,10 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan
}
}
LOG_INFO(Frontend, "Host CPU: {}", cpu_string);
-#endif
-
if (std::optional<int> processor_core = Common::GetProcessorCount()) {
LOG_INFO(Frontend, "Host CPU Cores: {}", *processor_core);
}
+#endif
LOG_INFO(Frontend, "Host CPU Threads: {}", processor_count);
LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString());
LOG_INFO(Frontend, "Host RAM: {:.2f} GiB",
@@ -549,6 +550,11 @@ void GMainWindow::RegisterMetaTypes() {
// Register applet types
+ // Cabinet Applet
+ qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters");
+ qRegisterMetaType<std::shared_ptr<Service::NFP::NfpDevice>>(
+ "std::shared_ptr<Service::NFP::NfpDevice>");
+
// Controller Applet
qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
@@ -570,6 +576,21 @@ void GMainWindow::RegisterMetaTypes() {
qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus");
}
+void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device) {
+ QtAmiiboSettingsDialog dialog(this, parameters, input_subsystem.get(), nfp_device);
+
+ dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
+ Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
+ dialog.setWindowModality(Qt::WindowModal);
+ if (dialog.exec() == QDialog::Rejected) {
+ emit AmiiboSettingsFinished(false, {});
+ return;
+ }
+
+ emit AmiiboSettingsFinished(true, dialog.GetName());
+}
+
void GMainWindow::ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters) {
QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get(), *system);
@@ -1547,6 +1568,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
system->SetFilesystem(vfs);
system->SetAppletFrontendSet({
+ std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings
std::make_unique<QtControllerSelector>(*this), // Controller Selector
std::make_unique<QtErrorDisplay>(*this), // Error Display
nullptr, // Mii Editor
@@ -1957,6 +1979,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
}
default:
UNIMPLEMENTED();
+ break;
}
const QString qpath = QString::fromStdString(Common::FS::PathToUTF8String(path));
@@ -3200,6 +3223,7 @@ void GMainWindow::OnToggleGpuAccuracy() {
case Settings::GPUAccuracy::Extreme:
default: {
Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High);
+ break;
}
}
@@ -3532,6 +3556,7 @@ void GMainWindow::UpdateGPUAccuracyButton() {
default: {
gpu_accuracy_button->setText(tr("GPU ERROR"));
gpu_accuracy_button->setChecked(true);
+ break;
}
}
}
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index b73f550dd..6a9992d05 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -55,6 +55,7 @@ class System;
} // namespace Core
namespace Core::Frontend {
+struct CabinetParameters;
struct ControllerParameters;
struct InlineAppearParameters;
struct InlineTextParameters;
@@ -82,6 +83,10 @@ enum class SwkbdReplyType : u32;
enum class WebExitReason : u32;
} // namespace Service::AM::Applets
+namespace Service::NFP {
+class NfpDevice;
+} // namespace Service::NFP
+
namespace Ui {
class MainWindow;
}
@@ -149,6 +154,8 @@ signals:
void UpdateInstallProgress();
+ void AmiiboSettingsFinished(bool is_success, const std::string& name);
+
void ControllerSelectorReconfigureFinished();
void ErrorDisplayFinished();
@@ -170,6 +177,8 @@ public slots:
void OnExecuteProgram(std::size_t program_index);
void OnExit();
void OnSaveConfig();
+ void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device);
void ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters);
void SoftwareKeyboardInitialize(