diff options
| author | 2023-05-08 22:37:03 -0400 | |
|---|---|---|
| committer | 2023-07-21 10:56:07 -0400 | |
| commit | f66d617107e45f8213643f2bbaa5f58878c3d3a6 (patch) | |
| tree | dce6687605ba2f3d195d75aec44a92769e95455f | |
| parent | configuration: Implement slider (diff) | |
| download | yuzu-f66d617107e45f8213643f2bbaa5f58878c3d3a6.tar.gz yuzu-f66d617107e45f8213643f2bbaa5f58878c3d3a6.tar.xz yuzu-f66d617107e45f8213643f2bbaa5f58878c3d3a6.zip | |
configuration: Move CreateWidget to a class
We were passing so many objects between the function and the caller that
it needed to be redesigned.
| -rw-r--r-- | src/yuzu/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 3 | ||||
| -rw-r--r-- | src/yuzu/configuration/configuration_shared.cpp | 386 | ||||
| -rw-r--r-- | src/yuzu/configuration/configuration_shared.h | 18 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_general.cpp | 63 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics.cpp | 55 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics.h | 1 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics_advanced.cpp | 8 | ||||
| -rw-r--r-- | src/yuzu/configuration/shared_widget.cpp | 360 | ||||
| -rw-r--r-- | src/yuzu/configuration/shared_widget.h | 64 |
10 files changed, 507 insertions, 453 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 8b54e1268..899b75871 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -145,6 +145,8 @@ add_executable(yuzu | |||
| 145 | configuration/input_profiles.h | 145 | configuration/input_profiles.h |
| 146 | configuration/shared_translation.cpp | 146 | configuration/shared_translation.cpp |
| 147 | configuration/shared_translation.h | 147 | configuration/shared_translation.h |
| 148 | configuration/shared_widget.cpp | ||
| 149 | configuration/shared_widget.h | ||
| 148 | debugger/console.cpp | 150 | debugger/console.cpp |
| 149 | debugger/console.h | 151 | debugger/console.h |
| 150 | debugger/controller.cpp | 152 | debugger/controller.cpp |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index c6a34e787..08aa20859 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -1346,8 +1346,11 @@ void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) { | |||
| 1346 | 1346 | ||
| 1347 | void Config::WriteSettingGeneric(Settings::BasicSetting* const setting) const { | 1347 | void Config::WriteSettingGeneric(Settings::BasicSetting* const setting) const { |
| 1348 | if (!setting->Save()) { | 1348 | if (!setting->Save()) { |
| 1349 | LOG_DEBUG(Frontend, "Skipping \"{}\" marked for not saving", setting->GetLabel()); | ||
| 1349 | return; | 1350 | return; |
| 1350 | } | 1351 | } |
| 1352 | LOG_DEBUG(Frontend, "Saving {} setting \"{}\"...", global ? "global" : "custom", | ||
| 1353 | setting->GetLabel()); | ||
| 1351 | const QVariant value = QVariant::fromValue(QString::fromStdString(setting->ToString())); | 1354 | const QVariant value = QVariant::fromValue(QString::fromStdString(setting->ToString())); |
| 1352 | const QVariant default_value = | 1355 | const QVariant default_value = |
| 1353 | QVariant::fromValue(QString::fromStdString(setting->DefaultToString())); | 1356 | QVariant::fromValue(QString::fromStdString(setting->DefaultToString())); |
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp index 076d9cc0d..dff70f04b 100644 --- a/src/yuzu/configuration/configuration_shared.cpp +++ b/src/yuzu/configuration/configuration_shared.cpp | |||
| @@ -28,392 +28,6 @@ | |||
| 28 | 28 | ||
| 29 | namespace ConfigurationShared { | 29 | namespace ConfigurationShared { |
| 30 | 30 | ||
| 31 | static QPushButton* CreateRestoreGlobalButton(QWidget* parent, Settings::BasicSetting* setting) { | ||
| 32 | QStyle* style = parent->style(); | ||
| 33 | QIcon* icon = new QIcon(style->standardIcon(QStyle::SP_DialogResetButton)); | ||
| 34 | QPushButton* button = new QPushButton(*icon, QStringLiteral(""), parent); | ||
| 35 | button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); | ||
| 36 | |||
| 37 | QSizePolicy sp_retain = button->sizePolicy(); | ||
| 38 | sp_retain.setRetainSizeWhenHidden(true); | ||
| 39 | button->setSizePolicy(sp_retain); | ||
| 40 | |||
| 41 | button->setEnabled(!setting->UsingGlobal()); | ||
| 42 | button->setVisible(!setting->UsingGlobal()); | ||
| 43 | |||
| 44 | return button; | ||
| 45 | } | ||
| 46 | |||
| 47 | static std::tuple<QWidget*, void*, QPushButton*, std::function<void()>> CreateCheckBox( | ||
| 48 | Settings::BasicSetting* setting, const QString& label, QWidget* parent) { | ||
| 49 | QWidget* widget = new QWidget(parent); | ||
| 50 | QHBoxLayout* layout = new QHBoxLayout(widget); | ||
| 51 | |||
| 52 | QCheckBox* checkbox = new QCheckBox(label, parent); | ||
| 53 | checkbox->setObjectName(QString::fromStdString(setting->GetLabel())); | ||
| 54 | checkbox->setCheckState(setting->ToString() == "true" ? Qt::CheckState::Checked | ||
| 55 | : Qt::CheckState::Unchecked); | ||
| 56 | |||
| 57 | std::function<void()> load_func; | ||
| 58 | |||
| 59 | QPushButton* button{nullptr}; | ||
| 60 | |||
| 61 | layout->addWidget(checkbox); | ||
| 62 | if (Settings::IsConfiguringGlobal()) { | ||
| 63 | load_func = [setting, checkbox]() { | ||
| 64 | setting->LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); | ||
| 65 | }; | ||
| 66 | } else { | ||
| 67 | button = CreateRestoreGlobalButton(parent, setting); | ||
| 68 | layout->addWidget(button); | ||
| 69 | |||
| 70 | QObject::connect(checkbox, &QCheckBox::stateChanged, [button](int) { | ||
| 71 | button->setVisible(true); | ||
| 72 | button->setEnabled(true); | ||
| 73 | }); | ||
| 74 | |||
| 75 | QObject::connect(button, &QAbstractButton::clicked, [checkbox, setting, button](bool) { | ||
| 76 | checkbox->setCheckState(setting->ToStringGlobal() == "true" ? Qt::Checked | ||
| 77 | : Qt::Unchecked); | ||
| 78 | button->setEnabled(false); | ||
| 79 | button->setVisible(false); | ||
| 80 | }); | ||
| 81 | |||
| 82 | load_func = [setting, checkbox, button]() { | ||
| 83 | bool using_global = !button->isEnabled(); | ||
| 84 | setting->SetGlobal(using_global); | ||
| 85 | if (!using_global) { | ||
| 86 | setting->LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); | ||
| 87 | } | ||
| 88 | }; | ||
| 89 | } | ||
| 90 | |||
| 91 | layout->setContentsMargins(0, 0, 0, 0); | ||
| 92 | |||
| 93 | return {widget, checkbox, button, load_func}; | ||
| 94 | } | ||
| 95 | |||
| 96 | static std::tuple<QWidget*, QComboBox*, QPushButton*, std::function<void()>> CreateCombobox( | ||
| 97 | Settings::BasicSetting* setting, const QString& label, QWidget* parent, bool managed) { | ||
| 98 | const auto type = setting->TypeId(); | ||
| 99 | |||
| 100 | QWidget* group = new QWidget(parent); | ||
| 101 | group->setObjectName(QString::fromStdString(setting->GetLabel())); | ||
| 102 | QLayout* layout = new QHBoxLayout(group); | ||
| 103 | |||
| 104 | QLabel* qt_label = new QLabel(label, parent); | ||
| 105 | QComboBox* combobox = new QComboBox(parent); | ||
| 106 | |||
| 107 | QPushButton* button{nullptr}; | ||
| 108 | |||
| 109 | std::forward_list<QString> combobox_enumerations = ComboboxEnumeration(type, parent); | ||
| 110 | for (const auto& item : combobox_enumerations) { | ||
| 111 | combobox->addItem(item); | ||
| 112 | } | ||
| 113 | |||
| 114 | layout->addWidget(qt_label); | ||
| 115 | layout->addWidget(combobox); | ||
| 116 | |||
| 117 | layout->setSpacing(6); | ||
| 118 | layout->setContentsMargins(0, 0, 0, 0); | ||
| 119 | |||
| 120 | combobox->setCurrentIndex(std::stoi(setting->ToString())); | ||
| 121 | |||
| 122 | std::function<void()> load_func = []() {}; | ||
| 123 | |||
| 124 | if (Settings::IsConfiguringGlobal() && managed) { | ||
| 125 | load_func = [setting, combobox]() { | ||
| 126 | setting->LoadString(std::to_string(combobox->currentIndex())); | ||
| 127 | }; | ||
| 128 | } else if (managed) { | ||
| 129 | button = CreateRestoreGlobalButton(parent, setting); | ||
| 130 | layout->addWidget(button); | ||
| 131 | |||
| 132 | QObject::connect(button, &QAbstractButton::clicked, [button, combobox, setting](bool) { | ||
| 133 | button->setEnabled(false); | ||
| 134 | button->setVisible(false); | ||
| 135 | |||
| 136 | combobox->setCurrentIndex(std::stoi(setting->ToStringGlobal())); | ||
| 137 | }); | ||
| 138 | |||
| 139 | QObject::connect(combobox, QOverload<int>::of(&QComboBox::activated), [=](int) { | ||
| 140 | button->setEnabled(true); | ||
| 141 | button->setVisible(true); | ||
| 142 | }); | ||
| 143 | |||
| 144 | load_func = [setting, combobox, button]() { | ||
| 145 | bool using_global = !button->isEnabled(); | ||
| 146 | setting->SetGlobal(using_global); | ||
| 147 | if (!using_global) { | ||
| 148 | setting->LoadString(std::to_string(combobox->currentIndex())); | ||
| 149 | } | ||
| 150 | }; | ||
| 151 | } | ||
| 152 | |||
| 153 | return {group, combobox, button, load_func}; | ||
| 154 | } | ||
| 155 | |||
| 156 | static std::tuple<QWidget*, void*, QPushButton*, std::function<void()>> CreateLineEdit( | ||
| 157 | Settings::BasicSetting* setting, const QString& label, QWidget* parent, bool managed = true) { | ||
| 158 | QWidget* widget = new QWidget(parent); | ||
| 159 | widget->setObjectName(label); | ||
| 160 | |||
| 161 | QHBoxLayout* layout = new QHBoxLayout(widget); | ||
| 162 | QLineEdit* line_edit = new QLineEdit(parent); | ||
| 163 | |||
| 164 | const QString text = QString::fromStdString(setting->ToString()); | ||
| 165 | line_edit->setText(text); | ||
| 166 | |||
| 167 | std::function<void()> load_func = []() {}; | ||
| 168 | |||
| 169 | QLabel* q_label = new QLabel(label, widget); | ||
| 170 | // setSizePolicy lets widget expand and take an equal part of the space as the line edit | ||
| 171 | q_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); | ||
| 172 | layout->addWidget(q_label); | ||
| 173 | |||
| 174 | layout->addWidget(line_edit); | ||
| 175 | |||
| 176 | QPushButton* button{nullptr}; | ||
| 177 | |||
| 178 | if (Settings::IsConfiguringGlobal() && !managed) { | ||
| 179 | load_func = [line_edit, setting]() { | ||
| 180 | std::string load_text = line_edit->text().toStdString(); | ||
| 181 | setting->LoadString(load_text); | ||
| 182 | }; | ||
| 183 | } else if (!managed) { | ||
| 184 | button = CreateRestoreGlobalButton(parent, setting); | ||
| 185 | layout->addWidget(button); | ||
| 186 | |||
| 187 | QObject::connect(button, &QAbstractButton::clicked, [=](bool) { | ||
| 188 | button->setEnabled(false); | ||
| 189 | button->setVisible(false); | ||
| 190 | |||
| 191 | line_edit->setText(QString::fromStdString(setting->ToStringGlobal())); | ||
| 192 | }); | ||
| 193 | |||
| 194 | QObject::connect(line_edit, &QLineEdit::textChanged, [=](QString) { | ||
| 195 | button->setEnabled(true); | ||
| 196 | button->setVisible(true); | ||
| 197 | }); | ||
| 198 | |||
| 199 | load_func = [=]() { | ||
| 200 | bool using_global = !button->isEnabled(); | ||
| 201 | setting->SetGlobal(using_global); | ||
| 202 | if (!using_global) { | ||
| 203 | setting->LoadString(line_edit->text().toStdString()); | ||
| 204 | } | ||
| 205 | }; | ||
| 206 | } | ||
| 207 | |||
| 208 | layout->setContentsMargins(0, 0, 0, 0); | ||
| 209 | |||
| 210 | return {widget, line_edit, button, load_func}; | ||
| 211 | } | ||
| 212 | |||
| 213 | static std::tuple<QWidget*, void*, QPushButton*, std::function<void()>> CreateSlider( | ||
| 214 | Settings::BasicSetting* setting, const QString& name, QWidget* parent, bool reversed, | ||
| 215 | float multiplier) { | ||
| 216 | QWidget* widget = new QWidget(parent); | ||
| 217 | QHBoxLayout* layout = new QHBoxLayout(widget); | ||
| 218 | QSlider* slider = new QSlider(Qt::Horizontal, widget); | ||
| 219 | QLabel* label = new QLabel(name, widget); | ||
| 220 | QPushButton* button{nullptr}; | ||
| 221 | QLabel* feedback = new QLabel(widget); | ||
| 222 | |||
| 223 | layout->addWidget(label); | ||
| 224 | layout->addWidget(slider); | ||
| 225 | layout->addWidget(feedback); | ||
| 226 | |||
| 227 | label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); | ||
| 228 | |||
| 229 | layout->setContentsMargins(0, 0, 0, 0); | ||
| 230 | |||
| 231 | int max_val = std::stoi(setting->MaxVal()); | ||
| 232 | |||
| 233 | QObject::connect(slider, &QAbstractSlider::valueChanged, [=](int value) { | ||
| 234 | int present = (reversed ? max_val - value : value) * multiplier; | ||
| 235 | feedback->setText( | ||
| 236 | QStringLiteral("%1%").arg(QString::fromStdString(std::to_string(present)))); | ||
| 237 | }); | ||
| 238 | |||
| 239 | slider->setValue(std::stoi(setting->ToString())); | ||
| 240 | slider->setMinimum(std::stoi(setting->MinVal())); | ||
| 241 | slider->setMaximum(max_val); | ||
| 242 | |||
| 243 | if (reversed) { | ||
| 244 | slider->setInvertedAppearance(true); | ||
| 245 | } | ||
| 246 | |||
| 247 | std::function<void()> load_func; | ||
| 248 | |||
| 249 | if (Settings::IsConfiguringGlobal()) { | ||
| 250 | load_func = [=]() { setting->LoadString(std::to_string(slider->value())); }; | ||
| 251 | } else { | ||
| 252 | button = CreateRestoreGlobalButton(parent, setting); | ||
| 253 | layout->addWidget(button); | ||
| 254 | |||
| 255 | QObject::connect(button, &QAbstractButton::clicked, [=](bool) { | ||
| 256 | slider->setValue(std::stoi(setting->ToStringGlobal())); | ||
| 257 | |||
| 258 | button->setEnabled(false); | ||
| 259 | button->setVisible(false); | ||
| 260 | }); | ||
| 261 | |||
| 262 | QObject::connect(slider, &QAbstractSlider::sliderMoved, [=](int) { | ||
| 263 | button->setEnabled(true); | ||
| 264 | button->setVisible(true); | ||
| 265 | }); | ||
| 266 | |||
| 267 | load_func = [=]() { | ||
| 268 | bool using_global = !button->isEnabled(); | ||
| 269 | setting->SetGlobal(using_global); | ||
| 270 | if (!using_global) { | ||
| 271 | setting->LoadString(std::to_string(slider->value())); | ||
| 272 | } | ||
| 273 | }; | ||
| 274 | } | ||
| 275 | |||
| 276 | return {widget, slider, button, []() {}}; | ||
| 277 | } | ||
| 278 | |||
| 279 | static std::tuple<QWidget*, void*, void*, QPushButton*, std::function<void()>> | ||
| 280 | CreateCheckBoxWithLineEdit(Settings::BasicSetting* setting, const QString& label, QWidget* parent) { | ||
| 281 | auto tuple = CreateCheckBox(setting, label, parent); | ||
| 282 | auto* widget = std::get<0>(tuple); | ||
| 283 | auto* checkbox = std::get<1>(tuple); | ||
| 284 | auto* button = std::get<2>(tuple); | ||
| 285 | auto load_func = std::get<3>(tuple); | ||
| 286 | QHBoxLayout* layout = dynamic_cast<QHBoxLayout*>(widget->layout()); | ||
| 287 | |||
| 288 | auto line_edit_tuple = CreateLineEdit(setting, label, parent, false); | ||
| 289 | auto* line_edit_widget = std::get<0>(line_edit_tuple); | ||
| 290 | auto* line_edit = std::get<1>(line_edit_tuple); | ||
| 291 | |||
| 292 | layout->insertWidget(1, line_edit_widget); | ||
| 293 | |||
| 294 | return {widget, checkbox, line_edit, button, load_func}; | ||
| 295 | } | ||
| 296 | |||
| 297 | std::tuple<QWidget*, void*, QPushButton*> CreateWidget( | ||
| 298 | Settings::BasicSetting* setting, const TranslationMap& translations, QWidget* parent, | ||
| 299 | bool runtime_lock, std::forward_list<std::function<void(bool)>>& apply_funcs, | ||
| 300 | RequestType request, bool managed, float multiplier, const std::string& text_box_default) { | ||
| 301 | if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) { | ||
| 302 | LOG_DEBUG(Frontend, "\"{}\" is not switchable, skipping...", setting->GetLabel()); | ||
| 303 | return {nullptr, nullptr, nullptr}; | ||
| 304 | } | ||
| 305 | |||
| 306 | const auto type = setting->TypeId(); | ||
| 307 | const int id = setting->Id(); | ||
| 308 | QWidget* widget{nullptr}; | ||
| 309 | void* extra{nullptr}; | ||
| 310 | |||
| 311 | std::function<void()> load_func; | ||
| 312 | |||
| 313 | const auto [label, tooltip] = [&]() { | ||
| 314 | const auto& setting_label = setting->GetLabel(); | ||
| 315 | if (translations.contains(id)) { | ||
| 316 | return std::pair{translations.at(id).first, translations.at(id).second}; | ||
| 317 | } | ||
| 318 | LOG_ERROR(Frontend, "Translation table lacks entry for \"{}\"", setting_label); | ||
| 319 | return std::pair{QString::fromStdString(setting_label), QStringLiteral("")}; | ||
| 320 | }(); | ||
| 321 | |||
| 322 | if (label == QStringLiteral("")) { | ||
| 323 | LOG_DEBUG(Frontend, "Translation table has emtpy entry for \"{}\", skipping...", | ||
| 324 | setting->GetLabel()); | ||
| 325 | return {nullptr, nullptr, nullptr}; | ||
| 326 | } | ||
| 327 | |||
| 328 | QPushButton* button; | ||
| 329 | |||
| 330 | if (type == typeid(bool)) { | ||
| 331 | switch (request) { | ||
| 332 | case RequestType::Default: { | ||
| 333 | auto tuple = CreateCheckBox(setting, label, parent); | ||
| 334 | widget = std::get<0>(tuple); | ||
| 335 | extra = std::get<1>(tuple); | ||
| 336 | button = std::get<2>(tuple); | ||
| 337 | load_func = std::get<3>(tuple); | ||
| 338 | break; | ||
| 339 | } | ||
| 340 | case RequestType::LineEdit: { | ||
| 341 | auto tuple = CreateCheckBoxWithLineEdit(setting, label, parent); | ||
| 342 | widget = std::get<0>(tuple); | ||
| 343 | break; | ||
| 344 | } | ||
| 345 | case RequestType::ComboBox: | ||
| 346 | case RequestType::SpinBox: | ||
| 347 | case RequestType::Slider: | ||
| 348 | case RequestType::ReverseSlider: | ||
| 349 | case RequestType::MaxEnum: | ||
| 350 | break; | ||
| 351 | } | ||
| 352 | } else if (setting->IsEnum()) { | ||
| 353 | auto tuple = CreateCombobox(setting, label, parent, managed); | ||
| 354 | widget = std::get<0>(tuple); | ||
| 355 | extra = std::get<1>(tuple); | ||
| 356 | button = std::get<2>(tuple); | ||
| 357 | load_func = std::get<3>(tuple); | ||
| 358 | } else if (type == typeid(u32) || type == typeid(int)) { | ||
| 359 | switch (request) { | ||
| 360 | case RequestType::LineEdit: | ||
| 361 | case RequestType::Default: { | ||
| 362 | auto tuple = CreateLineEdit(setting, label, parent); | ||
| 363 | widget = std::get<0>(tuple); | ||
| 364 | extra = std::get<1>(tuple); | ||
| 365 | button = std::get<2>(tuple); | ||
| 366 | load_func = std::get<3>(tuple); | ||
| 367 | break; | ||
| 368 | } | ||
| 369 | case RequestType::ComboBox: { | ||
| 370 | auto tuple = CreateCombobox(setting, label, parent, managed); | ||
| 371 | widget = std::get<0>(tuple); | ||
| 372 | extra = std::get<1>(tuple); | ||
| 373 | button = std::get<2>(tuple); | ||
| 374 | load_func = std::get<3>(tuple); | ||
| 375 | break; | ||
| 376 | } | ||
| 377 | case RequestType::Slider: | ||
| 378 | case RequestType::ReverseSlider: { | ||
| 379 | auto tuple = CreateSlider(setting, label, parent, request == RequestType::ReverseSlider, | ||
| 380 | multiplier); | ||
| 381 | widget = std::get<0>(tuple); | ||
| 382 | extra = std::get<1>(tuple); | ||
| 383 | button = std::get<2>(tuple); | ||
| 384 | load_func = std::get<3>(tuple); | ||
| 385 | break; | ||
| 386 | } | ||
| 387 | case RequestType::SpinBox: | ||
| 388 | case RequestType::MaxEnum: | ||
| 389 | break; | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | if (widget == nullptr) { | ||
| 394 | LOG_ERROR(Frontend, "No widget was created for \"{}\"", setting->GetLabel()); | ||
| 395 | return {nullptr, nullptr, nullptr}; | ||
| 396 | } | ||
| 397 | |||
| 398 | apply_funcs.push_front([load_func, setting](bool powered_on) { | ||
| 399 | if (setting->RuntimeModfiable() || !powered_on) { | ||
| 400 | load_func(); | ||
| 401 | } | ||
| 402 | }); | ||
| 403 | |||
| 404 | bool enable = runtime_lock || setting->RuntimeModfiable(); | ||
| 405 | if (setting->Switchable() && Settings::IsConfiguringGlobal() && !runtime_lock) { | ||
| 406 | enable &= !setting->UsingGlobal(); | ||
| 407 | } | ||
| 408 | widget->setEnabled(enable); | ||
| 409 | |||
| 410 | widget->setVisible(Settings::IsConfiguringGlobal() || setting->Switchable()); | ||
| 411 | |||
| 412 | widget->setToolTip(tooltip); | ||
| 413 | |||
| 414 | return {widget, extra, button}; | ||
| 415 | } | ||
| 416 | |||
| 417 | Tab::Tab(std::shared_ptr<std::forward_list<Tab*>> group_, QWidget* parent) | 31 | Tab::Tab(std::shared_ptr<std::forward_list<Tab*>> group_, QWidget* parent) |
| 418 | : QWidget(parent), group{group_} { | 32 | : QWidget(parent), group{group_} { |
| 419 | if (group != nullptr) { | 33 | if (group != nullptr) { |
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h index ef3b7c9a9..0a0a92ae5 100644 --- a/src/yuzu/configuration/configuration_shared.h +++ b/src/yuzu/configuration/configuration_shared.h | |||
| @@ -13,8 +13,6 @@ | |||
| 13 | #include "common/settings.h" | 13 | #include "common/settings.h" |
| 14 | #include "yuzu/configuration/shared_translation.h" | 14 | #include "yuzu/configuration/shared_translation.h" |
| 15 | 15 | ||
| 16 | class QPushButton; | ||
| 17 | |||
| 18 | namespace ConfigurationShared { | 16 | namespace ConfigurationShared { |
| 19 | 17 | ||
| 20 | class Tab : public QWidget { | 18 | class Tab : public QWidget { |
| @@ -43,22 +41,6 @@ enum class CheckState { | |||
| 43 | Count, // Simply the number of states, not a valid checkbox state | 41 | Count, // Simply the number of states, not a valid checkbox state |
| 44 | }; | 42 | }; |
| 45 | 43 | ||
| 46 | enum class RequestType { | ||
| 47 | Default, | ||
| 48 | ComboBox, | ||
| 49 | SpinBox, | ||
| 50 | Slider, | ||
| 51 | ReverseSlider, | ||
| 52 | LineEdit, | ||
| 53 | MaxEnum, | ||
| 54 | }; | ||
| 55 | |||
| 56 | std::tuple<QWidget*, void*, QPushButton*> CreateWidget( | ||
| 57 | Settings::BasicSetting* setting, const TranslationMap& translations, QWidget* parent, | ||
| 58 | bool runtime_lock, std::forward_list<std::function<void(bool)>>& apply_funcs, | ||
| 59 | RequestType request = RequestType::Default, bool managed = true, float multiplier = 1.0f, | ||
| 60 | const std::string& text_box_default = ""); | ||
| 61 | |||
| 62 | // Global-aware apply and set functions | 44 | // Global-aware apply and set functions |
| 63 | 45 | ||
| 64 | // ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting | 46 | // ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting |
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 8c6fee2a5..764ff68b3 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp | |||
| @@ -21,10 +21,10 @@ ConfigureGeneral::ConfigureGeneral( | |||
| 21 | 21 | ||
| 22 | SetConfiguration(); | 22 | SetConfiguration(); |
| 23 | 23 | ||
| 24 | if (Settings::IsConfiguringGlobal()) { | 24 | // if (Settings::IsConfiguringGlobal()) { |
| 25 | connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, | 25 | // connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, |
| 26 | [this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked()); }); | 26 | // [this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked()); }); |
| 27 | } | 27 | // } |
| 28 | 28 | ||
| 29 | connect(ui->button_reset_defaults, &QPushButton::clicked, this, | 29 | connect(ui->button_reset_defaults, &QPushButton::clicked, this, |
| 30 | &ConfigureGeneral::ResetDefaults); | 30 | &ConfigureGeneral::ResetDefaults); |
| @@ -46,17 +46,17 @@ void ConfigureGeneral::SetConfiguration() { | |||
| 46 | ui->toggle_controller_applet_disabled->setChecked( | 46 | ui->toggle_controller_applet_disabled->setChecked( |
| 47 | UISettings::values.controller_applet_disabled.GetValue()); | 47 | UISettings::values.controller_applet_disabled.GetValue()); |
| 48 | 48 | ||
| 49 | ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); | 49 | // ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); |
| 50 | ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); | 50 | // ui->speed_limit->setValue(Settings::values.speed_limit.GetValue()); |
| 51 | 51 | ||
| 52 | ui->button_reset_defaults->setEnabled(runtime_lock); | 52 | ui->button_reset_defaults->setEnabled(runtime_lock); |
| 53 | 53 | ||
| 54 | if (Settings::IsConfiguringGlobal()) { | 54 | // if (Settings::IsConfiguringGlobal()) { |
| 55 | ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue()); | 55 | // ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue()); |
| 56 | } else { | 56 | // } else { |
| 57 | ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() && | 57 | // ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() && |
| 58 | use_speed_limit != ConfigurationShared::CheckState::Global); | 58 | // use_speed_limit != ConfigurationShared::CheckState::Global); |
| 59 | } | 59 | // } |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | // Called to set the callback when resetting settings to defaults | 62 | // Called to set the callback when resetting settings to defaults |
| @@ -91,20 +91,20 @@ void ConfigureGeneral::ApplyConfiguration() { | |||
| 91 | ui->toggle_controller_applet_disabled->isChecked(); | 91 | ui->toggle_controller_applet_disabled->isChecked(); |
| 92 | 92 | ||
| 93 | // Guard if during game and set to game-specific value | 93 | // Guard if during game and set to game-specific value |
| 94 | if (Settings::values.use_speed_limit.UsingGlobal()) { | 94 | // if (Settings::values.use_speed_limit.UsingGlobal()) { |
| 95 | Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == | 95 | // Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == |
| 96 | Qt::Checked); | 96 | // Qt::Checked); |
| 97 | Settings::values.speed_limit.SetValue(ui->speed_limit->value()); | 97 | // Settings::values.speed_limit.SetValue(ui->speed_limit->value()); |
| 98 | } | 98 | // } |
| 99 | } else { | 99 | } else { |
| 100 | bool global_speed_limit = use_speed_limit == ConfigurationShared::CheckState::Global; | 100 | // bool global_speed_limit = use_speed_limit == ConfigurationShared::CheckState::Global; |
| 101 | Settings::values.use_speed_limit.SetGlobal(global_speed_limit); | 101 | // Settings::values.use_speed_limit.SetGlobal(global_speed_limit); |
| 102 | Settings::values.speed_limit.SetGlobal(global_speed_limit); | 102 | // Settings::values.speed_limit.SetGlobal(global_speed_limit); |
| 103 | if (!global_speed_limit) { | 103 | // if (!global_speed_limit) { |
| 104 | Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == | 104 | // Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() == |
| 105 | Qt::Checked); | 105 | // Qt::Checked); |
| 106 | Settings::values.speed_limit.SetValue(ui->speed_limit->value()); | 106 | // Settings::values.speed_limit.SetValue(ui->speed_limit->value()); |
| 107 | } | 107 | // } |
| 108 | } | 108 | } |
| 109 | } | 109 | } |
| 110 | 110 | ||
| @@ -125,8 +125,8 @@ void ConfigureGeneral::SetupPerGameUI() { | |||
| 125 | // Disables each setting if: | 125 | // Disables each setting if: |
| 126 | // - A game is running (thus settings in use), and | 126 | // - A game is running (thus settings in use), and |
| 127 | // - A non-global setting is applied. | 127 | // - A non-global setting is applied. |
| 128 | ui->toggle_speed_limit->setEnabled(Settings::values.use_speed_limit.UsingGlobal()); | 128 | // ui->toggle_speed_limit->setEnabled(Settings::values.use_speed_limit.UsingGlobal()); |
| 129 | ui->speed_limit->setEnabled(Settings::values.speed_limit.UsingGlobal()); | 129 | // ui->speed_limit->setEnabled(Settings::values.speed_limit.UsingGlobal()); |
| 130 | 130 | ||
| 131 | return; | 131 | return; |
| 132 | } | 132 | } |
| @@ -144,8 +144,9 @@ void ConfigureGeneral::SetupPerGameUI() { | |||
| 144 | ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, | 144 | ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, |
| 145 | use_multi_core); | 145 | use_multi_core); |
| 146 | 146 | ||
| 147 | connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() { | 147 | // connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() { |
| 148 | ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && | 148 | // ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && |
| 149 | (use_speed_limit != ConfigurationShared::CheckState::Global)); | 149 | // (use_speed_limit != |
| 150 | }); | 150 | // ConfigurationShared::CheckState::Global)); |
| 151 | // }); | ||
| 151 | } | 152 | } |
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index d3ca7e8cc..093e33625 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <QComboBox> | 15 | #include <QComboBox> |
| 16 | #include <QIcon> | 16 | #include <QIcon> |
| 17 | #include <QLabel> | 17 | #include <QLabel> |
| 18 | #include <QLineEdit> | ||
| 18 | #include <QPixmap> | 19 | #include <QPixmap> |
| 19 | #include <QPushButton> | 20 | #include <QPushButton> |
| 20 | #include <QSlider> | 21 | #include <QSlider> |
| @@ -35,6 +36,7 @@ | |||
| 35 | #include "ui_configure_graphics.h" | 36 | #include "ui_configure_graphics.h" |
| 36 | #include "yuzu/configuration/configuration_shared.h" | 37 | #include "yuzu/configuration/configuration_shared.h" |
| 37 | #include "yuzu/configuration/configure_graphics.h" | 38 | #include "yuzu/configuration/configure_graphics.h" |
| 39 | #include "yuzu/configuration/shared_widget.h" | ||
| 38 | #include "yuzu/qt_common.h" | 40 | #include "yuzu/qt_common.h" |
| 39 | #include "yuzu/uisettings.h" | 41 | #include "yuzu/uisettings.h" |
| 40 | #include "yuzu/vk_device_info.h" | 42 | #include "yuzu/vk_device_info.h" |
| @@ -219,35 +221,38 @@ void ConfigureGraphics::SetConfiguration() { | |||
| 219 | for (const auto setting : Settings::values.linkage.by_category[Settings::Category::Renderer]) { | 221 | for (const auto setting : Settings::values.linkage.by_category[Settings::Category::Renderer]) { |
| 220 | const auto& setting_label = setting->GetLabel(); | 222 | const auto& setting_label = setting->GetLabel(); |
| 221 | 223 | ||
| 222 | auto [widget, extra, button] = [&]() { | 224 | ConfigurationShared::Widget* widget = [&]() { |
| 223 | if (setting->Id() == Settings::values.vulkan_device.Id() || | 225 | if (setting->Id() == Settings::values.vulkan_device.Id() || |
| 224 | setting->Id() == Settings::values.shader_backend.Id() || | 226 | setting->Id() == Settings::values.shader_backend.Id() || |
| 225 | setting->Id() == Settings::values.vsync_mode.Id()) { | 227 | setting->Id() == Settings::values.vsync_mode.Id()) { |
| 226 | return ConfigurationShared::CreateWidget( | 228 | return new ConfigurationShared::Widget( |
| 227 | setting, translations, this, runtime_lock, apply_funcs, | 229 | setting, translations, this, runtime_lock, apply_funcs, |
| 228 | ConfigurationShared::RequestType::ComboBox, false); | 230 | ConfigurationShared::RequestType::ComboBox, false); |
| 229 | } else if (setting->Id() == Settings::values.fsr_sharpening_slider.Id()) { | 231 | } else if (setting->Id() == Settings::values.fsr_sharpening_slider.Id()) { |
| 230 | return ConfigurationShared::CreateWidget( | 232 | return new ConfigurationShared::Widget( |
| 231 | setting, translations, this, runtime_lock, apply_funcs, | 233 | setting, translations, this, runtime_lock, apply_funcs, |
| 232 | ConfigurationShared::RequestType::ReverseSlider, true, 0.5f); | 234 | ConfigurationShared::RequestType::ReverseSlider, true, 0.5f); |
| 233 | } else if (setting->Id() == Settings::values.use_speed_limit.Id()) { | 235 | } else if (setting->Id() == Settings::values.use_speed_limit.Id()) { |
| 234 | return ConfigurationShared::CreateWidget( | 236 | return new ConfigurationShared::Widget( |
| 235 | setting, translations, this, runtime_lock, apply_funcs, | 237 | setting, translations, this, runtime_lock, apply_funcs, |
| 236 | ConfigurationShared::RequestType::LineEdit, true, 1.0f, setting->ToString()); | 238 | ConfigurationShared::RequestType::LineEdit, true, 1.0f, |
| 239 | Settings::values.speed_limit.ToString()); | ||
| 237 | } else { | 240 | } else { |
| 238 | return ConfigurationShared::CreateWidget(setting, translations, this, runtime_lock, | 241 | return new ConfigurationShared::Widget(setting, translations, this, runtime_lock, |
| 239 | apply_funcs); | 242 | apply_funcs); |
| 240 | } | 243 | } |
| 241 | }(); | 244 | }(); |
| 242 | 245 | ||
| 243 | if (widget == nullptr) { | 246 | if (!widget->Valid()) { |
| 247 | LOG_DEBUG(Frontend, "Deleted widget for \"{}\"", setting->GetLabel()); | ||
| 248 | delete widget; | ||
| 244 | continue; | 249 | continue; |
| 245 | } | 250 | } |
| 246 | 251 | ||
| 247 | if (setting->Id() == Settings::values.renderer_backend.Id()) { | 252 | if (setting->Id() == Settings::values.renderer_backend.Id()) { |
| 248 | api_grid_layout->addWidget(widget); | 253 | api_grid_layout->addWidget(widget); |
| 249 | api_combobox = reinterpret_cast<QComboBox*>(extra); | 254 | api_combobox = widget->combobox; |
| 250 | api_restore_global_button = button; | 255 | api_restore_global_button = widget->restore_button; |
| 251 | 256 | ||
| 252 | if (!Settings::IsConfiguringGlobal()) { | 257 | if (!Settings::IsConfiguringGlobal()) { |
| 253 | QObject::connect(api_restore_global_button, &QAbstractButton::clicked, | 258 | QObject::connect(api_restore_global_button, &QAbstractButton::clicked, |
| @@ -259,14 +264,33 @@ void ConfigureGraphics::SetConfiguration() { | |||
| 259 | } | 264 | } |
| 260 | } else if (setting->Id() == Settings::values.vulkan_device.Id()) { | 265 | } else if (setting->Id() == Settings::values.vulkan_device.Id()) { |
| 261 | hold_api.push_front(widget); | 266 | hold_api.push_front(widget); |
| 262 | vulkan_device_combobox = reinterpret_cast<QComboBox*>(extra); | 267 | vulkan_device_combobox = widget->combobox; |
| 263 | vulkan_device_widget = widget; | 268 | vulkan_device_widget = widget; |
| 264 | } else if (setting->Id() == Settings::values.shader_backend.Id()) { | 269 | } else if (setting->Id() == Settings::values.shader_backend.Id()) { |
| 265 | hold_api.push_front(widget); | 270 | hold_api.push_front(widget); |
| 266 | shader_backend_combobox = reinterpret_cast<QComboBox*>(extra); | 271 | shader_backend_combobox = widget->combobox; |
| 267 | shader_backend_widget = widget; | 272 | shader_backend_widget = widget; |
| 273 | } else if (setting->Id() == Settings::values.use_speed_limit.Id()) { | ||
| 274 | apply_funcs.push_front([setting, widget](bool powered_on) { | ||
| 275 | if (!setting->RuntimeModfiable() && powered_on) { | ||
| 276 | return; | ||
| 277 | } | ||
| 278 | |||
| 279 | u16 value = QVariant(widget->line_edit->text()).value<u16>(); | ||
| 280 | auto& speed_limit = Settings::values.speed_limit; | ||
| 281 | if (Settings::IsConfiguringGlobal()) { | ||
| 282 | speed_limit.SetValue(value); | ||
| 283 | } else { | ||
| 284 | bool using_global = !widget->restore_button->isVisible(); | ||
| 285 | speed_limit.SetGlobal(using_global); | ||
| 286 | if (!using_global) { | ||
| 287 | speed_limit.SetValue(value); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | }); | ||
| 291 | hold_graphics[setting->IsEnum()][setting_label] = widget; | ||
| 268 | } else if (setting->Id() == Settings::values.vsync_mode.Id()) { | 292 | } else if (setting->Id() == Settings::values.vsync_mode.Id()) { |
| 269 | vsync_mode_combobox = reinterpret_cast<QComboBox*>(extra); | 293 | vsync_mode_combobox = widget->combobox; |
| 270 | hold_graphics[setting->IsEnum()][setting_label] = widget; | 294 | hold_graphics[setting->IsEnum()][setting_label] = widget; |
| 271 | } else { | 295 | } else { |
| 272 | hold_graphics[setting->IsEnum()][setting_label] = widget; | 296 | hold_graphics[setting->IsEnum()][setting_label] = widget; |
| @@ -360,6 +384,7 @@ void ConfigureGraphics::UpdateBackgroundColorButton(QColor color) { | |||
| 360 | } | 384 | } |
| 361 | 385 | ||
| 362 | void ConfigureGraphics::UpdateAPILayout() { | 386 | void ConfigureGraphics::UpdateAPILayout() { |
| 387 | bool runtime_lock = !system.IsPoweredOn(); | ||
| 363 | if (!Settings::IsConfiguringGlobal() && !api_restore_global_button->isEnabled()) { | 388 | if (!Settings::IsConfiguringGlobal() && !api_restore_global_button->isEnabled()) { |
| 364 | vulkan_device = Settings::values.vulkan_device.GetValue(true); | 389 | vulkan_device = Settings::values.vulkan_device.GetValue(true); |
| 365 | shader_backend = Settings::values.shader_backend.GetValue(true); | 390 | shader_backend = Settings::values.shader_backend.GetValue(true); |
| @@ -368,8 +393,8 @@ void ConfigureGraphics::UpdateAPILayout() { | |||
| 368 | } else { | 393 | } else { |
| 369 | vulkan_device = Settings::values.vulkan_device.GetValue(); | 394 | vulkan_device = Settings::values.vulkan_device.GetValue(); |
| 370 | shader_backend = Settings::values.shader_backend.GetValue(); | 395 | shader_backend = Settings::values.shader_backend.GetValue(); |
| 371 | vulkan_device_widget->setEnabled(true); | 396 | vulkan_device_widget->setEnabled(runtime_lock); |
| 372 | shader_backend_widget->setEnabled(true); | 397 | shader_backend_widget->setEnabled(runtime_lock); |
| 373 | } | 398 | } |
| 374 | 399 | ||
| 375 | switch (GetCurrentGraphicsBackend()) { | 400 | switch (GetCurrentGraphicsBackend()) { |
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index a049458a8..4ef551341 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "vk_device_info.h" | 15 | #include "vk_device_info.h" |
| 16 | #include "yuzu/configuration/configuration_shared.h" | 16 | #include "yuzu/configuration/configuration_shared.h" |
| 17 | 17 | ||
| 18 | class QPushButton; | ||
| 18 | class QEvent; | 19 | class QEvent; |
| 19 | class QObject; | 20 | class QObject; |
| 20 | class QComboBox; | 21 | class QComboBox; |
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 4a3868693..4f57a7ae6 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "ui_configure_graphics_advanced.h" | 8 | #include "ui_configure_graphics_advanced.h" |
| 9 | #include "yuzu/configuration/configuration_shared.h" | 9 | #include "yuzu/configuration/configuration_shared.h" |
| 10 | #include "yuzu/configuration/configure_graphics_advanced.h" | 10 | #include "yuzu/configuration/configure_graphics_advanced.h" |
| 11 | #include "yuzu/configuration/shared_widget.h" | ||
| 11 | 12 | ||
| 12 | ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced( | 13 | ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced( |
| 13 | const Core::System& system_, | 14 | const Core::System& system_, |
| @@ -32,10 +33,11 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { | |||
| 32 | 33 | ||
| 33 | for (auto setting : | 34 | for (auto setting : |
| 34 | Settings::values.linkage.by_category[Settings::Category::RendererAdvanced]) { | 35 | Settings::values.linkage.by_category[Settings::Category::RendererAdvanced]) { |
| 35 | auto [widget, extra, button] = ConfigurationShared::CreateWidget( | 36 | ConfigurationShared::Widget* widget = |
| 36 | setting, translations, this, runtime_lock, apply_funcs); | 37 | new ConfigurationShared::Widget(setting, translations, this, runtime_lock, apply_funcs); |
| 37 | 38 | ||
| 38 | if (widget == nullptr) { | 39 | if (!widget->Valid()) { |
| 40 | delete widget; | ||
| 39 | continue; | 41 | continue; |
| 40 | } | 42 | } |
| 41 | 43 | ||
diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp new file mode 100644 index 000000000..0676973a9 --- /dev/null +++ b/src/yuzu/configuration/shared_widget.cpp | |||
| @@ -0,0 +1,360 @@ | |||
| 1 | #include <functional> | ||
| 2 | #include <QCheckBox> | ||
| 3 | #include <QHBoxLayout> | ||
| 4 | #include <QIcon> | ||
| 5 | #include <QLabel> | ||
| 6 | #include <QLineEdit> | ||
| 7 | #include <QPushButton> | ||
| 8 | #include <QSizePolicy> | ||
| 9 | #include <QWidget> | ||
| 10 | #include <qabstractbutton.h> | ||
| 11 | #include "common/settings.h" | ||
| 12 | #include "yuzu/configuration/shared_translation.h" | ||
| 13 | #include "yuzu/configuration/shared_widget.h" | ||
| 14 | |||
| 15 | namespace ConfigurationShared { | ||
| 16 | |||
| 17 | void Widget::CreateRestoreGlobalButton() { | ||
| 18 | QStyle* style = this->style(); | ||
| 19 | QIcon* icon = new QIcon(style->standardIcon(QStyle::SP_DialogResetButton)); | ||
| 20 | restore_button = new QPushButton(*icon, QStringLiteral(""), this); | ||
| 21 | restore_button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); | ||
| 22 | |||
| 23 | QSizePolicy sp_retain = restore_button->sizePolicy(); | ||
| 24 | sp_retain.setRetainSizeWhenHidden(true); | ||
| 25 | restore_button->setSizePolicy(sp_retain); | ||
| 26 | |||
| 27 | restore_button->setEnabled(!setting.UsingGlobal()); | ||
| 28 | restore_button->setVisible(!setting.UsingGlobal()); | ||
| 29 | } | ||
| 30 | |||
| 31 | void Widget::CreateCheckBox(const QString& label, std::function<void()>& load_func) { | ||
| 32 | created = true; | ||
| 33 | |||
| 34 | QHBoxLayout* layout = new QHBoxLayout(this); | ||
| 35 | |||
| 36 | checkbox = new QCheckBox(label, this); | ||
| 37 | checkbox->setObjectName(QString::fromStdString(setting.GetLabel())); | ||
| 38 | checkbox->setCheckState(setting.ToString() == "true" ? Qt::CheckState::Checked | ||
| 39 | : Qt::CheckState::Unchecked); | ||
| 40 | |||
| 41 | layout->addWidget(checkbox); | ||
| 42 | if (Settings::IsConfiguringGlobal()) { | ||
| 43 | load_func = [=]() { | ||
| 44 | setting.LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); | ||
| 45 | }; | ||
| 46 | } else { | ||
| 47 | CreateRestoreGlobalButton(); | ||
| 48 | layout->addWidget(restore_button); | ||
| 49 | |||
| 50 | QObject::connect(checkbox, &QCheckBox::stateChanged, [&](int) { | ||
| 51 | restore_button->setVisible(true); | ||
| 52 | restore_button->setEnabled(true); | ||
| 53 | }); | ||
| 54 | |||
| 55 | QObject::connect(restore_button, &QAbstractButton::clicked, [&](bool) { | ||
| 56 | checkbox->setCheckState(setting.ToStringGlobal() == "true" ? Qt::Checked | ||
| 57 | : Qt::Unchecked); | ||
| 58 | restore_button->setEnabled(false); | ||
| 59 | restore_button->setVisible(false); | ||
| 60 | }); | ||
| 61 | |||
| 62 | load_func = [=]() { | ||
| 63 | bool using_global = !restore_button->isEnabled(); | ||
| 64 | setting.SetGlobal(using_global); | ||
| 65 | if (!using_global) { | ||
| 66 | setting.LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); | ||
| 67 | } | ||
| 68 | }; | ||
| 69 | } | ||
| 70 | |||
| 71 | layout->setContentsMargins(0, 0, 0, 0); | ||
| 72 | } | ||
| 73 | |||
| 74 | void Widget::CreateCombobox(const QString& label, bool managed, std::function<void()>& load_func) { | ||
| 75 | created = true; | ||
| 76 | |||
| 77 | const auto type = setting.TypeId(); | ||
| 78 | |||
| 79 | QLayout* layout = new QHBoxLayout(this); | ||
| 80 | |||
| 81 | QLabel* qt_label = new QLabel(label, this); | ||
| 82 | combobox = new QComboBox(this); | ||
| 83 | |||
| 84 | std::forward_list<QString> combobox_enumerations = ComboboxEnumeration(type, this); | ||
| 85 | for (const auto& item : combobox_enumerations) { | ||
| 86 | combobox->addItem(item); | ||
| 87 | } | ||
| 88 | |||
| 89 | layout->addWidget(qt_label); | ||
| 90 | layout->addWidget(combobox); | ||
| 91 | |||
| 92 | layout->setSpacing(6); | ||
| 93 | layout->setContentsMargins(0, 0, 0, 0); | ||
| 94 | |||
| 95 | combobox->setCurrentIndex(std::stoi(setting.ToString())); | ||
| 96 | |||
| 97 | if (Settings::IsConfiguringGlobal() && managed) { | ||
| 98 | load_func = [=]() { setting.LoadString(std::to_string(combobox->currentIndex())); }; | ||
| 99 | } else if (managed) { | ||
| 100 | CreateRestoreGlobalButton(); | ||
| 101 | layout->addWidget(restore_button); | ||
| 102 | |||
| 103 | QObject::connect(restore_button, &QAbstractButton::clicked, [&](bool) { | ||
| 104 | restore_button->setEnabled(false); | ||
| 105 | restore_button->setVisible(false); | ||
| 106 | |||
| 107 | combobox->setCurrentIndex(std::stoi(setting.ToStringGlobal())); | ||
| 108 | }); | ||
| 109 | |||
| 110 | QObject::connect(combobox, QOverload<int>::of(&QComboBox::activated), [=](int) { | ||
| 111 | restore_button->setEnabled(true); | ||
| 112 | restore_button->setVisible(true); | ||
| 113 | }); | ||
| 114 | |||
| 115 | load_func = [=]() { | ||
| 116 | bool using_global = !restore_button->isEnabled(); | ||
| 117 | setting.SetGlobal(using_global); | ||
| 118 | if (!using_global) { | ||
| 119 | setting.LoadString(std::to_string(combobox->currentIndex())); | ||
| 120 | } | ||
| 121 | }; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | void Widget::CreateLineEdit(const QString& label, bool managed, std::function<void()>& load_func) { | ||
| 126 | created = true; | ||
| 127 | |||
| 128 | QHBoxLayout* layout = new QHBoxLayout(this); | ||
| 129 | line_edit = new QLineEdit(this); | ||
| 130 | |||
| 131 | const QString text = QString::fromStdString(setting.ToString()); | ||
| 132 | line_edit->setText(text); | ||
| 133 | |||
| 134 | QLabel* q_label = new QLabel(label, this); | ||
| 135 | // setSizePolicy lets widget expand and take an equal part of the space as the line edit | ||
| 136 | q_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); | ||
| 137 | layout->addWidget(q_label); | ||
| 138 | |||
| 139 | layout->addWidget(line_edit); | ||
| 140 | |||
| 141 | if (Settings::IsConfiguringGlobal() && !managed) { | ||
| 142 | load_func = [=]() { | ||
| 143 | std::string load_text = line_edit->text().toStdString(); | ||
| 144 | setting.LoadString(load_text); | ||
| 145 | }; | ||
| 146 | } else if (!managed) { | ||
| 147 | CreateRestoreGlobalButton(); | ||
| 148 | layout->addWidget(restore_button); | ||
| 149 | |||
| 150 | QObject::connect(restore_button, &QAbstractButton::clicked, [&](bool) { | ||
| 151 | restore_button->setEnabled(false); | ||
| 152 | restore_button->setVisible(false); | ||
| 153 | |||
| 154 | line_edit->setText(QString::fromStdString(setting.ToStringGlobal())); | ||
| 155 | }); | ||
| 156 | |||
| 157 | QObject::connect(line_edit, &QLineEdit::textChanged, [&](QString) { | ||
| 158 | restore_button->setEnabled(true); | ||
| 159 | restore_button->setVisible(true); | ||
| 160 | }); | ||
| 161 | |||
| 162 | load_func = [=]() { | ||
| 163 | bool using_global = !restore_button->isEnabled(); | ||
| 164 | setting.SetGlobal(using_global); | ||
| 165 | if (!using_global) { | ||
| 166 | setting.LoadString(line_edit->text().toStdString()); | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | } | ||
| 170 | |||
| 171 | layout->setContentsMargins(0, 0, 0, 0); | ||
| 172 | } | ||
| 173 | |||
| 174 | void Widget::CreateSlider(const QString& name, bool reversed, float multiplier, | ||
| 175 | std::function<void()>& load_func) { | ||
| 176 | created = true; | ||
| 177 | |||
| 178 | QHBoxLayout* layout = new QHBoxLayout(this); | ||
| 179 | slider = new QSlider(Qt::Horizontal, this); | ||
| 180 | QLabel* label = new QLabel(name, this); | ||
| 181 | QLabel* feedback = new QLabel(this); | ||
| 182 | |||
| 183 | layout->addWidget(label); | ||
| 184 | layout->addWidget(slider); | ||
| 185 | layout->addWidget(feedback); | ||
| 186 | |||
| 187 | label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); | ||
| 188 | |||
| 189 | layout->setContentsMargins(0, 0, 0, 0); | ||
| 190 | |||
| 191 | int max_val = std::stoi(setting.MaxVal()); | ||
| 192 | |||
| 193 | QObject::connect(slider, &QAbstractSlider::valueChanged, [=](int value) { | ||
| 194 | int present = (reversed ? max_val - value : value) * multiplier; | ||
| 195 | feedback->setText( | ||
| 196 | QStringLiteral("%1%").arg(QString::fromStdString(std::to_string(present)))); | ||
| 197 | }); | ||
| 198 | |||
| 199 | slider->setValue(std::stoi(setting.ToString())); | ||
| 200 | slider->setMinimum(std::stoi(setting.MinVal())); | ||
| 201 | slider->setMaximum(max_val); | ||
| 202 | |||
| 203 | if (reversed) { | ||
| 204 | slider->setInvertedAppearance(true); | ||
| 205 | } | ||
| 206 | |||
| 207 | if (Settings::IsConfiguringGlobal()) { | ||
| 208 | load_func = [=]() { setting.LoadString(std::to_string(slider->value())); }; | ||
| 209 | } else { | ||
| 210 | CreateRestoreGlobalButton(); | ||
| 211 | layout->addWidget(restore_button); | ||
| 212 | |||
| 213 | QObject::connect(restore_button, &QAbstractButton::clicked, [=](bool) { | ||
| 214 | slider->setValue(std::stoi(setting.ToStringGlobal())); | ||
| 215 | |||
| 216 | restore_button->setEnabled(false); | ||
| 217 | restore_button->setVisible(false); | ||
| 218 | }); | ||
| 219 | |||
| 220 | QObject::connect(slider, &QAbstractSlider::sliderMoved, [=](int) { | ||
| 221 | restore_button->setEnabled(true); | ||
| 222 | restore_button->setVisible(true); | ||
| 223 | }); | ||
| 224 | |||
| 225 | load_func = [=]() { | ||
| 226 | bool using_global = !restore_button->isEnabled(); | ||
| 227 | setting.SetGlobal(using_global); | ||
| 228 | if (!using_global) { | ||
| 229 | setting.LoadString(std::to_string(slider->value())); | ||
| 230 | } | ||
| 231 | }; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | void Widget::CreateCheckBoxWithLineEdit(const QString& label, const std::string& text_box_default, | ||
| 236 | std::function<void()>& load_func) { | ||
| 237 | created = true; | ||
| 238 | |||
| 239 | CreateCheckBox(label, load_func); | ||
| 240 | |||
| 241 | QHBoxLayout* layout = reinterpret_cast<QHBoxLayout*>(this->layout()); | ||
| 242 | |||
| 243 | line_edit = new QLineEdit(this); | ||
| 244 | line_edit->setText(QString::fromStdString(text_box_default)); | ||
| 245 | |||
| 246 | checkbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); | ||
| 247 | |||
| 248 | layout->insertWidget(1, line_edit); | ||
| 249 | |||
| 250 | QObject::connect(line_edit, &QLineEdit::textEdited, | ||
| 251 | [=](const QString&) { checkbox->setCheckState(Qt::Checked); }); | ||
| 252 | |||
| 253 | if (!Settings::IsConfiguringGlobal()) { | ||
| 254 | QObject::connect(restore_button, &QAbstractButton::clicked, [=](bool) { | ||
| 255 | line_edit->setText(QString::fromStdString(text_box_default)); | ||
| 256 | }); | ||
| 257 | |||
| 258 | QObject::connect(line_edit, &QLineEdit::textEdited, [=](const QString&) { | ||
| 259 | restore_button->setEnabled(true); | ||
| 260 | restore_button->setVisible(true); | ||
| 261 | }); | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | bool Widget::Valid() { | ||
| 266 | return created; | ||
| 267 | } | ||
| 268 | |||
| 269 | Widget::~Widget() = default; | ||
| 270 | |||
| 271 | Widget::Widget(Settings::BasicSetting* setting_, const TranslationMap& translations_, | ||
| 272 | QWidget* parent_, bool runtime_lock, | ||
| 273 | std::forward_list<std::function<void(bool)>>& apply_funcs, RequestType request, | ||
| 274 | bool managed, float multiplier, const std::string& text_box_default) | ||
| 275 | : QWidget(parent_), parent{parent_}, translations{translations_}, setting{*setting_} { | ||
| 276 | if (!Settings::IsConfiguringGlobal() && !setting.Switchable()) { | ||
| 277 | LOG_DEBUG(Frontend, "\"{}\" is not switchable, skipping...", setting.GetLabel()); | ||
| 278 | return; | ||
| 279 | } | ||
| 280 | |||
| 281 | const auto type = setting.TypeId(); | ||
| 282 | const int id = setting.Id(); | ||
| 283 | |||
| 284 | const auto [label, tooltip] = [&]() { | ||
| 285 | const auto& setting_label = setting.GetLabel(); | ||
| 286 | if (translations.contains(id)) { | ||
| 287 | return std::pair{translations.at(id).first, translations.at(id).second}; | ||
| 288 | } | ||
| 289 | LOG_WARNING(Frontend, "Translation table lacks entry for \"{}\"", setting_label); | ||
| 290 | return std::pair{QString::fromStdString(setting_label), QStringLiteral("")}; | ||
| 291 | }(); | ||
| 292 | |||
| 293 | if (label == QStringLiteral("")) { | ||
| 294 | LOG_DEBUG(Frontend, "Translation table has emtpy entry for \"{}\", skipping...", | ||
| 295 | setting.GetLabel()); | ||
| 296 | return; | ||
| 297 | } | ||
| 298 | |||
| 299 | std::function<void()> load_func = []() {}; | ||
| 300 | |||
| 301 | if (type == typeid(bool)) { | ||
| 302 | switch (request) { | ||
| 303 | case RequestType::Default: | ||
| 304 | CreateCheckBox(label, load_func); | ||
| 305 | break; | ||
| 306 | case RequestType::LineEdit: | ||
| 307 | case RequestType::SpinBox: | ||
| 308 | CreateCheckBoxWithLineEdit(label, text_box_default, load_func); | ||
| 309 | break; | ||
| 310 | case RequestType::ComboBox: | ||
| 311 | case RequestType::Slider: | ||
| 312 | case RequestType::ReverseSlider: | ||
| 313 | case RequestType::MaxEnum: | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | } else if (setting.IsEnum()) { | ||
| 317 | CreateCombobox(label, managed, load_func); | ||
| 318 | } else if (type == typeid(u32) || type == typeid(int)) { | ||
| 319 | switch (request) { | ||
| 320 | case RequestType::Slider: | ||
| 321 | case RequestType::ReverseSlider: | ||
| 322 | CreateSlider(label, request == RequestType::ReverseSlider, multiplier, load_func); | ||
| 323 | break; | ||
| 324 | case RequestType::LineEdit: | ||
| 325 | case RequestType::Default: | ||
| 326 | CreateLineEdit(label, managed, load_func); | ||
| 327 | break; | ||
| 328 | case RequestType::ComboBox: | ||
| 329 | CreateCombobox(label, managed, load_func); | ||
| 330 | break; | ||
| 331 | case RequestType::SpinBox: | ||
| 332 | case RequestType::MaxEnum: | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | if (!created) { | ||
| 338 | LOG_ERROR(Frontend, "No widget was created for \"{}\"", setting.GetLabel()); | ||
| 339 | return; | ||
| 340 | } | ||
| 341 | |||
| 342 | apply_funcs.push_front([load_func, setting_](bool powered_on) { | ||
| 343 | LOG_DEBUG(Frontend, "{}", setting_->GetLabel()); | ||
| 344 | if (setting_->RuntimeModfiable() || !powered_on) { | ||
| 345 | load_func(); | ||
| 346 | } | ||
| 347 | }); | ||
| 348 | |||
| 349 | bool enable = runtime_lock || setting.RuntimeModfiable(); | ||
| 350 | if (setting.Switchable() && Settings::IsConfiguringGlobal() && !runtime_lock) { | ||
| 351 | enable &= setting.UsingGlobal(); | ||
| 352 | } | ||
| 353 | this->setEnabled(enable); | ||
| 354 | |||
| 355 | this->setVisible(Settings::IsConfiguringGlobal() || setting.Switchable()); | ||
| 356 | |||
| 357 | this->setToolTip(tooltip); | ||
| 358 | } | ||
| 359 | |||
| 360 | } // namespace ConfigurationShared | ||
diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h new file mode 100644 index 000000000..559a27b41 --- /dev/null +++ b/src/yuzu/configuration/shared_widget.h | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | #include "yuzu/configuration/configuration_shared.h" | ||
| 2 | #include "yuzu/configuration/shared_translation.h" | ||
| 3 | |||
| 4 | class QPushButton; | ||
| 5 | class QComboBox; | ||
| 6 | class QLineEdit; | ||
| 7 | class QSlider; | ||
| 8 | class QCheckBox; | ||
| 9 | |||
| 10 | namespace Settings { | ||
| 11 | class BasicSetting; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace ConfigurationShared { | ||
| 15 | |||
| 16 | enum class RequestType { | ||
| 17 | Default, | ||
| 18 | ComboBox, | ||
| 19 | SpinBox, | ||
| 20 | Slider, | ||
| 21 | ReverseSlider, | ||
| 22 | LineEdit, | ||
| 23 | MaxEnum, | ||
| 24 | }; | ||
| 25 | |||
| 26 | class Widget : public QWidget { | ||
| 27 | Q_OBJECT | ||
| 28 | |||
| 29 | public: | ||
| 30 | Widget(Settings::BasicSetting* setting, const TranslationMap& translations, QWidget* parent, | ||
| 31 | bool runtime_lock, std::forward_list<std::function<void(bool)>>& apply_funcs, | ||
| 32 | RequestType request = RequestType::Default, bool managed = true, float multiplier = 1.0f, | ||
| 33 | const std::string& text_box_default = ""); | ||
| 34 | virtual ~Widget(); | ||
| 35 | |||
| 36 | bool Valid(); | ||
| 37 | |||
| 38 | QPushButton* restore_button{}; | ||
| 39 | QLineEdit* line_edit{}; | ||
| 40 | QCheckBox* checkbox{}; | ||
| 41 | QSlider* slider{}; | ||
| 42 | QComboBox* combobox{}; | ||
| 43 | |||
| 44 | private: | ||
| 45 | void CreateCheckBox(const QString& label, std::function<void()>& load_func); | ||
| 46 | void CreateCheckBoxWithLineEdit(const QString& label, const std::string& text_box_default, | ||
| 47 | std::function<void()>& load_func); | ||
| 48 | void CreateCheckBoxWithSpinBox(const QString& label, const std::string& text_box_default, | ||
| 49 | std::function<void()>& load_func); | ||
| 50 | void CreateCombobox(const QString& label, bool managed, std::function<void()>& load_func); | ||
| 51 | void CreateLineEdit(const QString& label, bool managed, std::function<void()>& load_func); | ||
| 52 | void CreateSlider(const QString& label, bool reversed, float multiplier, | ||
| 53 | std::function<void()>& load_func); | ||
| 54 | |||
| 55 | void CreateRestoreGlobalButton(); | ||
| 56 | |||
| 57 | QWidget* parent; | ||
| 58 | const TranslationMap& translations; | ||
| 59 | Settings::BasicSetting& setting; | ||
| 60 | |||
| 61 | bool created{false}; | ||
| 62 | }; | ||
| 63 | |||
| 64 | } // namespace ConfigurationShared | ||