mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-10-31 14:56:40 +08:00 
			
		
		
		
	Merge pull request #9238 from german77/cabinet_applet
service: am: Implement cabinet applet
This commit is contained in:
		
						commit
						57a05b1653
					
				| @ -120,6 +120,8 @@ add_library(core STATIC | ||||
|     file_sys/vfs_vector.h | ||||
|     file_sys/xts_archive.cpp | ||||
|     file_sys/xts_archive.h | ||||
|     frontend/applets/cabinet.cpp | ||||
|     frontend/applets/cabinet.h | ||||
|     frontend/applets/controller.cpp | ||||
|     frontend/applets/controller.h | ||||
|     frontend/applets/error.cpp | ||||
| @ -312,6 +314,8 @@ add_library(core STATIC | ||||
|     hle/service/am/applet_ae.h | ||||
|     hle/service/am/applet_oe.cpp | ||||
|     hle/service/am/applet_oe.h | ||||
|     hle/service/am/applets/applet_cabinet.cpp | ||||
|     hle/service/am/applets/applet_cabinet.h | ||||
|     hle/service/am/applets/applet_controller.cpp | ||||
|     hle/service/am/applets/applet_controller.h | ||||
|     hle/service/am/applets/applet_error.cpp | ||||
|  | ||||
							
								
								
									
										20
									
								
								src/core/frontend/applets/cabinet.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/core/frontend/applets/cabinet.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "common/logging/log.h" | ||||
| #include "core/frontend/applets/cabinet.h" | ||||
| 
 | ||||
| #include <thread> | ||||
| 
 | ||||
| namespace Core::Frontend { | ||||
| 
 | ||||
| CabinetApplet::~CabinetApplet() = default; | ||||
| 
 | ||||
| void DefaultCabinetApplet::ShowCabinetApplet( | ||||
|     const CabinetCallback& callback, const CabinetParameters& parameters, | ||||
|     std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const { | ||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||
|     callback(false, {}); | ||||
| } | ||||
| 
 | ||||
| } // namespace Core::Frontend
 | ||||
							
								
								
									
										37
									
								
								src/core/frontend/applets/cabinet.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/core/frontend/applets/cabinet.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <functional> | ||||
| #include "core/hle/service/nfp/nfp_types.h" | ||||
| 
 | ||||
| namespace Service::NFP { | ||||
| class NfpDevice; | ||||
| } // namespace Service::NFP
 | ||||
| 
 | ||||
| namespace Core::Frontend { | ||||
| 
 | ||||
| struct CabinetParameters { | ||||
|     Service::NFP::TagInfo tag_info; | ||||
|     Service::NFP::RegisterInfo register_info; | ||||
|     Service::NFP::CabinetMode mode; | ||||
| }; | ||||
| 
 | ||||
| using CabinetCallback = std::function<void(bool, const std::string&)>; | ||||
| 
 | ||||
| class CabinetApplet { | ||||
| public: | ||||
|     virtual ~CabinetApplet(); | ||||
|     virtual void ShowCabinetApplet(const CabinetCallback& callback, | ||||
|                                    const CabinetParameters& parameters, | ||||
|                                    std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0; | ||||
| }; | ||||
| 
 | ||||
| class DefaultCabinetApplet final : public CabinetApplet { | ||||
| public: | ||||
|     void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, | ||||
|                            std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Core::Frontend
 | ||||
							
								
								
									
										177
									
								
								src/core/hle/service/am/applets/applet_cabinet.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								src/core/hle/service/am/applets/applet_cabinet.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,177 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "common/assert.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/frontend/applets/cabinet.h" | ||||
| #include "core/hid/hid_core.h" | ||||
| #include "core/hle/kernel/k_event.h" | ||||
| #include "core/hle/kernel/k_readable_event.h" | ||||
| #include "core/hle/service/am/am.h" | ||||
| #include "core/hle/service/am/applets/applet_cabinet.h" | ||||
| #include "core/hle/service/mii/mii_manager.h" | ||||
| #include "core/hle/service/nfp/nfp_device.h" | ||||
| 
 | ||||
| namespace Service::AM::Applets { | ||||
| 
 | ||||
| Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, | ||||
|                  const Core::Frontend::CabinetApplet& frontend_) | ||||
|     : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ | ||||
|                                                                                system_, | ||||
|                                                                                "CabinetApplet"} { | ||||
| 
 | ||||
|     availability_change_event = | ||||
|         service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); | ||||
| } | ||||
| 
 | ||||
| Cabinet::~Cabinet() = default; | ||||
| 
 | ||||
| void Cabinet::Initialize() { | ||||
|     Applet::Initialize(); | ||||
| 
 | ||||
|     LOG_INFO(Service_HID, "Initializing Cabinet Applet."); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_HID, | ||||
|               "Initializing Applet with common_args: arg_version={}, lib_version={}, " | ||||
|               "play_startup_sound={}, size={}, system_tick={}, theme_color={}", | ||||
|               common_args.arguments_version, common_args.library_version, | ||||
|               common_args.play_startup_sound, common_args.size, common_args.system_tick, | ||||
|               common_args.theme_color); | ||||
| 
 | ||||
|     const auto storage = broker.PopNormalDataToApplet(); | ||||
|     ASSERT(storage != nullptr); | ||||
| 
 | ||||
|     const auto applet_input_data = storage->GetData(); | ||||
|     ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings)); | ||||
| 
 | ||||
|     std::memcpy(&applet_input_common, applet_input_data.data(), | ||||
|                 sizeof(StartParamForAmiiboSettings)); | ||||
| } | ||||
| 
 | ||||
| bool Cabinet::TransactionComplete() const { | ||||
|     return is_complete; | ||||
| } | ||||
| 
 | ||||
| Result Cabinet::GetStatus() const { | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| void Cabinet::ExecuteInteractive() { | ||||
|     ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); | ||||
| } | ||||
| 
 | ||||
| void Cabinet::Execute() { | ||||
|     if (is_complete) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto callback = [this](bool apply_changes, const std::string& amiibo_name) { | ||||
|         DisplayCompleted(apply_changes, amiibo_name); | ||||
|     }; | ||||
| 
 | ||||
|     // TODO: listen on all controllers
 | ||||
|     if (nfp_device == nullptr) { | ||||
|         nfp_device = std::make_shared<Service::NFP::NfpDevice>( | ||||
|             system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event); | ||||
|         nfp_device->Initialize(); | ||||
|         nfp_device->StartDetection(Service::NFP::TagProtocol::All); | ||||
|     } | ||||
| 
 | ||||
|     const Core::Frontend::CabinetParameters parameters{ | ||||
|         .tag_info = applet_input_common.tag_info, | ||||
|         .register_info = applet_input_common.register_info, | ||||
|         .mode = applet_input_common.applet_mode, | ||||
|     }; | ||||
| 
 | ||||
|     switch (applet_input_common.applet_mode) { | ||||
|     case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: | ||||
|     case Service::NFP::CabinetMode::StartGameDataEraser: | ||||
|     case Service::NFP::CabinetMode::StartRestorer: | ||||
|     case Service::NFP::CabinetMode::StartFormatter: | ||||
|         frontend.ShowCabinetApplet(callback, parameters, nfp_device); | ||||
|         break; | ||||
|     default: | ||||
|         UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); | ||||
|         DisplayCompleted(false, {}); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) { | ||||
|     Service::Mii::MiiManager manager; | ||||
|     ReturnValueForAmiiboSettings applet_output{}; | ||||
| 
 | ||||
|     if (!apply_changes) { | ||||
|         Cancel(); | ||||
|     } | ||||
| 
 | ||||
|     if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && | ||||
|         nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { | ||||
|         Cancel(); | ||||
|     } | ||||
| 
 | ||||
|     if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) { | ||||
|         nfp_device->Mount(Service::NFP::MountTarget::All); | ||||
|     } | ||||
| 
 | ||||
|     switch (applet_input_common.applet_mode) { | ||||
|     case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { | ||||
|         Service::NFP::AmiiboName name{}; | ||||
|         std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); | ||||
|         nfp_device->SetNicknameAndOwner(name); | ||||
|         break; | ||||
|     } | ||||
|     case Service::NFP::CabinetMode::StartGameDataEraser: | ||||
|         nfp_device->DeleteApplicationArea(); | ||||
|         break; | ||||
|     case Service::NFP::CabinetMode::StartRestorer: | ||||
|         nfp_device->RestoreAmiibo(); | ||||
|         break; | ||||
|     case Service::NFP::CabinetMode::StartFormatter: | ||||
|         nfp_device->DeleteAllData(); | ||||
|         break; | ||||
|     default: | ||||
|         UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     applet_output.device_handle = applet_input_common.device_handle; | ||||
|     applet_output.result = CabinetResult::Cancel; | ||||
|     const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); | ||||
|     const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); | ||||
|     nfp_device->Finalize(); | ||||
| 
 | ||||
