memorycardsettingswidget.cpp (7592B)
1 // SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "memorycardsettingswidget.h" 5 6 #include "core/controller.h" 7 #include "core/settings.h" 8 #include "inputbindingwidgets.h" 9 #include "mainwindow.h" 10 #include "qthost.h" 11 #include "qtutils.h" 12 #include "settingswindow.h" 13 #include "settingwidgetbinder.h" 14 15 #include "common/small_string.h" 16 #include "common/string_util.h" 17 18 #include <QtCore/QUrl> 19 #include <QtWidgets/QFileDialog> 20 #include <QtWidgets/QLabel> 21 22 static constexpr char MEMORY_CARD_IMAGE_FILTER[] = 23 QT_TRANSLATE_NOOP("MemoryCardSettingsWidget", "All Memory Card Types (*.mcd *.mcr *.mc)"); 24 25 MemoryCardSettingsWidget::MemoryCardSettingsWidget(SettingsWindow* dialog, QWidget* parent) 26 : QWidget(parent), m_dialog(dialog) 27 { 28 createUi(dialog); 29 } 30 31 MemoryCardSettingsWidget::~MemoryCardSettingsWidget() = default; 32 33 void MemoryCardSettingsWidget::createUi(SettingsWindow* dialog) 34 { 35 QVBoxLayout* layout = new QVBoxLayout(this); 36 layout->setContentsMargins(0, 0, 0, 0); 37 38 for (int i = 0; i < static_cast<int>(m_port_ui.size()); i++) 39 { 40 createPortSettingsUi(dialog, i, &m_port_ui[i]); 41 layout->addWidget(m_port_ui[i].container); 42 } 43 44 { 45 QGroupBox* box = new QGroupBox(tr("Shared Settings"), this); 46 QVBoxLayout* box_layout = new QVBoxLayout(box); 47 QPushButton* browse = new QPushButton(tr("Browse..."), box); 48 QPushButton* open_memcards = new QPushButton(tr("Open..."), box); 49 QPushButton* reset = new QPushButton(tr("Reset"), box); 50 51 { 52 QLabel* label = new QLabel(tr("Memory Card Directory:"), box); 53 box_layout->addWidget(label); 54 55 QHBoxLayout* hbox = new QHBoxLayout(); 56 m_memory_card_directory = new QLineEdit(box); 57 58 hbox->addWidget(m_memory_card_directory); 59 hbox->addWidget(browse); 60 hbox->addWidget(open_memcards); 61 hbox->addWidget(reset); 62 63 box_layout->addLayout(hbox); 64 } 65 66 QCheckBox* playlist_title_as_game_title = new QCheckBox(tr("Use Single Card For Multi-Disc Games"), box); 67 SettingWidgetBinder::BindWidgetToBoolSetting(m_dialog->getSettingsInterface(), playlist_title_as_game_title, 68 "MemoryCards", "UsePlaylistTitle", true); 69 box_layout->addWidget(playlist_title_as_game_title); 70 dialog->registerWidgetHelp( 71 playlist_title_as_game_title, tr("Use Single Card For Multi-Disc Games"), tr("Checked"), 72 tr("When playing a multi-disc game and using per-game (title) memory cards, a single memory card " 73 "will be used for all discs. If unchecked, a separate card will be used for each disc.")); 74 75 box_layout->addWidget(QtUtils::CreateHorizontalLine(box)); 76 77 { 78 QHBoxLayout* hbox = new QHBoxLayout(); 79 QLabel* label = new QLabel( 80 tr("The memory card editor enables you to move saves between cards, as well as import cards of other formats."), 81 box); 82 label->setWordWrap(true); 83 hbox->addWidget(label, 1); 84 85 QPushButton* button = new QPushButton(tr("Memory Card Editor..."), box); 86 connect(button, &QPushButton::clicked, []() { g_main_window->openMemoryCardEditor(QString(), QString()); }); 87 hbox->addWidget(button); 88 box_layout->addLayout(hbox); 89 } 90 91 layout->addWidget(box); 92 93 SettingWidgetBinder::BindWidgetToFolderSetting( 94 m_dialog->getSettingsInterface(), m_memory_card_directory, browse, tr("Select Memory Card Directory"), 95 open_memcards, reset, "MemoryCards", "Directory", Path::Combine(EmuFolders::DataRoot, "memcards")); 96 } 97 98 layout->addStretch(1); 99 100 setLayout(layout); 101 } 102 103 void MemoryCardSettingsWidget::createPortSettingsUi(SettingsWindow* dialog, int index, PortSettingsUI* ui) 104 { 105 ui->container = new QGroupBox(tr("Memory Card %1").arg(index + 1), this); 106 ui->layout = new QVBoxLayout(ui->container); 107 108 ui->memory_card_type = new QComboBox(ui->container); 109 for (int i = 0; i < static_cast<int>(MemoryCardType::Count); i++) 110 { 111 ui->memory_card_type->addItem( 112 QString::fromUtf8(Settings::GetMemoryCardTypeDisplayName(static_cast<MemoryCardType>(i)))); 113 } 114 115 const MemoryCardType default_value = (index == 0) ? MemoryCardType::PerGameTitle : MemoryCardType::None; 116 SettingWidgetBinder::BindWidgetToEnumSetting(m_dialog->getSettingsInterface(), ui->memory_card_type, "MemoryCards", 117 fmt::format("Card{}Type", index + 1), &Settings::ParseMemoryCardTypeName, 118 &Settings::GetMemoryCardTypeName, default_value); 119 ui->layout->addWidget(new QLabel(tr("Memory Card Type:"), ui->container)); 120 ui->layout->addWidget(ui->memory_card_type); 121 122 QHBoxLayout* memory_card_layout = new QHBoxLayout(); 123 ui->memory_card_path = new QLineEdit(ui->container); 124 updateMemoryCardPath(index); 125 connect(ui->memory_card_path, &QLineEdit::textChanged, this, [this, index]() { onMemoryCardPathChanged(index); }); 126 if (ui->memory_card_path->text().isEmpty()) 127 { 128 QSignalBlocker sb(ui->memory_card_path); 129 ui->memory_card_path->setText(QString::fromStdString(g_settings.GetSharedMemoryCardPath(static_cast<u32>(index)))); 130 } 131 memory_card_layout->addWidget(ui->memory_card_path); 132 133 QPushButton* memory_card_path_browse = new QPushButton(tr("Browse..."), ui->container); 134 connect(memory_card_path_browse, &QPushButton::clicked, this, 135 [this, index]() { onBrowseMemoryCardPathClicked(index); }); 136 memory_card_layout->addWidget(memory_card_path_browse); 137 138 QPushButton* memory_card_path_reset = new QPushButton(tr("Reset"), ui->container); 139 connect(memory_card_path_reset, &QPushButton::clicked, this, 140 [this, index]() { onResetMemoryCardPathClicked(index); }); 141 memory_card_layout->addWidget(memory_card_path_reset); 142 143 ui->layout->addWidget(new QLabel(tr("Shared Memory Card Path:"), ui->container)); 144 ui->layout->addLayout(memory_card_layout); 145 146 ui->layout->addStretch(1); 147 } 148 149 void MemoryCardSettingsWidget::onBrowseMemoryCardPathClicked(int index) 150 { 151 QString path = QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Select path to memory card image"), 152 QString(), tr(MEMORY_CARD_IMAGE_FILTER))); 153 if (path.isEmpty()) 154 return; 155 156 m_port_ui[index].memory_card_path->setText(path); 157 } 158 159 void MemoryCardSettingsWidget::onMemoryCardPathChanged(int index) 160 { 161 const auto key = TinyString::from_format("Card{}Path", index + 1); 162 std::string relative_path( 163 Path::MakeRelative(m_port_ui[index].memory_card_path->text().toStdString(), EmuFolders::MemoryCards)); 164 m_dialog->setStringSettingValue("MemoryCards", key, relative_path.c_str()); 165 } 166 167 void MemoryCardSettingsWidget::onResetMemoryCardPathClicked(int index) 168 { 169 const auto key = TinyString::from_format("Card{}Path", index + 1); 170 if (m_dialog->isPerGameSettings()) 171 m_dialog->removeSettingValue("MemoryCards", key); 172 else 173 m_dialog->setStringSettingValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index).c_str()); 174 175 updateMemoryCardPath(index); 176 } 177 178 void MemoryCardSettingsWidget::updateMemoryCardPath(int index) 179 { 180 const auto key = TinyString::from_format("Card{}Path", index + 1); 181 std::string path( 182 m_dialog->getEffectiveStringValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index).c_str())); 183 if (!Path::IsAbsolute(path)) 184 path = Path::Canonicalize(Path::Combine(EmuFolders::MemoryCards, path)); 185 186 QSignalBlocker db(m_port_ui[index].memory_card_path); 187 m_port_ui[index].memory_card_path->setText(QString::fromStdString(path)); 188 }