controllersettingswindow.cpp (22313B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "controllersettingswindow.h" 5 #include "controllerbindingwidgets.h" 6 #include "controllerglobalsettingswidget.h" 7 #include "hotkeysettingswidget.h" 8 #include "qthost.h" 9 10 #include "core/controller.h" 11 #include "core/host.h" 12 13 #include "util/ini_settings_interface.h" 14 #include "util/input_manager.h" 15 16 #include "common/assert.h" 17 #include "common/file_system.h" 18 19 #include <QtWidgets/QInputDialog> 20 #include <QtWidgets/QMessageBox> 21 #include <QtWidgets/QTextEdit> 22 #include <array> 23 24 static constexpr const std::array<char, 4> s_mtap_slot_names = {{'A', 'B', 'C', 'D'}}; 25 26 ControllerSettingsWindow::ControllerSettingsWindow(SettingsInterface* game_sif /* = nullptr */, 27 QWidget* parent /* = nullptr */) 28 : QWidget(parent), m_editing_settings_interface(game_sif) 29 { 30 m_ui.setupUi(this); 31 32 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); 33 34 m_ui.settingsCategory->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); 35 36 connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, 37 &ControllerSettingsWindow::onCategoryCurrentRowChanged); 38 connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &ControllerSettingsWindow::close); 39 40 if (!game_sif) 41 { 42 refreshProfileList(); 43 44 m_ui.editProfileLayout->removeWidget(m_ui.copyGlobalSettings); 45 delete m_ui.copyGlobalSettings; 46 m_ui.copyGlobalSettings = nullptr; 47 48 connect(m_ui.currentProfile, &QComboBox::currentIndexChanged, this, 49 &ControllerSettingsWindow::onCurrentProfileChanged); 50 connect(m_ui.newProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onNewProfileClicked); 51 connect(m_ui.applyProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onApplyProfileClicked); 52 connect(m_ui.deleteProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onDeleteProfileClicked); 53 connect(m_ui.restoreDefaults, &QPushButton::clicked, this, &ControllerSettingsWindow::onRestoreDefaultsClicked); 54 55 connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this, 56 &ControllerSettingsWindow::onInputDevicesEnumerated); 57 connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &ControllerSettingsWindow::onInputDeviceConnected); 58 connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this, 59 &ControllerSettingsWindow::onInputDeviceDisconnected); 60 connect(g_emu_thread, &EmuThread::onVibrationMotorsEnumerated, this, 61 &ControllerSettingsWindow::onVibrationMotorsEnumerated); 62 63 // trigger a device enumeration to populate the device list 64 g_emu_thread->enumerateInputDevices(); 65 g_emu_thread->enumerateVibrationMotors(); 66 } 67 else 68 { 69 m_ui.editProfileLayout->removeWidget(m_ui.editProfileLabel); 70 delete m_ui.editProfileLabel; 71 m_ui.editProfileLabel = nullptr; 72 m_ui.editProfileLayout->removeWidget(m_ui.currentProfile); 73 delete m_ui.currentProfile; 74 m_ui.currentProfile = nullptr; 75 m_ui.editProfileLayout->removeWidget(m_ui.newProfile); 76 delete m_ui.newProfile; 77 m_ui.newProfile = nullptr; 78 m_ui.editProfileLayout->removeWidget(m_ui.applyProfile); 79 delete m_ui.applyProfile; 80 m_ui.applyProfile = nullptr; 81 m_ui.editProfileLayout->removeWidget(m_ui.deleteProfile); 82 delete m_ui.deleteProfile; 83 m_ui.deleteProfile = nullptr; 84 85 connect(m_ui.copyGlobalSettings, &QPushButton::clicked, this, 86 &ControllerSettingsWindow::onCopyGlobalSettingsClicked); 87 connect(m_ui.restoreDefaults, &QPushButton::clicked, this, 88 &ControllerSettingsWindow::onRestoreDefaultsForGameClicked); 89 } 90 91 createWidgets(); 92 } 93 94 ControllerSettingsWindow::~ControllerSettingsWindow() = default; 95 96 void ControllerSettingsWindow::editControllerSettingsForGame(QWidget* parent, SettingsInterface* sif) 97 { 98 ControllerSettingsWindow* dlg = new ControllerSettingsWindow(sif, parent); 99 dlg->setWindowFlag(Qt::Window); 100 dlg->setAttribute(Qt::WA_DeleteOnClose); 101 dlg->setWindowModality(Qt::WindowModality::WindowModal); 102 dlg->setWindowTitle(parent->windowTitle()); 103 dlg->setWindowIcon(parent->windowIcon()); 104 dlg->show(); 105 } 106 107 int ControllerSettingsWindow::getHotkeyCategoryIndex() const 108 { 109 const std::array<bool, 2> mtap_enabled = getEnabledMultitaps(); 110 return 1 + (mtap_enabled[0] ? 4 : 1) + (mtap_enabled[1] ? 4 : 1); 111 } 112 113 ControllerSettingsWindow::Category ControllerSettingsWindow::getCurrentCategory() const 114 { 115 const int index = m_ui.settingsCategory->currentRow(); 116 if (index == 0) 117 return Category::GlobalSettings; 118 else if (index >= getHotkeyCategoryIndex()) 119 return Category::HotkeySettings; 120 else 121 return Category::FirstControllerSettings; 122 } 123 124 void ControllerSettingsWindow::setCategory(Category category) 125 { 126 switch (category) 127 { 128 case Category::GlobalSettings: 129 m_ui.settingsCategory->setCurrentRow(0); 130 break; 131 132 case Category::FirstControllerSettings: 133 m_ui.settingsCategory->setCurrentRow(1); 134 break; 135 136 case Category::HotkeySettings: 137 m_ui.settingsCategory->setCurrentRow(getHotkeyCategoryIndex()); 138 break; 139 140 default: 141 break; 142 } 143 } 144 145 void ControllerSettingsWindow::onCategoryCurrentRowChanged(int row) 146 { 147 m_ui.settingsContainer->setCurrentIndex(row); 148 } 149 150 void ControllerSettingsWindow::onCurrentProfileChanged(int index) 151 { 152 std::string profile_name; 153 if (index > 0) 154 profile_name = m_ui.currentProfile->itemText(index).toStdString(); 155 156 switchProfile(profile_name); 157 } 158 159 void ControllerSettingsWindow::onNewProfileClicked() 160 { 161 const std::string profile_name = 162 QInputDialog::getText(this, tr("Create Input Profile"), tr("Enter the name for the new input profile:")) 163 .toStdString(); 164 if (profile_name.empty()) 165 return; 166 167 std::string profile_path = System::GetInputProfilePath(profile_name); 168 if (FileSystem::FileExists(profile_path.c_str())) 169 { 170 QMessageBox::critical(this, tr("Error"), 171 tr("A profile with the name '%1' already exists.").arg(QString::fromStdString(profile_name))); 172 return; 173 } 174 175 const int res = QMessageBox::question(this, tr("Create Input Profile"), 176 tr("Do you want to copy all bindings from the currently-selected profile to " 177 "the new profile? Selecting No will create a completely empty profile."), 178 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); 179 if (res == QMessageBox::Cancel) 180 return; 181 182 INISettingsInterface temp_si(std::move(profile_path)); 183 if (res == QMessageBox::Yes) 184 { 185 // copy from global or the current profile 186 if (!m_editing_settings_interface) 187 { 188 const int hkres = QMessageBox::question( 189 this, tr("Create Input Profile"), 190 tr("Do you want to copy the current hotkey bindings from global settings to the new input profile?"), 191 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); 192 if (hkres == QMessageBox::Cancel) 193 return; 194 195 const bool copy_hotkey_bindings = (hkres == QMessageBox::Yes); 196 if (copy_hotkey_bindings) 197 temp_si.SetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", true); 198 199 // from global 200 auto lock = Host::GetSettingsLock(); 201 InputManager::CopyConfiguration(&temp_si, *Host::Internal::GetBaseSettingsLayer(), true, true, 202 copy_hotkey_bindings); 203 } 204 else 205 { 206 // from profile 207 const bool copy_hotkey_bindings = 208 m_editing_settings_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false); 209 temp_si.SetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", copy_hotkey_bindings); 210 InputManager::CopyConfiguration(&temp_si, *m_editing_settings_interface, true, true, copy_hotkey_bindings); 211 } 212 } 213 214 if (!temp_si.Save()) 215 { 216 QMessageBox::critical( 217 this, tr("Error"), 218 tr("Failed to save the new profile to '%1'.").arg(QString::fromStdString(temp_si.GetFileName()))); 219 return; 220 } 221 222 refreshProfileList(); 223 switchProfile(profile_name); 224 } 225 226 void ControllerSettingsWindow::onApplyProfileClicked() 227 { 228 if (QMessageBox::question(this, tr("Load Input Profile"), 229 tr("Are you sure you want to load the input profile named '%1'?\n\n" 230 "All current global bindings will be removed, and the profile bindings loaded.\n\n" 231 "You cannot undo this action.") 232 .arg(m_profile_name)) != QMessageBox::Yes) 233 { 234 return; 235 } 236 237 { 238 const bool copy_hotkey_bindings = 239 m_editing_settings_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false); 240 auto lock = Host::GetSettingsLock(); 241 InputManager::CopyConfiguration(Host::Internal::GetBaseSettingsLayer(), *m_editing_settings_interface, true, true, 242 copy_hotkey_bindings); 243 QtHost::QueueSettingsSave(); 244 } 245 g_emu_thread->applySettings(); 246 247 // make it visible 248 switchProfile({}); 249 } 250 251 void ControllerSettingsWindow::onDeleteProfileClicked() 252 { 253 if (QMessageBox::question(this, tr("Delete Input Profile"), 254 tr("Are you sure you want to delete the input profile named '%1'?\n\n" 255 "You cannot undo this action.") 256 .arg(m_profile_name)) != QMessageBox::Yes) 257 { 258 return; 259 } 260 261 std::string profile_path(System::GetInputProfilePath(m_profile_name.toStdString())); 262 if (!FileSystem::DeleteFile(profile_path.c_str())) 263 { 264 QMessageBox::critical(this, tr("Error"), tr("Failed to delete '%1'.").arg(QString::fromStdString(profile_path))); 265 return; 266 } 267 268 // switch back to global 269 refreshProfileList(); 270 switchProfile({}); 271 } 272 273 void ControllerSettingsWindow::onRestoreDefaultsClicked() 274 { 275 if (QMessageBox::question( 276 this, tr("Restore Defaults"), 277 tr("Are you sure you want to restore the default controller configuration?\n\n" 278 "All shared bindings and configuration will be lost, but your input profiles will remain.\n\n" 279 "You cannot undo this action.")) != QMessageBox::Yes) 280 { 281 return; 282 } 283 284 // actually restore it 285 g_emu_thread->setDefaultSettings(false, true); 286 287 // reload all settings 288 switchProfile({}); 289 } 290 291 void ControllerSettingsWindow::onCopyGlobalSettingsClicked() 292 { 293 DebugAssert(isEditingGameSettings()); 294 295 { 296 const auto lock = Host::GetSettingsLock(); 297 InputManager::CopyConfiguration(m_editing_settings_interface, *Host::Internal::GetBaseSettingsLayer(), true, true, 298 false); 299 } 300 301 m_editing_settings_interface->Save(); 302 g_emu_thread->reloadGameSettings(); 303 createWidgets(); 304 305 QMessageBox::information(QtUtils::GetRootWidget(this), tr("DuckStation Controller Settings"), 306 tr("Per-game controller configuration reset to global settings.")); 307 } 308 309 void ControllerSettingsWindow::onRestoreDefaultsForGameClicked() 310 { 311 DebugAssert(isEditingGameSettings()); 312 Settings::SetDefaultControllerConfig(*m_editing_settings_interface); 313 m_editing_settings_interface->Save(); 314 g_emu_thread->reloadGameSettings(); 315 createWidgets(); 316 317 QMessageBox::information(QtUtils::GetRootWidget(this), tr("DuckStation Controller Settings"), 318 tr("Per-game controller configuration reset to default settings.")); 319 } 320 321 void ControllerSettingsWindow::onInputDevicesEnumerated(const std::vector<std::pair<std::string, std::string>>& devices) 322 { 323 m_device_list = devices; 324 for (const auto& [device_name, display_name] : m_device_list) 325 m_global_settings->addDeviceToList(QString::fromStdString(device_name), QString::fromStdString(display_name)); 326 } 327 328 void ControllerSettingsWindow::onInputDeviceConnected(const std::string& identifier, const std::string& device_name) 329 { 330 m_device_list.emplace_back(identifier, device_name); 331 m_global_settings->addDeviceToList(QString::fromStdString(identifier), QString::fromStdString(device_name)); 332 g_emu_thread->enumerateVibrationMotors(); 333 } 334 335 void ControllerSettingsWindow::onInputDeviceDisconnected(const std::string& identifier) 336 { 337 for (auto iter = m_device_list.begin(); iter != m_device_list.end(); ++iter) 338 { 339 if (iter->first == identifier) 340 { 341 m_device_list.erase(iter); 342 break; 343 } 344 } 345 346 m_global_settings->removeDeviceFromList(QString::fromStdString(identifier)); 347 g_emu_thread->enumerateVibrationMotors(); 348 } 349 350 void ControllerSettingsWindow::onVibrationMotorsEnumerated(const QList<InputBindingKey>& motors) 351 { 352 m_vibration_motors.clear(); 353 m_vibration_motors.reserve(motors.size()); 354 355 for (const InputBindingKey key : motors) 356 { 357 const std::string key_str(InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type::Motor, key)); 358 if (!key_str.empty()) 359 m_vibration_motors.push_back(QString::fromStdString(key_str)); 360 } 361 } 362 363 bool ControllerSettingsWindow::getBoolValue(const char* section, const char* key, bool default_value) const 364 { 365 if (m_editing_settings_interface) 366 return m_editing_settings_interface->GetBoolValue(section, key, default_value); 367 else 368 return Host::GetBaseBoolSettingValue(section, key, default_value); 369 } 370 371 s32 ControllerSettingsWindow::getIntValue(const char* section, const char* key, s32 default_value) const 372 { 373 if (m_editing_settings_interface) 374 return m_editing_settings_interface->GetIntValue(section, key, default_value); 375 else 376 return Host::GetBaseIntSettingValue(section, key, default_value); 377 } 378 379 std::string ControllerSettingsWindow::getStringValue(const char* section, const char* key, 380 const char* default_value) const 381 { 382 std::string value; 383 if (m_editing_settings_interface) 384 value = m_editing_settings_interface->GetStringValue(section, key, default_value); 385 else 386 value = Host::GetBaseStringSettingValue(section, key, default_value); 387 return value; 388 } 389 390 void ControllerSettingsWindow::setBoolValue(const char* section, const char* key, bool value) 391 { 392 if (m_editing_settings_interface) 393 { 394 m_editing_settings_interface->SetBoolValue(section, key, value); 395 saveAndReloadGameSettings(); 396 } 397 else 398 { 399 Host::SetBaseBoolSettingValue(section, key, value); 400 Host::CommitBaseSettingChanges(); 401 g_emu_thread->applySettings(); 402 } 403 } 404 405 void ControllerSettingsWindow::setIntValue(const char* section, const char* key, s32 value) 406 { 407 if (m_editing_settings_interface) 408 { 409 m_editing_settings_interface->SetIntValue(section, key, value); 410 saveAndReloadGameSettings(); 411 } 412 else 413 { 414 Host::SetBaseIntSettingValue(section, key, value); 415 Host::CommitBaseSettingChanges(); 416 g_emu_thread->applySettings(); 417 } 418 } 419 420 void ControllerSettingsWindow::setStringValue(const char* section, const char* key, const char* value) 421 { 422 if (m_editing_settings_interface) 423 { 424 m_editing_settings_interface->SetStringValue(section, key, value); 425 saveAndReloadGameSettings(); 426 } 427 else 428 { 429 Host::SetBaseStringSettingValue(section, key, value); 430 Host::CommitBaseSettingChanges(); 431 g_emu_thread->applySettings(); 432 } 433 } 434 435 void ControllerSettingsWindow::saveAndReloadGameSettings() 436 { 437 DebugAssert(m_editing_settings_interface); 438 QtHost::SaveGameSettings(m_editing_settings_interface, false); 439 g_emu_thread->reloadGameSettings(false); 440 } 441 442 void ControllerSettingsWindow::clearSettingValue(const char* section, const char* key) 443 { 444 if (m_editing_settings_interface) 445 { 446 m_editing_settings_interface->DeleteValue(section, key); 447 m_editing_settings_interface->Save(); 448 g_emu_thread->reloadGameSettings(); 449 } 450 else 451 { 452 Host::DeleteBaseSettingValue(section, key); 453 Host::CommitBaseSettingChanges(); 454 g_emu_thread->applySettings(); 455 } 456 } 457 458 void ControllerSettingsWindow::createWidgets() 459 { 460 QSignalBlocker sb(m_ui.settingsContainer); 461 QSignalBlocker sb2(m_ui.settingsCategory); 462 463 while (m_ui.settingsContainer->count() > 0) 464 { 465 QWidget* widget = m_ui.settingsContainer->widget(m_ui.settingsContainer->count() - 1); 466 m_ui.settingsContainer->removeWidget(widget); 467 widget->deleteLater(); 468 } 469 470 m_ui.settingsCategory->clear(); 471 472 m_global_settings = nullptr; 473 m_hotkey_settings = nullptr; 474 475 { 476 // global settings 477 QListWidgetItem* item = new QListWidgetItem(); 478 item->setText(tr("Global Settings")); 479 item->setIcon(QIcon::fromTheme(QStringLiteral("settings-3-line"))); 480 m_ui.settingsCategory->addItem(item); 481 m_ui.settingsCategory->setCurrentRow(0); 482 m_global_settings = new ControllerGlobalSettingsWidget(m_ui.settingsContainer, this); 483 m_ui.settingsContainer->addWidget(m_global_settings); 484 connect(m_global_settings, &ControllerGlobalSettingsWidget::bindingSetupChanged, this, 485 &ControllerSettingsWindow::createWidgets); 486 for (const auto& [identifier, device_name] : m_device_list) 487 m_global_settings->addDeviceToList(QString::fromStdString(identifier), QString::fromStdString(device_name)); 488 } 489 490 // load mtap settings 491 const std::array<bool, 2> mtap_enabled = getEnabledMultitaps(); 492 493 // we reorder things a little to make it look less silly for mtap 494 static constexpr const std::array<u32, MAX_PORTS> mtap_port_order = {{0, 2, 3, 4, 1, 5, 6, 7}}; 495 496 // create the ports 497 for (u32 global_slot : mtap_port_order) 498 { 499 const bool is_mtap_port = Controller::PadIsMultitapSlot(global_slot); 500 const auto [port, slot] = Controller::ConvertPadToPortAndSlot(global_slot); 501 if (is_mtap_port && !mtap_enabled[port]) 502 continue; 503 504 m_port_bindings[global_slot] = new ControllerBindingWidget(m_ui.settingsContainer, this, global_slot); 505 m_ui.settingsContainer->addWidget(m_port_bindings[global_slot]); 506 507 const QString display_name(QString::fromUtf8(m_port_bindings[global_slot]->getControllerInfo()->GetDisplayName())); 508 509 QListWidgetItem* item = new QListWidgetItem(); 510 item->setText(mtap_enabled[port] ? 511 (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) : 512 tr("Controller Port %1\n%2").arg(port + 1).arg(display_name)); 513 item->setIcon(m_port_bindings[global_slot]->getIcon()); 514 item->setData(Qt::UserRole, QVariant(global_slot)); 515 m_ui.settingsCategory->addItem(item); 516 } 517 518 // only add hotkeys if we're editing global settings 519 if (!m_editing_settings_interface || 520 m_editing_settings_interface->GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false)) 521 { 522 QListWidgetItem* item = new QListWidgetItem(); 523 item->setText(tr("Hotkeys")); 524 item->setIcon(QIcon::fromTheme(QStringLiteral("keyboard-line"))); 525 m_ui.settingsCategory->addItem(item); 526 m_hotkey_settings = new HotkeySettingsWidget(m_ui.settingsContainer, this); 527 m_ui.settingsContainer->addWidget(m_hotkey_settings); 528 } 529 530 if (!isEditingGameSettings()) 531 { 532 m_ui.applyProfile->setEnabled(isEditingProfile()); 533 m_ui.deleteProfile->setEnabled(isEditingProfile()); 534 m_ui.restoreDefaults->setEnabled(isEditingGlobalSettings()); 535 } 536 } 537 538 void ControllerSettingsWindow::closeEvent(QCloseEvent* event) 539 { 540 QWidget::closeEvent(event); 541 emit windowClosed(); 542 } 543 544 void ControllerSettingsWindow::updateListDescription(u32 global_slot, ControllerBindingWidget* widget) 545 { 546 for (int i = 0; i < m_ui.settingsCategory->count(); i++) 547 { 548 QListWidgetItem* item = m_ui.settingsCategory->item(i); 549 const QVariant item_data(item->data(Qt::UserRole)); 550 bool is_ok; 551 if (item_data.toUInt(&is_ok) == global_slot && is_ok) 552 { 553 const std::array<bool, 2> mtap_enabled = getEnabledMultitaps(); 554 const auto [port, slot] = Controller::ConvertPadToPortAndSlot(global_slot); 555 556 const QString display_name = QString::fromUtf8(widget->getControllerInfo()->GetDisplayName()); 557 558 item->setText(mtap_enabled[port] ? 559 (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) : 560 tr("Controller Port %1\n%2").arg(port + 1).arg(display_name)); 561 item->setIcon(widget->getIcon()); 562 break; 563 } 564 } 565 } 566 567 std::array<bool, 2> ControllerSettingsWindow::getEnabledMultitaps() const 568 { 569 const MultitapMode mtap_mode = 570 Settings::ParseMultitapModeName( 571 getStringValue("ControllerPorts", "MultitapMode", Settings::GetMultitapModeName(Settings::DEFAULT_MULTITAP_MODE)) 572 .c_str()) 573 .value_or(Settings::DEFAULT_MULTITAP_MODE); 574 return {{(mtap_mode == MultitapMode::Port1Only || mtap_mode == MultitapMode::BothPorts), 575 (mtap_mode == MultitapMode::Port2Only || mtap_mode == MultitapMode::BothPorts)}}; 576 } 577 void ControllerSettingsWindow::refreshProfileList() 578 { 579 const std::vector<std::string> names(InputManager::GetInputProfileNames()); 580 581 QSignalBlocker sb(m_ui.currentProfile); 582 m_ui.currentProfile->clear(); 583 m_ui.currentProfile->addItem(tr("Shared")); 584 if (isEditingGlobalSettings()) 585 m_ui.currentProfile->setCurrentIndex(0); 586 587 for (const std::string& name : names) 588 { 589 const QString qname(QString::fromStdString(name)); 590 m_ui.currentProfile->addItem(qname); 591 if (qname == m_profile_name) 592 m_ui.currentProfile->setCurrentIndex(m_ui.currentProfile->count() - 1); 593 } 594 } 595 596 void ControllerSettingsWindow::switchProfile(const std::string_view name) 597 { 598 QSignalBlocker sb(m_ui.currentProfile); 599 600 if (!name.empty()) 601 { 602 const QString name_qstr = QtUtils::StringViewToQString(name); 603 604 std::string path = System::GetInputProfilePath(name); 605 if (!FileSystem::FileExists(path.c_str())) 606 { 607 QMessageBox::critical(this, tr("Error"), tr("The input profile named '%1' cannot be found.").arg(name_qstr)); 608 return; 609 } 610 611 std::unique_ptr<INISettingsInterface> sif = std::make_unique<INISettingsInterface>(std::move(path)); 612 sif->Load(); 613 614 m_profile_settings_interface = std::move(sif); 615 m_editing_settings_interface = m_profile_settings_interface.get(); 616 m_ui.currentProfile->setCurrentIndex(m_ui.currentProfile->findText(name_qstr)); 617 m_profile_name = name_qstr; 618 } 619 else 620 { 621 m_profile_settings_interface.reset(); 622 m_editing_settings_interface = nullptr; 623 m_ui.currentProfile->setCurrentIndex(0); 624 m_profile_name = QString(); 625 } 626 627 createWidgets(); 628 }