|     if (reg_result.IsSuccess()) { | ||||
|         applet_output.result |= CabinetResult::RegisterInfo; | ||||
|     } | ||||
| 
 | ||||
|     if (tag_result.IsSuccess()) { | ||||
|         applet_output.result |= CabinetResult::TagInfo; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings)); | ||||
|     std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); | ||||
| 
 | ||||
|     is_complete = true; | ||||
| 
 | ||||
|     broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); | ||||
|     broker.SignalStateChanged(); | ||||
| } | ||||
| 
 | ||||
| void Cabinet::Cancel() { | ||||
|     ReturnValueForAmiiboSettings applet_output{}; | ||||
|     applet_output.device_handle = applet_input_common.device_handle; | ||||
|     applet_output.result = CabinetResult::Cancel; | ||||
|     nfp_device->Finalize(); | ||||
| 
 | ||||
|     std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings)); | ||||
|     std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); | ||||
| 
 | ||||
|     is_complete = true; | ||||
| 
 | ||||
|     broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); | ||||
|     broker.SignalStateChanged(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Service::AM::Applets
 | ||||
							
								
								
									
										104
									
								
								src/core/hle/service/am/applets/applet_cabinet.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/core/hle/service/am/applets/applet_cabinet.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| 
 | ||||
| #include "core/hle/result.h" | ||||
| #include "core/hle/service/am/applets/applets.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/nfp/nfp_types.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class KEvent; | ||||
| class KReadableEvent; | ||||
| } // namespace Kernel
 | ||||
