forked from eden-emu/eden
		
	qt: implement RequestExit for applets
This commit is contained in:
		
							parent
							
								
									950db851ea
								
							
						
					
					
						commit
						50a59487eb
					
				
					 38 changed files with 250 additions and 69 deletions
				
			
		
							
								
								
									
										14
									
								
								src/core/frontend/applets/applet.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/core/frontend/applets/applet.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| namespace Core::Frontend { | ||||
| 
 | ||||
| class Applet { | ||||
| public: | ||||
|     virtual ~Applet() = default; | ||||
|     virtual void Close() const = 0; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Core::Frontend
 | ||||
|  | @ -10,6 +10,8 @@ namespace Core::Frontend { | |||
| 
 | ||||
| CabinetApplet::~CabinetApplet() = default; | ||||
| 
 | ||||
| void DefaultCabinetApplet::Close() const {} | ||||
| 
 | ||||
| void DefaultCabinetApplet::ShowCabinetApplet( | ||||
|     const CabinetCallback& callback, const CabinetParameters& parameters, | ||||
|     std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const { | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <functional> | ||||
| #include "core/frontend/applets/applet.h" | ||||
| #include "core/hle/service/nfp/nfp_types.h" | ||||
| 
 | ||||
| namespace Service::NFP { | ||||
|  | @ -20,7 +21,7 @@ struct CabinetParameters { | |||
| 
 | ||||
| using CabinetCallback = std::function<void(bool, const std::string&)>; | ||||
| 
 | ||||
| class CabinetApplet { | ||||
| class CabinetApplet : public Applet { | ||||
| public: | ||||
|     virtual ~CabinetApplet(); | ||||
|     virtual void ShowCabinetApplet(const CabinetCallback& callback, | ||||
|  | @ -30,6 +31,7 @@ public: | |||
| 
 | ||||
| class DefaultCabinetApplet final : public CabinetApplet { | ||||
| public: | ||||
|     void Close() const override; | ||||
|     void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, | ||||
|                            std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; | ||||
| }; | ||||
|  |  | |||
|  | @ -16,6 +16,8 @@ DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_ | |||
| 
 | ||||
| DefaultControllerApplet::~DefaultControllerApplet() = default; | ||||
| 
 | ||||
| void DefaultControllerApplet::Close() const {} | ||||
| 
 | ||||
| void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callback, | ||||
|                                                      const ControllerParameters& parameters) const { | ||||
|     LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "core/frontend/applets/applet.h" | ||||
| 
 | ||||
| namespace Core::HID { | ||||
| class HIDCore; | ||||
|  | @ -34,7 +35,7 @@ struct ControllerParameters { | |||
|     bool allow_gamecube_controller{}; | ||||
| }; | ||||
| 
 | ||||
| class ControllerApplet { | ||||
| class ControllerApplet : public Applet { | ||||
| public: | ||||
|     using ReconfigureCallback = std::function<void()>; | ||||
| 
 | ||||
|  | @ -49,6 +50,7 @@ public: | |||
|     explicit DefaultControllerApplet(HID::HIDCore& hid_core_); | ||||
|     ~DefaultControllerApplet() override; | ||||
| 
 | ||||
|     void Close() const override; | ||||
|     void ReconfigureControllers(ReconfigureCallback callback, | ||||
|                                 const ControllerParameters& parameters) const override; | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ namespace Core::Frontend { | |||
| 
 | ||||
| ErrorApplet::~ErrorApplet() = default; | ||||
| 
 | ||||
| void DefaultErrorApplet::Close() const {} | ||||
| 
 | ||||
| void DefaultErrorApplet::ShowError(Result error, FinishedCallback finished) const { | ||||
|     LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})", | ||||
|                  error.module.Value(), error.description.Value(), error.raw); | ||||
|  |  | |||
|  | @ -6,11 +6,12 @@ | |||
| #include <chrono> | ||||
| #include <functional> | ||||
| 
 | ||||
| #include "core/frontend/applets/applet.h" | ||||
| #include "core/hle/result.h" | ||||
| 
 | ||||
| namespace Core::Frontend { | ||||
| 
 | ||||
| class ErrorApplet { | ||||
| class ErrorApplet : public Applet { | ||||
| public: | ||||
|     using FinishedCallback = std::function<void()>; | ||||
| 
 | ||||
|  | @ -28,6 +29,7 @@ public: | |||
| 
 | ||||
| class DefaultErrorApplet final : public ErrorApplet { | ||||
| public: | ||||
|     void Close() const override; | ||||
|     void ShowError(Result error, FinishedCallback finished) const override; | ||||
|     void ShowErrorWithTimestamp(Result error, std::chrono::seconds time, | ||||
|                                 FinishedCallback finished) const override; | ||||
|  |  | |||
|  | @ -10,6 +10,8 @@ ParentalControlsApplet::~ParentalControlsApplet() = default; | |||
| 
 | ||||
| DefaultParentalControlsApplet::~DefaultParentalControlsApplet() = default; | ||||
| 
 | ||||
| void DefaultParentalControlsApplet::Close() const {} | ||||
| 
 | ||||
| void DefaultParentalControlsApplet::VerifyPIN(std::function<void(bool)> finished, | ||||
|                                               bool suspend_future_verification_temporarily) { | ||||
|     LOG_INFO(Service_AM, | ||||
|  | @ -39,6 +41,8 @@ PhotoViewerApplet::~PhotoViewerApplet() = default; | |||
| 
 | ||||
| DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() = default; | ||||
| 
 | ||||
| void DefaultPhotoViewerApplet::Close() const {} | ||||
| 
 | ||||
| void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id, | ||||
|                                                         std::function<void()> finished) const { | ||||
|     LOG_INFO(Service_AM, | ||||
|  |  | |||
|  | @ -6,9 +6,11 @@ | |||
| #include <functional> | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| #include "core/frontend/applets/applet.h" | ||||
| 
 | ||||
| namespace Core::Frontend { | ||||
| 
 | ||||
| class ParentalControlsApplet { | ||||
| class ParentalControlsApplet : public Applet { | ||||
| public: | ||||
|     virtual ~ParentalControlsApplet(); | ||||
| 
 | ||||
|  | @ -33,6 +35,7 @@ class DefaultParentalControlsApplet final : public ParentalControlsApplet { | |||
| public: | ||||
|     ~DefaultParentalControlsApplet() override; | ||||
| 
 | ||||
|     void Close() const override; | ||||
|     void VerifyPIN(std::function<void(bool)> finished, | ||||
|                    bool suspend_future_verification_temporarily) override; | ||||
|     void VerifyPINForSettings(std::function<void(bool)> finished) override; | ||||
|  | @ -40,7 +43,7 @@ public: | |||
|     void ChangePIN(std::function<void()> finished) override; | ||||
| }; | ||||
| 
 | ||||
| class PhotoViewerApplet { | ||||
| class PhotoViewerApplet : public Applet { | ||||
| public: | ||||
|     virtual ~PhotoViewerApplet(); | ||||
| 
 | ||||
|  | @ -52,6 +55,7 @@ class DefaultPhotoViewerApplet final : public PhotoViewerApplet { | |||
| public: | ||||
|     ~DefaultPhotoViewerApplet() override; | ||||
| 
 | ||||
|     void Close() const override; | ||||
|     void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const override; | ||||
|     void ShowAllPhotos(std::function<void()> finished) const override; | ||||
| }; | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ namespace Core::Frontend { | |||
| 
 | ||||
| MiiEditApplet::~MiiEditApplet() = default; | ||||
| 
 | ||||
| void DefaultMiiEditApplet::Close() const {} | ||||
| 
 | ||||
| void DefaultMiiEditApplet::ShowMiiEdit(const MiiEditCallback& callback) const { | ||||
|     LOG_WARNING(Service_AM, "(STUBBED) called"); | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,9 +5,11 @@ | |||
| 
 | ||||
| #include <functional> | ||||
| 
 | ||||
| #include "core/frontend/applets/applet.h" | ||||
| 
 | ||||
| namespace Core::Frontend { | ||||
| 
 | ||||
| class MiiEditApplet { | ||||
| class MiiEditApplet : public Applet { | ||||
| public: | ||||
|     using MiiEditCallback = std::function<void()>; | ||||
| 
 | ||||
|  | @ -18,6 +20,7 @@ public: | |||
| 
 | ||||
| class DefaultMiiEditApplet final : public MiiEditApplet { | ||||
| public: | ||||
|     void Close() const override; | ||||
|     void ShowMiiEdit(const MiiEditCallback& callback) const override; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,8 @@ namespace Core::Frontend { | |||
| 
 | ||||
| ProfileSelectApplet::~ProfileSelectApplet() = default; | ||||
| 
 | ||||
| void DefaultProfileSelectApplet::Close() const {} | ||||
| 
 | ||||
| void DefaultProfileSelectApplet::SelectProfile(SelectProfileCallback callback) const { | ||||
|     Service::Account::ProfileManager manager; | ||||
|     callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{})); | ||||
|  |  | |||
|  | @ -7,9 +7,11 @@ | |||
| #include <optional> | ||||
| #include "common/uuid.h" | ||||
| 
 | ||||
| #include "core/frontend/applets/applet.h" | ||||
| 
 | ||||
| namespace Core::Frontend { | ||||
| 
 | ||||
| class ProfileSelectApplet { | ||||
| class ProfileSelectApplet : public Applet { | ||||
| public: | ||||
|     using SelectProfileCallback = std::function<void(std::optional<Common::UUID>)>; | ||||
| 
 | ||||
|  | @ -20,6 +22,7 @@ public: | |||
| 
 | ||||
| class DefaultProfileSelectApplet final : public ProfileSelectApplet { | ||||
| public: | ||||
|     void Close() const override; | ||||
|     void SelectProfile(SelectProfileCallback callback) const override; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default; | |||
| 
 | ||||
| DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default; | ||||
| 
 | ||||
| void DefaultSoftwareKeyboardApplet::Close() const {} | ||||
| 
 | ||||
| void DefaultSoftwareKeyboardApplet::InitializeKeyboard( | ||||
|     bool is_inline, KeyboardInitializeParameters initialize_parameters, | ||||
|     SubmitNormalCallback submit_normal_callback_, SubmitInlineCallback submit_inline_callback_) { | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| 
 | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| #include "core/frontend/applets/applet.h" | ||||
| #include "core/hle/service/am/applets/applet_software_keyboard_types.h" | ||||
| 
 | ||||
| namespace Core::Frontend { | ||||
|  | @ -52,7 +53,7 @@ struct InlineTextParameters { | |||
|     s32 cursor_position; | ||||
| }; | ||||
| 
 | ||||
| class SoftwareKeyboardApplet { | ||||
| class SoftwareKeyboardApplet : public Applet { | ||||
| public: | ||||
|     using SubmitInlineCallback = | ||||
|         std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>; | ||||
|  | @ -84,6 +85,8 @@ class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet { | |||
| public: | ||||
|     ~DefaultSoftwareKeyboardApplet() override; | ||||
| 
 | ||||
|     void Close() const override; | ||||
| 
 | ||||
|     void InitializeKeyboard(bool is_inline, KeyboardInitializeParameters initialize_parameters, | ||||
|                             SubmitNormalCallback submit_normal_callback_, | ||||
|                             SubmitInlineCallback submit_inline_callback_) override; | ||||
|  |  | |||
|  | @ -10,6 +10,8 @@ WebBrowserApplet::~WebBrowserApplet() = default; | |||
| 
 | ||||
| DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; | ||||
| 
 | ||||
| void DefaultWebBrowserApplet::Close() const {} | ||||
| 
 | ||||
| void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url, | ||||
|                                                ExtractROMFSCallback extract_romfs_callback, | ||||
|                                                OpenWebPageCallback callback) const { | ||||
|  |  | |||
|  | @ -5,11 +5,12 @@ | |||
| 
 | ||||
| #include <functional> | ||||
| 
 | ||||
| #include "core/frontend/applets/applet.h" | ||||
| #include "core/hle/service/am/applets/applet_web_browser_types.h" | ||||
| 
 | ||||
| namespace Core::Frontend { | ||||
| 
 | ||||
| class WebBrowserApplet { | ||||
| class WebBrowserApplet : public Applet { | ||||
| public: | ||||
|     using ExtractROMFSCallback = std::function<void()>; | ||||
|     using OpenWebPageCallback = | ||||
|  | @ -29,6 +30,8 @@ class DefaultWebBrowserApplet final : public WebBrowserApplet { | |||
| public: | ||||
|     ~DefaultWebBrowserApplet() override; | ||||
| 
 | ||||
|     void Close() const override; | ||||
| 
 | ||||
|     void OpenLocalWebPage(const std::string& local_url, ExtractROMFSCallback extract_romfs_callback, | ||||
|                           OpenWebPageCallback callback) const override; | ||||
| 
 | ||||
|  |  | |||
|  | @ -175,7 +175,7 @@ void Cabinet::Cancel() { | |||
| } | ||||
| 
 | ||||
| Result Cabinet::RequestExit() { | ||||
|     this->Cancel(); | ||||
|     frontend.Close(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -263,7 +263,7 @@ void Controller::ConfigurationComplete() { | |||
| } | ||||
| 
 | ||||
| Result Controller::RequestExit() { | ||||
|     this->ConfigurationComplete(); | ||||
|     frontend.Close(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -210,7 +210,7 @@ void Error::DisplayCompleted() { | |||
| } | ||||
| 
 | ||||
| Result Error::RequestExit() { | ||||
|     this->DisplayCompleted(); | ||||
|     frontend.Close(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -151,7 +151,7 @@ void Auth::AuthFinished(bool is_successful) { | |||
| } | ||||
| 
 | ||||
| Result Auth::RequestExit() { | ||||
|     this->AuthFinished(false); | ||||
|     frontend.Close(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
|  | @ -208,7 +208,7 @@ void PhotoViewer::ViewFinished() { | |||
| } | ||||
| 
 | ||||
| Result PhotoViewer::RequestExit() { | ||||
|     this->ViewFinished(); | ||||
|     frontend.Close(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -136,7 +136,7 @@ void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, | |||
| } | ||||
| 
 | ||||
| Result MiiEdit::RequestExit() { | ||||
|     this->MiiEditOutput(MiiEditResult::Cancel, -1); | ||||
|     frontend.Close(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -74,7 +74,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { | |||
| } | ||||
| 
 | ||||
| Result ProfileSelect::RequestExit() { | ||||
|     this->SelectionComplete(std::nullopt); | ||||
|     frontend.Close(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -771,7 +771,7 @@ void SoftwareKeyboard::ExitKeyboard() { | |||
| } | ||||
| 
 | ||||
| Result SoftwareKeyboard::RequestExit() { | ||||
|     this->ExitKeyboard(); | ||||
|     frontend.Close(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -364,7 +364,7 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) | |||
| } | ||||
| 
 | ||||
| Result WebBrowser::RequestExit() { | ||||
|     this->WebBrowserExit(WebExitReason::ExitRequested); | ||||
|     frontend.Close(); | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -245,12 +245,19 @@ void QtAmiiboSettingsDialog::SetSettingsDescription() { | |||
| QtAmiiboSettings::QtAmiiboSettings(GMainWindow& parent) { | ||||
|     connect(this, &QtAmiiboSettings::MainWindowShowAmiiboSettings, &parent, | ||||
|             &GMainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection); | ||||
|     connect(this, &QtAmiiboSettings::MainWindowRequestExit, &parent, | ||||
|             &GMainWindow::AmiiboSettingsRequestExit, Qt::QueuedConnection); | ||||
|     connect(&parent, &GMainWindow::AmiiboSettingsFinished, this, | ||||
|             &QtAmiiboSettings::MainWindowFinished, Qt::QueuedConnection); | ||||
| } | ||||
| 
 | ||||
| QtAmiiboSettings::~QtAmiiboSettings() = default; | ||||
| 
 | ||||
| void QtAmiiboSettings::Close() const { | ||||
|     callback = {}; | ||||
|     emit MainWindowRequestExit(); | ||||
| } | ||||
| 
 | ||||
| void QtAmiiboSettings::ShowCabinetApplet( | ||||
|     const Core::Frontend::CabinetCallback& callback_, | ||||
|     const Core::Frontend::CabinetParameters& parameters, | ||||
|  | @ -260,5 +267,7 @@ void QtAmiiboSettings::ShowCabinetApplet( | |||
| } | ||||
| 
 | ||||
| void QtAmiiboSettings::MainWindowFinished(bool is_success, const std::string& name) { | ||||
|     if (callback) { | ||||
|         callback(is_success, name); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -68,6 +68,7 @@ public: | |||
|     explicit QtAmiiboSettings(GMainWindow& parent); | ||||
|     ~QtAmiiboSettings() override; | ||||
| 
 | ||||
|     void Close() const override; | ||||
|     void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_, | ||||
|                            const Core::Frontend::CabinetParameters& parameters, | ||||
|                            std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; | ||||
|  | @ -75,6 +76,7 @@ public: | |||
| signals: | ||||
|     void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters, | ||||
|                                       std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const; | ||||
|     void MainWindowRequestExit() const; | ||||
| 
 | ||||
| private: | ||||
|     void MainWindowFinished(bool is_success, const std::string& name); | ||||
|  |  | |||
|  | @ -678,12 +678,19 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() { | |||
| QtControllerSelector::QtControllerSelector(GMainWindow& parent) { | ||||
|     connect(this, &QtControllerSelector::MainWindowReconfigureControllers, &parent, | ||||
|             &GMainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection); | ||||
|     connect(this, &QtControllerSelector::MainWindowRequestExit, &parent, | ||||
|             &GMainWindow::ControllerSelectorRequestExit, Qt::QueuedConnection); | ||||
|     connect(&parent, &GMainWindow::ControllerSelectorReconfigureFinished, this, | ||||
|             &QtControllerSelector::MainWindowReconfigureFinished, Qt::QueuedConnection); | ||||
| } | ||||
| 
 | ||||
| QtControllerSelector::~QtControllerSelector() = default; | ||||
| 
 | ||||
| void QtControllerSelector::Close() const { | ||||
|     callback = {}; | ||||
|     emit MainWindowRequestExit(); | ||||
| } | ||||
| 
 | ||||
| void QtControllerSelector::ReconfigureControllers( | ||||
|     ReconfigureCallback callback_, const Core::Frontend::ControllerParameters& parameters) const { | ||||
|     callback = std::move(callback_); | ||||
|  | @ -691,5 +698,7 @@ void QtControllerSelector::ReconfigureControllers( | |||
| } | ||||
| 
 | ||||
| void QtControllerSelector::MainWindowReconfigureFinished() { | ||||
|     if (callback) { | ||||
|         callback(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -156,6 +156,7 @@ public: | |||
|     explicit QtControllerSelector(GMainWindow& parent); | ||||
|     ~QtControllerSelector() override; | ||||
| 
 | ||||
|     void Close() const override; | ||||
|     void ReconfigureControllers( | ||||
|         ReconfigureCallback callback_, | ||||
|         const Core::Frontend::ControllerParameters& parameters) const override; | ||||
|  | @ -163,6 +164,7 @@ public: | |||
| signals: | ||||
|     void MainWindowReconfigureControllers( | ||||
|         const Core::Frontend::ControllerParameters& parameters) const; | ||||
|     void MainWindowRequestExit() const; | ||||
| 
 | ||||
| private: | ||||
|     void MainWindowReconfigureFinished(); | ||||
|  |  | |||
|  | @ -8,12 +8,19 @@ | |||
| QtErrorDisplay::QtErrorDisplay(GMainWindow& parent) { | ||||
|     connect(this, &QtErrorDisplay::MainWindowDisplayError, &parent, | ||||
|             &GMainWindow::ErrorDisplayDisplayError, Qt::QueuedConnection); | ||||
|     connect(this, &QtErrorDisplay::MainWindowRequestExit, &parent, | ||||
|             &GMainWindow::ErrorDisplayRequestExit, Qt::QueuedConnection); | ||||
|     connect(&parent, &GMainWindow::ErrorDisplayFinished, this, | ||||
|             &QtErrorDisplay::MainWindowFinishedError, Qt::DirectConnection); | ||||
| } | ||||
| 
 | ||||
| QtErrorDisplay::~QtErrorDisplay() = default; | ||||
| 
 | ||||
| void QtErrorDisplay::Close() const { | ||||
|     callback = {}; | ||||
|     emit MainWindowRequestExit(); | ||||
| } | ||||
| 
 | ||||
| void QtErrorDisplay::ShowError(Result error, FinishedCallback finished) const { | ||||
|     callback = std::move(finished); | ||||
|     emit MainWindowDisplayError( | ||||
|  | @ -55,5 +62,7 @@ void QtErrorDisplay::ShowCustomErrorText(Result error, std::string dialog_text, | |||
| } | ||||
| 
 | ||||
| void QtErrorDisplay::MainWindowFinishedError() { | ||||
|     if (callback) { | ||||
|         callback(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ public: | |||
|     explicit QtErrorDisplay(GMainWindow& parent); | ||||
|     ~QtErrorDisplay() override; | ||||
| 
 | ||||
|     void Close() const override; | ||||
|     void ShowError(Result error, FinishedCallback finished) const override; | ||||
|     void ShowErrorWithTimestamp(Result error, std::chrono::seconds time, | ||||
|                                 FinishedCallback finished) const override; | ||||
|  | @ -24,6 +25,7 @@ public: | |||
| 
 | ||||
| signals: | ||||
|     void MainWindowDisplayError(QString error_code, QString error_text) const; | ||||
|     void MainWindowRequestExit() const; | ||||
| 
 | ||||
| private: | ||||
|     void MainWindowFinishedError(); | ||||
|  |  | |||
|  | @ -157,17 +157,26 @@ void QtProfileSelectionDialog::SelectUser(const QModelIndex& index) { | |||
| QtProfileSelector::QtProfileSelector(GMainWindow& parent) { | ||||
|     connect(this, &QtProfileSelector::MainWindowSelectProfile, &parent, | ||||
|             &GMainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection); | ||||
|     connect(this, &QtProfileSelector::MainWindowRequestExit, &parent, | ||||
|             &GMainWindow::ProfileSelectorRequestExit, Qt::QueuedConnection); | ||||
|     connect(&parent, &GMainWindow::ProfileSelectorFinishedSelection, this, | ||||
|             &QtProfileSelector::MainWindowFinishedSelection, Qt::DirectConnection); | ||||
| } | ||||
| 
 | ||||
| QtProfileSelector::~QtProfileSelector() = default; | ||||
| 
 | ||||
| void QtProfileSelector::Close() const { | ||||
|     callback = {}; | ||||
|     emit MainWindowRequestExit(); | ||||
| } | ||||
| 
 | ||||
| void QtProfileSelector::SelectProfile(SelectProfileCallback callback_) const { | ||||
|     callback = std::move(callback_); | ||||
|     emit MainWindowSelectProfile(); | ||||
| } | ||||
| 
 | ||||
| void QtProfileSelector::MainWindowFinishedSelection(std::optional<Common::UUID> uuid) { | ||||
|     if (callback) { | ||||
|         callback(uuid); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -65,10 +65,12 @@ public: | |||
|     explicit QtProfileSelector(GMainWindow& parent); | ||||
|     ~QtProfileSelector() override; | ||||
| 
 | ||||
|     void Close() const override; | ||||
|     void SelectProfile(SelectProfileCallback callback_) const override; | ||||
| 
 | ||||
| signals: | ||||
|     void MainWindowSelectProfile() const; | ||||
|     void MainWindowRequestExit() const; | ||||
| 
 | ||||
| private: | ||||
|     void MainWindowFinishedSelection(std::optional<Common::UUID> uuid); | ||||
|  |  | |||
|  | @ -233,6 +233,10 @@ public: | |||
|     explicit QtSoftwareKeyboard(GMainWindow& parent); | ||||
|     ~QtSoftwareKeyboard() override; | ||||
| 
 | ||||
|     void Close() const override { | ||||
|         ExitKeyboard(); | ||||
|     } | ||||
| 
 | ||||
|     void InitializeKeyboard(bool is_inline, | ||||
|                             Core::Frontend::KeyboardInitializeParameters initialize_parameters, | ||||
|                             SubmitNormalCallback submit_normal_callback_, | ||||
|  |  | |||
|  | @ -393,6 +393,8 @@ void QtNXWebEngineView::FocusFirstLinkElement() { | |||
| QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { | ||||
|     connect(this, &QtWebBrowser::MainWindowOpenWebPage, &main_window, | ||||
|             &GMainWindow::WebBrowserOpenWebPage, Qt::QueuedConnection); | ||||
|     connect(this, &QtWebBrowser::MainWindowRequestExit, &main_window, | ||||
|             &GMainWindow::WebBrowserRequestExit, Qt::QueuedConnection); | ||||
|     connect(&main_window, &GMainWindow::WebBrowserExtractOfflineRomFS, this, | ||||
|             &QtWebBrowser::MainWindowExtractOfflineRomFS, Qt::QueuedConnection); | ||||
|     connect(&main_window, &GMainWindow::WebBrowserClosed, this, | ||||
|  | @ -401,6 +403,11 @@ QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { | |||
| 
 | ||||
| QtWebBrowser::~QtWebBrowser() = default; | ||||
| 
 | ||||
| void QtWebBrowser::Close() const { | ||||
|     callback = {}; | ||||
|     emit MainWindowRequestExit(); | ||||
| } | ||||
| 
 | ||||
| void QtWebBrowser::OpenLocalWebPage(const std::string& local_url, | ||||
|                                     ExtractROMFSCallback extract_romfs_callback_, | ||||
|                                     OpenWebPageCallback callback_) const { | ||||
|  | @ -436,5 +443,7 @@ void QtWebBrowser::MainWindowExtractOfflineRomFS() { | |||
| 
 | ||||
| void QtWebBrowser::MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, | ||||
|                                               std::string last_url) { | ||||
|     if (callback) { | ||||
|         callback(exit_reason, last_url); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -196,6 +196,7 @@ public: | |||
|     explicit QtWebBrowser(GMainWindow& parent); | ||||
|     ~QtWebBrowser() override; | ||||
| 
 | ||||
|     void Close() const override; | ||||
|     void OpenLocalWebPage(const std::string& local_url, | ||||
|                           ExtractROMFSCallback extract_romfs_callback_, | ||||
|                           OpenWebPageCallback callback_) const override; | ||||
|  | @ -206,6 +207,7 @@ public: | |||
| signals: | ||||
|     void MainWindowOpenWebPage(const std::string& main_url, const std::string& additional_args, | ||||
|                                bool is_local) const; | ||||
|     void MainWindowRequestExit() const; | ||||
| 
 | ||||
| private: | ||||
|     void MainWindowExtractOfflineRomFS(); | ||||
|  |  | |||
|  | @ -596,27 +596,45 @@ void GMainWindow::RegisterMetaTypes() { | |||
| 
 | ||||
| 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); | ||||
|     cabinet_applet = | ||||
|         new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device); | ||||
|     SCOPE_EXIT({ | ||||
|         cabinet_applet->deleteLater(); | ||||
|         cabinet_applet = nullptr; | ||||
|     }); | ||||
| 
 | ||||
|     dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | | ||||
|     cabinet_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | | ||||
|                                    Qt::WindowTitleHint | Qt::WindowSystemMenuHint); | ||||
|     dialog.setWindowModality(Qt::WindowModal); | ||||
|     if (dialog.exec() == QDialog::Rejected) { | ||||
|     cabinet_applet->setWindowModality(Qt::WindowModal); | ||||
| 
 | ||||
|     if (cabinet_applet->exec() == QDialog::Rejected) { | ||||
|         emit AmiiboSettingsFinished(false, {}); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     emit AmiiboSettingsFinished(true, dialog.GetName()); | ||||
|     emit AmiiboSettingsFinished(true, cabinet_applet->GetName()); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::AmiiboSettingsRequestExit() { | ||||
|     if (cabinet_applet) { | ||||
|         cabinet_applet->reject(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::ControllerSelectorReconfigureControllers( | ||||
|     const Core::Frontend::ControllerParameters& parameters) { | ||||
|     QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get(), *system); | ||||
|     controller_applet = | ||||
|         new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system); | ||||
|     SCOPE_EXIT({ | ||||
|         controller_applet->deleteLater(); | ||||
|         controller_applet = nullptr; | ||||
|     }); | ||||
| 
 | ||||
|     dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | | ||||
|                           Qt::WindowTitleHint | Qt::WindowSystemMenuHint); | ||||
|     dialog.setWindowModality(Qt::WindowModal); | ||||
|     dialog.exec(); | ||||
|     controller_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | | ||||
|                                       Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | | ||||
|                                       Qt::WindowSystemMenuHint); | ||||
|     controller_applet->setWindowModality(Qt::WindowModal); | ||||
|     controller_applet->exec(); | ||||
| 
 | ||||
|     emit ControllerSelectorReconfigureFinished(); | ||||
| 
 | ||||
|  | @ -627,19 +645,30 @@ void GMainWindow::ControllerSelectorReconfigureControllers( | |||
|     UpdateStatusButtons(); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::ControllerSelectorRequestExit() { | ||||
|     if (controller_applet) { | ||||
|         controller_applet->reject(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::ProfileSelectorSelectProfile() { | ||||
|     QtProfileSelectionDialog dialog(system->HIDCore(), this); | ||||
|     dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | | ||||
|                           Qt::WindowTitleHint | Qt::WindowSystemMenuHint | | ||||
|                           Qt::WindowCloseButtonHint); | ||||
|     dialog.setWindowModality(Qt::WindowModal); | ||||
|     if (dialog.exec() == QDialog::Rejected) { | ||||
|     profile_select_applet = new QtProfileSelectionDialog(system->HIDCore(), this); | ||||
|     SCOPE_EXIT({ | ||||
|         profile_select_applet->deleteLater(); | ||||
|         profile_select_applet = nullptr; | ||||
|     }); | ||||
| 
 | ||||
|     profile_select_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | | ||||
|                                           Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | | ||||
|                                           Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); | ||||
|     profile_select_applet->setWindowModality(Qt::WindowModal); | ||||
|     if (profile_select_applet->exec() == QDialog::Rejected) { | ||||
|         emit ProfileSelectorFinishedSelection(std::nullopt); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const Service::Account::ProfileManager manager; | ||||
|     const auto uuid = manager.GetUser(static_cast<std::size_t>(dialog.GetIndex())); | ||||
|     const auto uuid = manager.GetUser(static_cast<std::size_t>(profile_select_applet->GetIndex())); | ||||
|     if (!uuid.has_value()) { | ||||
|         emit ProfileSelectorFinishedSelection(std::nullopt); | ||||
|         return; | ||||
|  | @ -648,6 +677,12 @@ void GMainWindow::ProfileSelectorSelectProfile() { | |||
|     emit ProfileSelectorFinishedSelection(uuid); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::ProfileSelectorRequestExit() { | ||||
|     if (profile_select_applet) { | ||||
|         profile_select_applet->reject(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::SoftwareKeyboardInitialize( | ||||
|     bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) { | ||||
|     if (software_keyboard) { | ||||
|  | @ -772,7 +807,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     QtNXWebEngineView web_browser_view(this, *system, input_subsystem.get()); | ||||
|     web_applet = new QtNXWebEngineView(this, *system, input_subsystem.get()); | ||||
| 
 | ||||
|     ui->action_Pause->setEnabled(false); | ||||
|     ui->action_Restart->setEnabled(false); | ||||
|  | @ -799,9 +834,9 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, | |||
|         loading_progress.setValue(1); | ||||
| 
 | ||||
|         if (is_local) { | ||||
|             web_browser_view.LoadLocalWebPage(main_url, additional_args); | ||||
|             web_applet->LoadLocalWebPage(main_url, additional_args); | ||||
|         } else { | ||||
|             web_browser_view.LoadExternalWebPage(main_url, additional_args); | ||||
|             web_applet->LoadExternalWebPage(main_url, additional_args); | ||||
|         } | ||||
| 
 | ||||
|         if (render_window->IsLoadingComplete()) { | ||||
|  | @ -810,15 +845,15 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, | |||
| 
 | ||||
|         const auto& layout = render_window->GetFramebufferLayout(); | ||||
|         const auto scale_ratio = devicePixelRatioF(); | ||||
|         web_browser_view.resize(layout.screen.GetWidth() / scale_ratio, | ||||
|         web_applet->resize(layout.screen.GetWidth() / scale_ratio, | ||||
|                            layout.screen.GetHeight() / scale_ratio); | ||||
|         web_browser_view.move(layout.screen.left / scale_ratio, | ||||
|         web_applet->move(layout.screen.left / scale_ratio, | ||||
|                          (layout.screen.top / scale_ratio) + menuBar()->height()); | ||||
|         web_browser_view.setZoomFactor(static_cast<qreal>(layout.screen.GetWidth() / scale_ratio) / | ||||
|         web_applet->setZoomFactor(static_cast<qreal>(layout.screen.GetWidth() / scale_ratio) / | ||||
|                                   static_cast<qreal>(Layout::ScreenUndocked::Width)); | ||||
| 
 | ||||
|         web_browser_view.setFocus(); | ||||
|         web_browser_view.show(); | ||||
|         web_applet->setFocus(); | ||||
|         web_applet->show(); | ||||
| 
 | ||||
|         loading_progress.setValue(2); | ||||
| 
 | ||||
|  | @ -831,7 +866,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, | |||
| 
 | ||||
|     // TODO (Morph): Remove this
 | ||||
|     QAction* exit_action = new QAction(tr("Disable Web Applet"), this); | ||||
|     connect(exit_action, &QAction::triggered, this, [this, &web_browser_view] { | ||||
|     connect(exit_action, &QAction::triggered, this, [this] { | ||||
|         const auto result = QMessageBox::warning( | ||||
|             this, tr("Disable Web Applet"), | ||||
|             tr("Disabling the web applet can lead to undefined behavior and should only be used " | ||||
|  | @ -840,21 +875,21 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, | |||
|             QMessageBox::Yes | QMessageBox::No); | ||||
|         if (result == QMessageBox::Yes) { | ||||
|             UISettings::values.disable_web_applet = true; | ||||
|             web_browser_view.SetFinished(true); | ||||
|             web_applet->SetFinished(true); | ||||
|         } | ||||
|     }); | ||||
|     ui->menubar->addAction(exit_action); | ||||
| 
 | ||||
|     while (!web_browser_view.IsFinished()) { | ||||
|     while (!web_applet->IsFinished()) { | ||||
|         QCoreApplication::processEvents(); | ||||
| 
 | ||||
|         if (!exit_check) { | ||||
|             web_browser_view.page()->runJavaScript( | ||||
|             web_applet->page()->runJavaScript( | ||||
|                 QStringLiteral("end_applet;"), [&](const QVariant& variant) { | ||||
|                     exit_check = false; | ||||
|                     if (variant.toBool()) { | ||||
|                         web_browser_view.SetFinished(true); | ||||
|                         web_browser_view.SetExitReason( | ||||
|                         web_applet->SetFinished(true); | ||||
|                         web_applet->SetExitReason( | ||||
|                             Service::AM::Applets::WebExitReason::EndButtonPressed); | ||||
|                     } | ||||
|                 }); | ||||
|  | @ -862,22 +897,22 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, | |||
|             exit_check = true; | ||||
|         } | ||||
| 
 | ||||
|         if (web_browser_view.GetCurrentURL().contains(QStringLiteral("localhost"))) { | ||||
|             if (!web_browser_view.IsFinished()) { | ||||
|                 web_browser_view.SetFinished(true); | ||||
|                 web_browser_view.SetExitReason(Service::AM::Applets::WebExitReason::CallbackURL); | ||||
|         if (web_applet->GetCurrentURL().contains(QStringLiteral("localhost"))) { | ||||
|             if (!web_applet->IsFinished()) { | ||||
|                 web_applet->SetFinished(true); | ||||
|                 web_applet->SetExitReason(Service::AM::Applets::WebExitReason::CallbackURL); | ||||
|             } | ||||
| 
 | ||||
|             web_browser_view.SetLastURL(web_browser_view.GetCurrentURL().toStdString()); | ||||
|             web_applet->SetLastURL(web_applet->GetCurrentURL().toStdString()); | ||||
|         } | ||||
| 
 | ||||
|         std::this_thread::sleep_for(std::chrono::milliseconds(1)); | ||||
|     } | ||||
| 
 | ||||
|     const auto exit_reason = web_browser_view.GetExitReason(); | ||||
|     const auto last_url = web_browser_view.GetLastURL(); | ||||
|     const auto exit_reason = web_applet->GetExitReason(); | ||||
|     const auto last_url = web_applet->GetLastURL(); | ||||
| 
 | ||||
|     web_browser_view.hide(); | ||||
|     web_applet->hide(); | ||||
| 
 | ||||
|     render_window->setFocus(); | ||||
| 
 | ||||
|  | @ -903,6 +938,15 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::WebBrowserRequestExit() { | ||||
| #ifdef YUZU_USE_QT_WEB_ENGINE | ||||
|     if (web_applet) { | ||||
|         web_applet->SetExitReason(Service::AM::Applets::WebExitReason::ExitRequested); | ||||
|         web_applet->SetFinished(true); | ||||
|     } | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::InitializeWidgets() { | ||||
| #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING | ||||
|     ui->action_Report_Compatibility->setVisible(true); | ||||
|  | @ -3089,13 +3133,23 @@ void GMainWindow::OnSaveConfig() { | |||
| } | ||||
| 
 | ||||
| void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { | ||||
|     OverlayDialog dialog(render_window, *system, error_code, error_text, QString{}, tr("OK"), | ||||
|                          Qt::AlignLeft | Qt::AlignVCenter); | ||||
|     dialog.exec(); | ||||
|     error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{}, | ||||
|                                      tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); | ||||
|     SCOPE_EXIT({ | ||||
|         error_applet->deleteLater(); | ||||
|         error_applet = nullptr; | ||||
|     }); | ||||
|     error_applet->exec(); | ||||
| 
 | ||||
|     emit ErrorDisplayFinished(); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::ErrorDisplayRequestExit() { | ||||
|     if (error_applet) { | ||||
|         error_applet->reject(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::OnMenuReportCompatibility() { | ||||
| #if defined(ARCHITECTURE_x86_64) && !defined(__APPLE__) | ||||
|     const auto& caps = Common::GetCPUCaps(); | ||||
|  |  | |||
|  | @ -47,7 +47,11 @@ enum class DumpRomFSTarget; | |||
| enum class InstalledEntryType; | ||||
| class GameListPlaceholder; | ||||
| 
 | ||||
| class QtAmiiboSettingsDialog; | ||||
| class QtControllerSelectorDialog; | ||||
| class QtProfileSelectionDialog; | ||||
| class QtSoftwareKeyboardDialog; | ||||
| class QtNXWebEngineView; | ||||
| 
 | ||||
| enum class StartGameType { | ||||
|     Normal, // Can use custom configuration
 | ||||
|  | @ -184,8 +188,10 @@ public slots: | |||
|     void OnSaveConfig(); | ||||
|     void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, | ||||
|                                   std::shared_ptr<Service::NFP::NfpDevice> nfp_device); | ||||
|     void AmiiboSettingsRequestExit(); | ||||
|     void ControllerSelectorReconfigureControllers( | ||||
|         const Core::Frontend::ControllerParameters& parameters); | ||||
|     void ControllerSelectorRequestExit(); | ||||
|     void SoftwareKeyboardInitialize( | ||||
|         bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters); | ||||
|     void SoftwareKeyboardShowNormal(); | ||||
|  | @ -196,9 +202,12 @@ public slots: | |||
|     void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters); | ||||
|     void SoftwareKeyboardExit(); | ||||
|     void ErrorDisplayDisplayError(QString error_code, QString error_text); | ||||
|     void ErrorDisplayRequestExit(); | ||||
|     void ProfileSelectorSelectProfile(); | ||||
|     void ProfileSelectorRequestExit(); | ||||
|     void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args, | ||||
|                                bool is_local); | ||||
|     void WebBrowserRequestExit(); | ||||
|     void OnAppFocusStateChanged(Qt::ApplicationState state); | ||||
|     void OnTasStateChanged(); | ||||
| 
 | ||||
|  | @ -466,7 +475,12 @@ private: | |||
|     QString last_filename_booted; | ||||
| 
 | ||||
|     // Applets
 | ||||
|     QtAmiiboSettingsDialog* cabinet_applet = nullptr; | ||||
|     QtControllerSelectorDialog* controller_applet = nullptr; | ||||
|     QtProfileSelectionDialog* profile_select_applet = nullptr; | ||||
|     QDialog* error_applet = nullptr; | ||||
|     QtSoftwareKeyboardDialog* software_keyboard = nullptr; | ||||
|     QtNXWebEngineView* web_applet = nullptr; | ||||
| 
 | ||||
|     // True if amiibo file select is visible
 | ||||
|     bool is_amiibo_file_select_active{}; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Liam
						Liam