summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2018-12-23 14:35:13 -0500
committerGravatar GitHub2018-12-23 14:35:13 -0500
commitf95f6c7d86af9857cb737a741fc847bf2c5d8413 (patch)
treeb5c02a35cdb18b78c648bc3a6f98b87e68d2e651
parentMerge pull request #1780 from DarkLordZach/controller-profiles (diff)
parentapplets: Correct event ResetTypes from OneShot to Sticky (diff)
downloadyuzu-f95f6c7d86af9857cb737a741fc847bf2c5d8413.tar.gz
yuzu-f95f6c7d86af9857cb737a741fc847bf2c5d8413.tar.xz
yuzu-f95f6c7d86af9857cb737a741fc847bf2c5d8413.zip
Merge pull request #1781 from DarkLordZach/applet-profile-select
am: Implement HLE profile selector applet
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/core.cpp11
-rw-r--r--src/core/core.h5
-rw-r--r--src/core/frontend/applets/profile_select.cpp19
-rw-r--r--src/core/frontend/applets/profile_select.h27
-rw-r--r--src/core/hle/service/am/am.cpp4
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp77
-rw-r--r--src/core/hle/service/am/applets/profile_select.h50
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu/applets/profile_select.cpp168
-rw-r--r--src/yuzu/applets/profile_select.h73
-rw-r--r--src/yuzu/main.cpp24
-rw-r--r--src/yuzu/main.h2
13 files changed, 466 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 882c9ab59..93f5ba3fe 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -83,6 +83,8 @@ add_library(core STATIC
83 file_sys/vfs_vector.h 83 file_sys/vfs_vector.h
84 file_sys/xts_archive.cpp 84 file_sys/xts_archive.cpp
85 file_sys/xts_archive.h 85 file_sys/xts_archive.h
86 frontend/applets/profile_select.cpp
87 frontend/applets/profile_select.h
86 frontend/applets/software_keyboard.cpp 88 frontend/applets/software_keyboard.cpp
87 frontend/applets/software_keyboard.h 89 frontend/applets/software_keyboard.h
88 frontend/emu_window.cpp 90 frontend/emu_window.cpp
@@ -162,6 +164,8 @@ add_library(core STATIC
162 hle/service/am/applet_oe.h 164 hle/service/am/applet_oe.h
163 hle/service/am/applets/applets.cpp 165 hle/service/am/applets/applets.cpp
164 hle/service/am/applets/applets.h 166 hle/service/am/applets/applets.h
167 hle/service/am/applets/profile_select.cpp
168 hle/service/am/applets/profile_select.h
165 hle/service/am/applets/software_keyboard.cpp 169 hle/service/am/applets/software_keyboard.cpp
166 hle/service/am/applets/software_keyboard.h 170 hle/service/am/applets/software_keyboard.h
167 hle/service/am/applets/stub_applet.cpp 171 hle/service/am/applets/stub_applet.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index ce7851538..fd10199ec 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -99,6 +99,8 @@ struct System::Impl {
99 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); 99 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
100 100
101 /// Create default implementations of applets if one is not provided. 101 /// Create default implementations of applets if one is not provided.
102 if (profile_selector == nullptr)
103 profile_selector = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
102 if (software_keyboard == nullptr) 104 if (software_keyboard == nullptr)
103 software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>(); 105 software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
104 106
@@ -229,6 +231,7 @@ struct System::Impl {
229 bool is_powered_on = false; 231 bool is_powered_on = false;
230 232
231 /// Frontend applets 233 /// Frontend applets
234 std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector;
232 std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; 235 std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
233 236
234 /// Service manager 237 /// Service manager
@@ -424,6 +427,14 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const {
424 return impl->virtual_filesystem; 427 return impl->virtual_filesystem;
425} 428}
426 429
430void System::SetProfileSelector(std::unique_ptr<Core::Frontend::ProfileSelectApplet> applet) {
431 impl->profile_selector = std::move(applet);
432}
433
434const Core::Frontend::ProfileSelectApplet& System::GetProfileSelector() const {
435 return *impl->profile_selector;
436}
437
427void System::SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet) { 438void System::SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet) {
428 impl->software_keyboard = std::move(applet); 439 impl->software_keyboard = std::move(applet);
429} 440}
diff --git a/src/core/core.h b/src/core/core.h
index 71031dfcf..869921493 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -11,6 +11,7 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/file_sys/vfs_types.h" 12#include "core/file_sys/vfs_types.h"
13#include "core/hle/kernel/object.h" 13#include "core/hle/kernel/object.h"
14#include "frontend/applets/profile_select.h"
14 15
15namespace Core::Frontend { 16namespace Core::Frontend {
16class EmuWindow; 17class EmuWindow;
@@ -241,6 +242,10 @@ public:
241 242
242 std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const; 243 std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
243 244
245 void SetProfileSelector(std::unique_ptr<Core::Frontend::ProfileSelectApplet> applet);
246
247 const Core::Frontend::ProfileSelectApplet& GetProfileSelector() const;
248
244 void SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet); 249 void SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet);
245 250
246 const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const; 251 const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp
new file mode 100644
index 000000000..fbf5f2a9e
--- /dev/null
+++ b/src/core/frontend/applets/profile_select.cpp
@@ -0,0 +1,19 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/frontend/applets/profile_select.h"
6#include "core/settings.h"
7
8namespace Core::Frontend {
9
10ProfileSelectApplet::~ProfileSelectApplet() = default;
11
12void DefaultProfileSelectApplet::SelectProfile(
13 std::function<void(std::optional<Service::Account::UUID>)> callback) const {
14 Service::Account::ProfileManager manager;
15 callback(manager.GetUser(Settings::values.current_user).value_or(Service::Account::UUID{}));
16 LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
17}
18
19} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/profile_select.h b/src/core/frontend/applets/profile_select.h
new file mode 100644
index 000000000..fc8f7ae94
--- /dev/null
+++ b/src/core/frontend/applets/profile_select.h
@@ -0,0 +1,27 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8#include <optional>
9#include "core/hle/service/acc/profile_manager.h"
10
11namespace Core::Frontend {
12
13class ProfileSelectApplet {
14public:
15 virtual ~ProfileSelectApplet();
16
17 virtual void SelectProfile(
18 std::function<void(std::optional<Service::Account::UUID>)> callback) const = 0;
19};
20
21class DefaultProfileSelectApplet final : public ProfileSelectApplet {
22public:
23 void SelectProfile(
24 std::function<void(std::optional<Service::Account::UUID>)> callback) const override;
25};
26
27} // namespace Core::Frontend
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 27c31aad2..5fc02a521 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -19,6 +19,7 @@
19#include "core/hle/service/am/applet_ae.h" 19#include "core/hle/service/am/applet_ae.h"
20#include "core/hle/service/am/applet_oe.h" 20#include "core/hle/service/am/applet_oe.h"
21#include "core/hle/service/am/applets/applets.h" 21#include "core/hle/service/am/applets/applets.h"
22#include "core/hle/service/am/applets/profile_select.h"
22#include "core/hle/service/am/applets/software_keyboard.h" 23#include "core/hle/service/am/applets/software_keyboard.h"
23#include "core/hle/service/am/applets/stub_applet.h" 24#include "core/hle/service/am/applets/stub_applet.h"
24#include "core/hle/service/am/idle.h" 25#include "core/hle/service/am/idle.h"
@@ -39,6 +40,7 @@ constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2};
39constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; 40constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
40 41
41enum class AppletId : u32 { 42enum class AppletId : u32 {
43 ProfileSelect = 0x10,
42 SoftwareKeyboard = 0x11, 44 SoftwareKeyboard = 0x11,
43}; 45};
44 46
@@ -775,6 +777,8 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default;
775 777
776static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) { 778static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) {
777 switch (id) { 779 switch (id) {
780 case AppletId::ProfileSelect:
781 return std::make_shared<Applets::ProfileSelect>();
778 case AppletId::SoftwareKeyboard: 782 case AppletId::SoftwareKeyboard:
779 return std::make_shared<Applets::SoftwareKeyboard>(); 783 return std::make_shared<Applets::SoftwareKeyboard>();
780 default: 784 default:
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp
new file mode 100644
index 000000000..4c7b45454
--- /dev/null
+++ b/src/core/hle/service/am/applets/profile_select.cpp
@@ -0,0 +1,77 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6
7#include "common/assert.h"
8#include "common/string_util.h"
9#include "core/core.h"
10#include "core/frontend/applets/software_keyboard.h"
11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/profile_select.h"
13
14namespace Service::AM::Applets {
15
16constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
17
18ProfileSelect::ProfileSelect() = default;
19ProfileSelect::~ProfileSelect() = default;
20
21void ProfileSelect::Initialize() {
22 complete = false;
23 status = RESULT_SUCCESS;
24 final_data.clear();
25
26 Applet::Initialize();
27
28 const auto user_config_storage = broker.PopNormalDataToApplet();
29 ASSERT(user_config_storage != nullptr);
30 const auto& user_config = user_config_storage->GetData();
31
32 ASSERT(user_config.size() >= sizeof(UserSelectionConfig));
33 std::memcpy(&config, user_config.data(), sizeof(UserSelectionConfig));
34}
35
36bool ProfileSelect::TransactionComplete() const {
37 return complete;
38}
39
40ResultCode ProfileSelect::GetStatus() const {
41 return status;
42}
43
44void ProfileSelect::ExecuteInteractive() {
45 UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
46}
47
48void ProfileSelect::Execute() {
49 if (complete) {
50 broker.PushNormalDataFromApplet(IStorage{final_data});
51 return;
52 }
53
54 const auto& frontend{Core::System::GetInstance().GetProfileSelector()};
55
56 frontend.SelectProfile([this](std::optional<Account::UUID> uuid) { SelectionComplete(uuid); });
57}
58
59void ProfileSelect::SelectionComplete(std::optional<Account::UUID> uuid) {
60 UserSelectionOutput output{};
61
62 if (uuid.has_value() && uuid->uuid != Account::INVALID_UUID) {
63 output.result = 0;
64 output.uuid_selected = uuid->uuid;
65 } else {
66 status = ERR_USER_CANCELLED_SELECTION;
67 output.result = ERR_USER_CANCELLED_SELECTION.raw;
68 output.uuid_selected = Account::INVALID_UUID;
69 }
70
71 final_data = std::vector<u8>(sizeof(UserSelectionOutput));
72 std::memcpy(final_data.data(), &output, final_data.size());
73 broker.PushNormalDataFromApplet(IStorage{final_data});
74 broker.SignalStateChanged();
75}
76
77} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h
new file mode 100644
index 000000000..787485f22
--- /dev/null
+++ b/src/core/hle/service/am/applets/profile_select.h
@@ -0,0 +1,50 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8
9#include "common/common_funcs.h"
10#include "core/hle/service/acc/profile_manager.h"
11#include "core/hle/service/am/applets/applets.h"
12
13namespace Service::AM::Applets {
14
15struct UserSelectionConfig {
16 // TODO(DarkLordZach): RE this structure
17 // It seems to be flags and the like that determine the UI of the applet on the switch... from
18 // my research this is safe to ignore for now.
19 INSERT_PADDING_BYTES(0xA0);
20};
21static_assert(sizeof(UserSelectionConfig) == 0xA0, "UserSelectionConfig has incorrect size.");
22
23struct UserSelectionOutput {
24 u64 result;
25 u128 uuid_selected;
26};
27static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has incorrect size.");
28
29class ProfileSelect final : public Applet {
30public:
31 ProfileSelect();
32 ~ProfileSelect() override;
33
34 void Initialize() override;
35
36 bool TransactionComplete() const override;
37 ResultCode GetStatus() const override;
38 void ExecuteInteractive() override;
39 void Execute() override;
40
41 void SelectionComplete(std::optional<Account::UUID> uuid);
42
43private:
44 UserSelectionConfig config;
45 bool complete = false;
46 ResultCode status = RESULT_SUCCESS;
47 std::vector<u8> final_data;
48};
49
50} // namespace Service::AM::Applets
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 0691b91a2..17ecaafde 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -7,6 +7,8 @@ add_executable(yuzu
7 Info.plist 7 Info.plist
8 about_dialog.cpp 8 about_dialog.cpp
9 about_dialog.h 9 about_dialog.h
10 applets/profile_select.cpp
11 applets/profile_select.h
10 applets/software_keyboard.cpp 12 applets/software_keyboard.cpp
11 applets/software_keyboard.h 13 applets/software_keyboard.h
12 bootmanager.cpp 14 bootmanager.cpp
diff --git a/src/yuzu/applets/profile_select.cpp b/src/yuzu/applets/profile_select.cpp
new file mode 100644
index 000000000..5c1b65a2c
--- /dev/null
+++ b/src/yuzu/applets/profile_select.cpp
@@ -0,0 +1,168 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <mutex>
6#include <QDialogButtonBox>
7#include <QLabel>
8#include <QLineEdit>
9#include <QScrollArea>
10#include <QStandardItemModel>
11#include <QVBoxLayout>
12#include "common/file_util.h"
13#include "common/string_util.h"
14#include "core/hle/lock.h"
15#include "yuzu/applets/profile_select.h"
16#include "yuzu/main.h"
17
18// Same backup JPEG used by acc IProfile::GetImage if no jpeg found
19constexpr std::array<u8, 107> backup_jpeg{
20 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02,
21 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05,
22 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e,
23 0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13,
24 0x12, 0x10, 0x13, 0x0f, 0x10, 0x10, 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01,
25 0x01, 0x01, 0x11, 0x00, 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08,
26 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9,
27};
28
29QString FormatUserEntryText(const QString& username, Service::Account::UUID uuid) {
30 return QtProfileSelectionDialog::tr(
31 "%1\n%2", "%1 is the profile username, %2 is the formatted UUID (e.g. "
32 "00112233-4455-6677-8899-AABBCCDDEEFF))")
33 .arg(username, QString::fromStdString(uuid.FormatSwitch()));
34}
35
36QString GetImagePath(Service::Account::UUID uuid) {
37 const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
38 "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
39 return QString::fromStdString(path);
40}
41
42QPixmap GetIcon(Service::Account::UUID uuid) {
43 QPixmap icon{GetImagePath(uuid)};
44
45 if (!icon) {
46 icon.fill(Qt::black);
47 icon.loadFromData(backup_jpeg.data(), static_cast<u32>(backup_jpeg.size()));
48 }
49
50 return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
51}
52
53QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
54 : QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) {
55 outer_layout = new QVBoxLayout;
56
57 instruction_label = new QLabel(tr("Select a user:"));
58
59 scroll_area = new QScrollArea;
60
61 buttons = new QDialogButtonBox;
62 buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
63 buttons->addButton(tr("OK"), QDialogButtonBox::AcceptRole);
64
65 connect(buttons, &QDialogButtonBox::accepted, this, &QtProfileSelectionDialog::accept);
66 connect(buttons, &QDialogButtonBox::rejected, this, &QtProfileSelectionDialog::reject);
67
68 outer_layout->addWidget(instruction_label);
69 outer_layout->addWidget(scroll_area);
70 outer_layout->addWidget(buttons);
71
72 layout = new QVBoxLayout;
73 tree_view = new QTreeView;
74 item_model = new QStandardItemModel(tree_view);
75 tree_view->setModel(item_model);
76
77 tree_view->setAlternatingRowColors(true);
78 tree_view->setSelectionMode(QHeaderView::SingleSelection);
79 tree_view->setSelectionBehavior(QHeaderView::SelectRows);
80 tree_view->setVerticalScrollMode(QHeaderView::ScrollPerPixel);
81 tree_view->setHorizontalScrollMode(QHeaderView::ScrollPerPixel);
82 tree_view->setSortingEnabled(true);
83 tree_view->setEditTriggers(QHeaderView::NoEditTriggers);
84 tree_view->setUniformRowHeights(true);
85 tree_view->setIconSize({64, 64});
86 tree_view->setContextMenuPolicy(Qt::NoContextMenu);
87
88 item_model->insertColumns(0, 1);
89 item_model->setHeaderData(0, Qt::Horizontal, "Users");
90
91 // We must register all custom types with the Qt Automoc system so that we are able to use it
92 // with signals/slots. In this case, QList falls under the umbrells of custom types.
93 qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
94
95 layout->setContentsMargins(0, 0, 0, 0);
96 layout->setSpacing(0);
97 layout->addWidget(tree_view);
98
99 scroll_area->setLayout(layout);
100
101 connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser);
102
103 const auto& profiles = profile_manager->GetAllUsers();
104 for (const auto& user : profiles) {
105 Service::Account::ProfileBase profile;
106 if (!profile_manager->GetProfileBase(user, profile))
107 continue;
108
109 const auto username = Common::StringFromFixedZeroTerminatedBuffer(
110 reinterpret_cast<const char*>(profile.username.data()), profile.username.size());
111
112 list_items.push_back(QList<QStandardItem*>{new QStandardItem{
113 GetIcon(user), FormatUserEntryText(QString::fromStdString(username), user)}});
114 }
115
116 for (const auto& item : list_items)
117 item_model->appendRow(item);
118
119 setLayout(outer_layout);
120 setWindowTitle(tr("Profile Selector"));
121 resize(550, 400);
122}
123
124QtProfileSelectionDialog::~QtProfileSelectionDialog() = default;
125
126void QtProfileSelectionDialog::accept() {
127 ok = true;
128 QDialog::accept();
129}
130
131void QtProfileSelectionDialog::reject() {
132 ok = false;
133 user_index = 0;
134 QDialog::reject();
135}
136
137bool QtProfileSelectionDialog::GetStatus() const {
138 return ok;
139}
140
141u32 QtProfileSelectionDialog::GetIndex() const {
142 return user_index;
143}
144
145void QtProfileSelectionDialog::SelectUser(const QModelIndex& index) {
146 user_index = index.row();
147}
148
149QtProfileSelector::QtProfileSelector(GMainWindow& parent) {
150 connect(this, &QtProfileSelector::MainWindowSelectProfile, &parent,
151 &GMainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection);
152 connect(&parent, &GMainWindow::ProfileSelectorFinishedSelection, this,
153 &QtProfileSelector::MainWindowFinishedSelection, Qt::DirectConnection);
154}
155
156QtProfileSelector::~QtProfileSelector() = default;
157
158void QtProfileSelector::SelectProfile(
159 std::function<void(std::optional<Service::Account::UUID>)> callback) const {
160 this->callback = std::move(callback);
161 emit MainWindowSelectProfile();
162}
163
164void QtProfileSelector::MainWindowFinishedSelection(std::optional<Service::Account::UUID> uuid) {
165 // Acquire the HLE mutex
166 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
167 callback(uuid);
168}
diff --git a/src/yuzu/applets/profile_select.h b/src/yuzu/applets/profile_select.h
new file mode 100644
index 000000000..868573324
--- /dev/null
+++ b/src/yuzu/applets/profile_select.h
@@ -0,0 +1,73 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include <QDialog>
9#include <QList>
10#include "core/frontend/applets/profile_select.h"
11
12class GMainWindow;
13class QDialogButtonBox;
14class QGraphicsScene;
15class QLabel;
16class QScrollArea;
17class QStandardItem;
18class QStandardItemModel;
19class QTreeView;
20class QVBoxLayout;
21
22class QtProfileSelectionDialog final : public QDialog {
23 Q_OBJECT
24
25public:
26 explicit QtProfileSelectionDialog(QWidget* parent);
27 ~QtProfileSelectionDialog() override;
28
29 void accept() override;
30 void reject() override;
31
32 bool GetStatus() const;
33 u32 GetIndex() const;
34
35private:
36 bool ok = false;
37 u32 user_index = 0;
38
39 void SelectUser(const QModelIndex& index);
40
41 QVBoxLayout* layout;
42 QTreeView* tree_view;
43 QStandardItemModel* item_model;
44 QGraphicsScene* scene;
45
46 std::vector<QList<QStandardItem*>> list_items;
47
48 QVBoxLayout* outer_layout;
49 QLabel* instruction_label;
50 QScrollArea* scroll_area;
51 QDialogButtonBox* buttons;
52
53 std::unique_ptr<Service::Account::ProfileManager> profile_manager;
54};
55
56class QtProfileSelector final : public QObject, public Core::Frontend::ProfileSelectApplet {
57 Q_OBJECT
58
59public:
60 explicit QtProfileSelector(GMainWindow& parent);
61 ~QtProfileSelector() override;
62
63 void SelectProfile(
64 std::function<void(std::optional<Service::Account::UUID>)> callback) const override;
65
66signals:
67 void MainWindowSelectProfile() const;
68
69private:
70 void MainWindowFinishedSelection(std::optional<Service::Account::UUID> uuid);
71
72 mutable std::function<void(std::optional<Service::Account::UUID>)> callback;
73};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 90b212ba5..feb5572c6 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -8,6 +8,7 @@
8#include <thread> 8#include <thread>
9 9
10// VFS includes must be before glad as they will conflict with Windows file api, which uses defines. 10// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
11#include "applets/profile_select.h"
11#include "applets/software_keyboard.h" 12#include "applets/software_keyboard.h"
12#include "configuration/configure_per_general.h" 13#include "configuration/configure_per_general.h"
13#include "core/file_sys/vfs.h" 14#include "core/file_sys/vfs.h"
@@ -208,6 +209,28 @@ GMainWindow::~GMainWindow() {
208 delete render_window; 209 delete render_window;
209} 210}
210 211
212void GMainWindow::ProfileSelectorSelectProfile() {
213 QtProfileSelectionDialog dialog(this);
214 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
215 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
216 dialog.setWindowModality(Qt::WindowModal);
217 dialog.exec();
218
219 if (!dialog.GetStatus()) {
220 emit ProfileSelectorFinishedSelection(std::nullopt);
221 return;
222 }
223
224 Service::Account::ProfileManager manager;
225 const auto uuid = manager.GetUser(dialog.GetIndex());
226 if (!uuid.has_value()) {
227 emit ProfileSelectorFinishedSelection(std::nullopt);
228 return;
229 }
230
231 emit ProfileSelectorFinishedSelection(uuid);
232}
233
211void GMainWindow::SoftwareKeyboardGetText( 234void GMainWindow::SoftwareKeyboardGetText(
212 const Core::Frontend::SoftwareKeyboardParameters& parameters) { 235 const Core::Frontend::SoftwareKeyboardParameters& parameters) {
213 QtSoftwareKeyboardDialog dialog(this, parameters); 236 QtSoftwareKeyboardDialog dialog(this, parameters);
@@ -574,6 +597,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
574 597
575 system.SetGPUDebugContext(debug_context); 598 system.SetGPUDebugContext(debug_context);
576 599
600 system.SetProfileSelector(std::make_unique<QtProfileSelector>(*this));
577 system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this)); 601 system.SetSoftwareKeyboard(std::make_unique<QtSoftwareKeyboard>(*this));
578 602
579 const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; 603 const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index ca9c50367..4a982bb02 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -99,10 +99,12 @@ signals:
99 // Signal that tells widgets to update icons to use the current theme 99 // Signal that tells widgets to update icons to use the current theme
100 void UpdateThemedIcons(); 100 void UpdateThemedIcons();
101 101
102 void ProfileSelectorFinishedSelection(std::optional<Service::Account::UUID> uuid);
102 void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); 103 void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
103 void SoftwareKeyboardFinishedCheckDialog(); 104 void SoftwareKeyboardFinishedCheckDialog();
104 105
105public slots: 106public slots:
107 void ProfileSelectorSelectProfile();
106 void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); 108 void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
107 void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); 109 void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
108 110