| 
 | ||||
| namespace Core { | ||||
| class System; | ||||
| } // namespace Core
 | ||||
| 
 | ||||
| namespace Service::NFP { | ||||
| class NfpDevice; | ||||
| } | ||||
| 
 | ||||
| namespace Service::AM::Applets { | ||||
| 
 | ||||
| enum class CabinetAppletVersion : u32 { | ||||
|     Version1 = 0x1, | ||||
| }; | ||||
| 
 | ||||
| enum class CabinetResult : u8 { | ||||
|     Cancel = 0, | ||||
|     TagInfo = 1 << 1, | ||||
|     RegisterInfo = 1 << 2, | ||||
|     All = TagInfo | RegisterInfo, | ||||
| }; | ||||
| DECLARE_ENUM_FLAG_OPERATORS(CabinetResult) | ||||
| 
 | ||||
| // This is nn::nfp::AmiiboSettingsStartParam
 | ||||
| struct AmiiboSettingsStartParam { | ||||
|     u64 device_handle; | ||||
|     std::array<u8, 0x20> param_1; | ||||
|     u8 param_2; | ||||
| }; | ||||
| static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, | ||||
|               "AmiiboSettingsStartParam is an invalid size"); | ||||
| 
 | ||||
| #pragma pack(push, 1) | ||||
| // This is nn::nfp::StartParamForAmiiboSettings
 | ||||
