1 // Copyright 2016 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4 
5 #include <array>
6 #include <chrono>
7 #include <optional>
8 
9 #include <QFileDialog>
10 #include <QGraphicsItem>
11 #include <QMessageBox>
12 #include "common/assert.h"
13 #include "common/file_util.h"
14 #include "core/core.h"
15 #include "core/hle/service/time/time.h"
16 #include "core/settings.h"
17 #include "ui_configure_system.h"
18 #include "yuzu/configuration/configuration_shared.h"
19 #include "yuzu/configuration/configure_system.h"
20 
ConfigureSystem(QWidget * parent)21 ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) {
22     ui->setupUi(this);
23     connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
24             &ConfigureSystem::RefreshConsoleID);
25 
26     connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
27         ui->rng_seed_edit->setEnabled(state == Qt::Checked);
28         if (state != Qt::Checked) {
29             ui->rng_seed_edit->setText(QStringLiteral("00000000"));
30         }
31     });
32 
33     connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
34         ui->custom_rtc_edit->setEnabled(state == Qt::Checked);
35         if (state != Qt::Checked) {
36             ui->custom_rtc_edit->setDateTime(QDateTime::currentDateTime());
37         }
38     });
39 
40     ui->label_console_id->setVisible(Settings::IsConfiguringGlobal());
41     ui->button_regenerate_console_id->setVisible(Settings::IsConfiguringGlobal());
42 
43     SetupPerGameUI();
44 
45     SetConfiguration();
46 }
47 
48 ConfigureSystem::~ConfigureSystem() = default;
49 
changeEvent(QEvent * event)50 void ConfigureSystem::changeEvent(QEvent* event) {
51     if (event->type() == QEvent::LanguageChange) {
52         RetranslateUI();
53     }
54 
55     QWidget::changeEvent(event);
56 }
57 
RetranslateUI()58 void ConfigureSystem::RetranslateUI() {
59     ui->retranslateUi(this);
60 }
61 
SetConfiguration()62 void ConfigureSystem::SetConfiguration() {
63     enabled = !Core::System::GetInstance().IsPoweredOn();
64     const auto rng_seed =
65         QStringLiteral("%1")
66             .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'})
67             .toUpper();
68     const auto rtc_time = Settings::values.custom_rtc.GetValue().value_or(
69         std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
70 
71     ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
72     ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() &&
73                                   Settings::values.rng_seed.UsingGlobal());
74     ui->rng_seed_edit->setText(rng_seed);
75 
76     ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value());
77     ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() &&
78                                     Settings::values.rng_seed.UsingGlobal());
79     ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
80 
81     if (Settings::IsConfiguringGlobal()) {
82         ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
83         ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue());
84         ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue());
85         ui->combo_sound->setCurrentIndex(Settings::values.sound_index.GetValue());
86     } else {
87         ConfigurationShared::SetPerGameSetting(ui->combo_language,
88                                                &Settings::values.language_index);
89         ConfigurationShared::SetPerGameSetting(ui->combo_region, &Settings::values.region_index);
90         ConfigurationShared::SetPerGameSetting(ui->combo_time_zone,
91                                                &Settings::values.time_zone_index);
92         ConfigurationShared::SetPerGameSetting(ui->combo_sound, &Settings::values.sound_index);
93 
94         ConfigurationShared::SetHighlight(ui->label_language,
95                                           !Settings::values.language_index.UsingGlobal());
96         ConfigurationShared::SetHighlight(ui->label_region,
97                                           !Settings::values.region_index.UsingGlobal());
98         ConfigurationShared::SetHighlight(ui->label_timezone,
99                                           !Settings::values.time_zone_index.UsingGlobal());
100         ConfigurationShared::SetHighlight(ui->label_sound,
101                                           !Settings::values.sound_index.UsingGlobal());
102     }
103 }
104 
ReadSystemSettings()105 void ConfigureSystem::ReadSystemSettings() {}
106 
ApplyConfiguration()107 void ConfigureSystem::ApplyConfiguration() {
108     auto& system = Core::System::GetInstance();
109 
110     // Allow setting custom RTC even if system is powered on,
111     // to allow in-game time to be fast forwarded
112     if (Settings::values.custom_rtc.UsingGlobal()) {
113         if (ui->custom_rtc_checkbox->isChecked()) {
114             Settings::values.custom_rtc.SetValue(
115                 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
116             if (system.IsPoweredOn()) {
117                 const s64 posix_time{Settings::values.custom_rtc.GetValue()->count() +
118                                      Service::Time::TimeManager::GetExternalTimeZoneOffset()};
119                 system.GetTimeManager().UpdateLocalSystemClockTime(posix_time);
120             }
121         } else {
122             Settings::values.custom_rtc.SetValue(std::nullopt);
123         }
124     }
125 
126     if (!enabled) {
127         return;
128     }
129 
130     if (Settings::IsConfiguringGlobal()) {
131         // Guard if during game and set to game-specific value
132         if (Settings::values.language_index.UsingGlobal()) {
133             Settings::values.language_index.SetValue(ui->combo_language->currentIndex());
134         }
135         if (Settings::values.region_index.UsingGlobal()) {
136             Settings::values.region_index.SetValue(ui->combo_region->currentIndex());
137         }
138         if (Settings::values.time_zone_index.UsingGlobal()) {
139             Settings::values.time_zone_index.SetValue(ui->combo_time_zone->currentIndex());
140         }
141         if (Settings::values.sound_index.UsingGlobal()) {
142             Settings::values.sound_index.SetValue(ui->combo_sound->currentIndex());
143         }
144 
145         if (Settings::values.rng_seed.UsingGlobal()) {
146             if (ui->rng_seed_checkbox->isChecked()) {
147                 Settings::values.rng_seed.SetValue(
148                     ui->rng_seed_edit->text().toULongLong(nullptr, 16));
149             } else {
150                 Settings::values.rng_seed.SetValue(std::nullopt);
151             }
152         }
153     } else {
154         ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index,
155                                                  ui->combo_language);
156         ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
157         ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
158                                                  ui->combo_time_zone);
159         ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
160 
161         switch (use_rng_seed) {
162         case ConfigurationShared::CheckState::On:
163         case ConfigurationShared::CheckState::Off:
164             Settings::values.rng_seed.SetGlobal(false);
165             if (ui->rng_seed_checkbox->isChecked()) {
166                 Settings::values.rng_seed.SetValue(
167                     ui->rng_seed_edit->text().toULongLong(nullptr, 16));
168             } else {
169                 Settings::values.rng_seed.SetValue(std::nullopt);
170             }
171             break;
172         case ConfigurationShared::CheckState::Global:
173             Settings::values.rng_seed.SetGlobal(false);
174             Settings::values.rng_seed.SetValue(std::nullopt);
175             Settings::values.rng_seed.SetGlobal(true);
176             break;
177         case ConfigurationShared::CheckState::Count:
178             break;
179         }
180 
181         switch (use_custom_rtc) {
182         case ConfigurationShared::CheckState::On:
183         case ConfigurationShared::CheckState::Off:
184             Settings::values.custom_rtc.SetGlobal(false);
185             if (ui->custom_rtc_checkbox->isChecked()) {
186                 Settings::values.custom_rtc.SetValue(
187                     std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
188             } else {
189                 Settings::values.custom_rtc.SetValue(std::nullopt);
190             }
191             break;
192         case ConfigurationShared::CheckState::Global:
193             Settings::values.custom_rtc.SetGlobal(false);
194             Settings::values.custom_rtc.SetValue(std::nullopt);
195             Settings::values.custom_rtc.SetGlobal(true);
196             break;
197         case ConfigurationShared::CheckState::Count:
198             break;
199         }
200     }
201 
202     Settings::Apply(system);
203 }
204 
RefreshConsoleID()205 void ConfigureSystem::RefreshConsoleID() {
206     QMessageBox::StandardButton reply;
207     QString warning_text = tr("This will replace your current virtual Switch with a new one. "
208                               "Your current virtual Switch will not be recoverable. "
209                               "This might have unexpected effects in games. This might fail, "
210                               "if you use an outdated config savegame. Continue?");
211     reply = QMessageBox::critical(this, tr("Warning"), warning_text,
212                                   QMessageBox::No | QMessageBox::Yes);
213     if (reply == QMessageBox::No) {
214         return;
215     }
216 
217     u64 console_id{};
218     ui->label_console_id->setText(
219         tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
220 }
221 
SetupPerGameUI()222 void ConfigureSystem::SetupPerGameUI() {
223     if (Settings::IsConfiguringGlobal()) {
224         ui->combo_language->setEnabled(Settings::values.language_index.UsingGlobal());
225         ui->combo_region->setEnabled(Settings::values.region_index.UsingGlobal());
226         ui->combo_time_zone->setEnabled(Settings::values.time_zone_index.UsingGlobal());
227         ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal());
228         ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal());
229         ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal());
230         ui->custom_rtc_checkbox->setEnabled(Settings::values.custom_rtc.UsingGlobal());
231         ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.UsingGlobal());
232 
233         return;
234     }
235 
236     ConfigurationShared::SetColoredComboBox(ui->combo_language, ui->label_language,
237                                             Settings::values.language_index.GetValue(true));
238     ConfigurationShared::SetColoredComboBox(ui->combo_region, ui->label_region,
239                                             Settings::values.region_index.GetValue(true));
240     ConfigurationShared::SetColoredComboBox(ui->combo_time_zone, ui->label_timezone,
241                                             Settings::values.time_zone_index.GetValue(true));
242     ConfigurationShared::SetColoredComboBox(ui->combo_sound, ui->label_sound,
243                                             Settings::values.sound_index.GetValue(true));
244 
245     ConfigurationShared::SetColoredTristate(
246         ui->rng_seed_checkbox, Settings::values.rng_seed.UsingGlobal(),
247         Settings::values.rng_seed.GetValue().has_value(),
248         Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed);
249     ConfigurationShared::SetColoredTristate(
250         ui->custom_rtc_checkbox, Settings::values.custom_rtc.UsingGlobal(),
251         Settings::values.custom_rtc.GetValue().has_value(),
252         Settings::values.custom_rtc.GetValue(true).has_value(), use_custom_rtc);
253 }
254