| struct StartParamForAmiiboSettings { | ||||
|     u8 param_1; | ||||
|     Service::NFP::CabinetMode applet_mode; | ||||
|     u8 flags; | ||||
|     u8 amiibo_settings_1; | ||||
|     u64 device_handle; | ||||
|     Service::NFP::TagInfo tag_info; | ||||
|     Service::NFP::RegisterInfo register_info; | ||||
|     std::array<u8, 0x20> amiibo_settings_3; | ||||
|     INSERT_PADDING_BYTES(0x24); | ||||
| }; | ||||
| static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8, | ||||
|               "StartParamForAmiiboSettings is an invalid size"); | ||||
| 
 | ||||
| // This is nn::nfp::ReturnValueForAmiiboSettings
 | ||||
| struct ReturnValueForAmiiboSettings { | ||||
|     CabinetResult result; | ||||
|     INSERT_PADDING_BYTES(0x3); | ||||
|     u64 device_handle; | ||||
|     Service::NFP::TagInfo tag_info; | ||||
|     Service::NFP::RegisterInfo register_info; | ||||
|     INSERT_PADDING_BYTES(0x24); | ||||
| }; | ||||
| static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, | ||||
|               "ReturnValueForAmiiboSettings is an invalid size"); | ||||
| #pragma pack(pop) | ||||
| 
 | ||||
| class Cabinet final : public Applet { | ||||
| public: | ||||
|     explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, | ||||
|                      const Core::Frontend::CabinetApplet& frontend_); | ||||
|     ~Cabinet() override; | ||||
| 
 | ||||
|     void Initialize() override; | ||||
| 
 | ||||
|     bool TransactionComplete() const override; | ||||
|     Result GetStatus() const override; | ||||
|     void ExecuteInteractive() override; | ||||
|     void Execute() override; | ||||
|     void DisplayCompleted(bool apply_changes, std::string_view amiibo_name); | ||||
|     void Cancel(); | ||||
| 
 | ||||
| private: | ||||
|     const Core::Frontend::CabinetApplet& frontend; | ||||
|     Core::System& system; | ||||
| 
 | ||||
|     bool is_complete{false}; | ||||
|     std::shared_ptr<Service::NFP::NfpDevice> nfp_device; | ||||
|     Kernel::KEvent* availability_change_event; | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|     StartParamForAmiiboSettings applet_input_common{}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::AM::Applets
 | ||||
| @ -5,6 +5,7 @@ | ||||
| 
 | ||||
| #include "common/assert.h" | ||||
| #include "core/core.h" | ||||
| #include "core/frontend/applets/cabinet.h" | ||||
| #include "core/frontend/applets/controller.h" | ||||
| #include "core/frontend/applets/error.h" | ||||
| #include "core/frontend/applets/general_frontend.h" | ||||
| @ -16,6 +17,7 @@ | ||||
| #include "core/hle/service/am/am.h" | ||||
| #include "core/hle/service/am/applet_ae.h" | ||||
| #include "core/hle/service/am/applet_oe.h" | ||||
| #include "core/hle/service/am/applets/applet_cabinet.h" | ||||
| #include "core/hle/service/am/applets/applet_controller.h" | ||||
| #include "core/hle/service/am/applets/applet_error.h" | ||||
| #include "core/hle/service/am/applets/applet_general_backend.h" | ||||
| @ -171,13 +173,15 @@ void Applet::Initialize() { | ||||
| 
 | ||||
| AppletFrontendSet::AppletFrontendSet() = default; | ||||
| 
 | ||||
| AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, | ||||
| AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet, | ||||
|                                      ControllerApplet controller_applet, ErrorApplet error_applet, | ||||
|                                      MiiEdit mii_edit_, | ||||
|                                      ParentalControlsApplet parental_controls_applet, | ||||
|                                      PhotoViewer photo_viewer_, ProfileSelect profile_select_, | ||||
|                                      SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) | ||||
|     : controller{std::move(controller_applet)}, error{std::move(error_applet)}, | ||||
|       mii_edit{std::move(mii_edit_)}, parental_controls{std::move(parental_controls_applet)}, | ||||
|     : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)}, | ||||
|       error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)}, | ||||
|       parental_controls{std::move(parental_controls_applet)}, | ||||
|       photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, | ||||
|       software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} | ||||
| 
 | ||||
| @ -196,6 +200,10 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { | ||||
| } | ||||
| 
 | ||||
| void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { | ||||
|     if (set.cabinet != nullptr) { | ||||
|         frontend.cabinet = std::move(set.cabinet); | ||||
|     } | ||||
| 
 | ||||
|     if (set.controller != nullptr) { | ||||
|         frontend.controller = std::move(set.controller); | ||||
|     } | ||||
| @ -235,6 +243,10 @@ void AppletManager::SetDefaultAppletFrontendSet() { | ||||
| } | ||||
| 
 | ||||
| void AppletManager::SetDefaultAppletsIfMissing() { | ||||
|     if (frontend.cabinet == nullptr) { | ||||
|         frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>(); | ||||
|     } | ||||
| 
 | ||||
|     if (frontend.controller == nullptr) { | ||||
|         frontend.controller = | ||||
|             std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); | ||||
| @ -279,6 +291,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode | ||||
|     switch (id) { | ||||
|     case AppletId::Auth: | ||||
|         return std::make_shared<Auth>(system, mode, *frontend.parental_controls); | ||||
|     case AppletId::Cabinet: | ||||
|         return std::make_shared<Cabinet>(system, mode, *frontend.cabinet); | ||||
|     case AppletId::Controller: | ||||
|         return std::make_shared<Controller>(system, mode, *frontend.controller); | ||||
|     case AppletId::Error: | ||||
|  | ||||
| @ -16,6 +16,7 @@ class System; | ||||
| } | ||||
| 
 | ||||
| namespace Core::Frontend { | ||||
| class CabinetApplet; | ||||
| class ControllerApplet; | ||||
| class ECommerceApplet; | ||||
| class ErrorApplet; | ||||
| @ -176,6 +177,7 @@ protected: | ||||
| }; | ||||
| 
 | ||||
| struct AppletFrontendSet { | ||||
|     using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>; | ||||
|     using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; | ||||
|     using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; | ||||
|     using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>; | ||||
| @ -186,10 +188,11 @@ struct AppletFrontendSet { | ||||
|     using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; | ||||
| 
 | ||||
|     AppletFrontendSet(); | ||||
|     AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, | ||||
|                       MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet, | ||||
|                       PhotoViewer photo_viewer_, ProfileSelect profile_select_, | ||||
|                       SoftwareKeyboard software_keyboard_, WebBrowser web_browser_); | ||||
|     AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet, | ||||
|                       ErrorApplet error_applet, MiiEdit mii_edit_, | ||||
|                       ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, | ||||
|                       ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, | ||||
|                       WebBrowser web_browser_); | ||||
|     ~AppletFrontendSet(); | ||||
| 
 | ||||
|     AppletFrontendSet(const AppletFrontendSet&) = delete; | ||||
| @ -198,6 +201,7 @@ struct AppletFrontendSet { | ||||
|     AppletFrontendSet(AppletFrontendSet&&) noexcept; | ||||
|     AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; | ||||
| 
 | ||||
|     CabinetApplet cabinet; | ||||
|     ControllerApplet controller; | ||||
|     ErrorApplet error; | ||||
|     MiiEdit mii_edit; | ||||
|  | ||||
| @ -77,6 +77,9 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { | ||||
|         LoadAmiibo(nfc_status.data); | ||||
|         break; | ||||
|     case Common::Input::NfcState::AmiiboRemoved: | ||||
|         if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { | ||||
|             break; | ||||
|         } | ||||
|         if (device_state != DeviceState::SearchingForTag) { | ||||
|             CloseAmiibo(); | ||||
|         } | ||||
| @ -97,6 +100,8 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Filter by allowed_protocols here
 | ||||
| 
 | ||||
|     memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); | ||||
| 
 | ||||
|     device_state = DeviceState::TagFound; | ||||
| @ -143,7 +148,7 @@ void NfpDevice::Finalize() { | ||||
|     device_state = DeviceState::Unavailable; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::StartDetection(s32 protocol_) { | ||||
| Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { | ||||
|     if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { | ||||
|         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||||
|         return WrongDeviceState; | ||||
| @ -155,7 +160,7 @@ Result NfpDevice::StartDetection(s32 protocol_) { | ||||
|     } | ||||
| 
 | ||||
|     device_state = DeviceState::SearchingForTag; | ||||
|     protocol = protocol_; | ||||
|     allowed_protocols = allowed_protocol; | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| @ -469,6 +474,32 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) { | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { | ||||
|     application_area_id = {}; | ||||
| 
 | ||||
|     if (device_state != DeviceState::TagMounted) { | ||||
|         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||||
|         if (device_state == DeviceState::TagRemoved) { | ||||
|             return TagRemoved; | ||||
|         } | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||||
|         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     if (tag_data.settings.settings.appdata_initialized.Value() == 0) { | ||||
|         LOG_WARNING(Service_NFP, "Application area is not initialized"); | ||||
|         return ApplicationAreaIsNotInitialized; | ||||
|     } | ||||
| 
 | ||||
|     application_area_id = tag_data.application_area_id; | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const { | ||||
|     if (device_state != DeviceState::TagMounted) { | ||||
|         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #include <span> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_funcs.h" | ||||
| @ -37,7 +38,7 @@ public: | ||||
|     void Initialize(); | ||||
|     void Finalize(); | ||||
| 
 | ||||
|     Result StartDetection(s32 protocol_); | ||||
|     Result StartDetection(TagProtocol allowed_protocol); | ||||
|     Result StopDetection(); | ||||
|     Result Mount(MountTarget mount_target); | ||||
|     Result Unmount(); | ||||
| @ -53,6 +54,7 @@ public: | ||||
|     Result DeleteAllData(); | ||||
| 
 | ||||
|     Result OpenApplicationArea(u32 access_id); | ||||
|     Result GetApplicationAreaId(u32& application_area_id) const; | ||||
|     Result GetApplicationArea(std::vector<u8>& data) const; | ||||
|     Result SetApplicationArea(std::span<const u8> data); | ||||
|     Result CreateApplicationArea(u32 access_id, std::span<const u8> data); | ||||
| @ -88,7 +90,7 @@ private: | ||||
| 
 | ||||
|     bool is_data_moddified{}; | ||||
|     bool is_app_area_open{}; | ||||
|     s32 protocol{}; | ||||
|     TagProtocol allowed_protocols{}; | ||||
|     s64 current_posix_time{}; | ||||
|     MountTarget mount_target{MountTarget::None}; | ||||
|     DeviceState device_state{DeviceState::Unavailable}; | ||||
|  | ||||
| @ -88,11 +88,22 @@ enum class PackedTagType : u8 { | ||||
|     Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
 | ||||
| }; | ||||
| 
 | ||||
| // Verify this enum. It might be completely wrong default protocol is 0x48
 | ||||
| enum class TagProtocol : u32 { | ||||
|     None, | ||||
|     TypeA, // ISO14443A
 | ||||
|     TypeB, // ISO14443B
 | ||||
|     TypeF, // Sony Felica
 | ||||
|     TypeA = 1U << 0, // ISO14443A
 | ||||
|     TypeB = 1U << 1, // ISO14443B
 | ||||
|     TypeF = 1U << 2, // Sony Felica
 | ||||
|     Unknown1 = 1U << 3, | ||||
|     Unknown2 = 1U << 5, | ||||
|     All = 0xFFFFFFFFU, | ||||
| }; | ||||
| 
 | ||||
| enum class CabinetMode : u8 { | ||||
|     StartNicknameAndOwnerSettings, | ||||
|     StartGameDataEraser, | ||||
|     StartRestorer, | ||||
|     StartFormatter, | ||||
| }; | ||||
| 
 | ||||
| using UniqueSerialNumber = std::array<u8, 7>; | ||||
|  | ||||
| @ -130,7 +130,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) { | ||||
| void IUser::StartDetection(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto nfp_protocol{rp.Pop<s32>()}; | ||||
|     const auto nfp_protocol{rp.PopEnum<TagProtocol>()}; | ||||
|     LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|  | ||||
| @ -60,6 +60,8 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData( | ||||
|         return Common::Input::NfcState::WriteFailed; | ||||
|     } | ||||
| 
 | ||||
|     amiibo_data = data; | ||||
| 
 | ||||
|     return Common::Input::NfcState::Success; | ||||
| } | ||||
| 
 | ||||
| @ -91,6 +93,15 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) { | ||||
|     return Info::Success; | ||||
| } | ||||
| 
 | ||||
| VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { | ||||
|     if (state == State::AmiiboIsOpen) { | ||||
|         SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data}); | ||||
|         return Info::Success; | ||||
|     } | ||||
| 
 | ||||
|     return LoadAmiibo(file_path); | ||||
| } | ||||
| 
 | ||||
| VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { | ||||
|     state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo | ||||
|                                                             : State::Initialized; | ||||
| @ -98,4 +109,8 @@ VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { | ||||
|     return Info::Success; | ||||
| } | ||||
| 
 | ||||
| std::string VirtualAmiibo::GetLastFilePath() const { | ||||
|     return file_path; | ||||
| } | ||||
| 
 | ||||
| } // namespace InputCommon
 | ||||
|  | ||||
| @ -47,8 +47,11 @@ public: | ||||
|     State GetCurrentState() const; | ||||
| 
 | ||||
|     Info LoadAmiibo(const std::string& amiibo_file); | ||||
|     Info ReloadAmiibo(); | ||||
|     Info CloseAmiibo(); | ||||
| 
 | ||||
|     std::string GetLastFilePath() const; | ||||
| 
 | ||||
| private: | ||||
|     static constexpr std::size_t amiibo_size = 0x21C; | ||||
|     static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8; | ||||
|  | ||||
| @ -133,7 +133,7 @@ public: | ||||
|         return Common::Input::CameraError::NotSupported; | ||||
|     } | ||||
| 
 | ||||
|     // Request nfc data from a controller
 | ||||
|     // Returns success if nfc is supported
 | ||||
|     virtual Common::Input::NfcState SupportsNfc( | ||||
|         [[maybe_unused]] const PadIdentifier& identifier) const { | ||||
|         return Common::Input::NfcState::NotSupported; | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										260
									
								
								src/yuzu/applets/qt_amiibo_settings.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								src/yuzu/applets/qt_amiibo_settings.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| } | ||||
							
								
								
									
										83
									
								
								src/yuzu/applets/qt_amiibo_settings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/yuzu/applets/qt_amiibo_settings.h
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| }; | ||||
							
								
								
									
										494
									
								
								src/yuzu/applets/qt_amiibo_settings.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										494
									
								
								src/yuzu/applets/qt_amiibo_settings.ui
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
| @ -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" | ||||
| @ -548,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"); | ||||
| 
 | ||||
| @ -569,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); | ||||
| @ -1546,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
 | ||||
|  | ||||
| @ -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( | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user