diff --git a/src/duckstation-qt/CMakeLists.txt b/src/duckstation-qt/CMakeLists.txt index 5355515c1..a0187b38f 100644 --- a/src/duckstation-qt/CMakeLists.txt +++ b/src/duckstation-qt/CMakeLists.txt @@ -13,6 +13,8 @@ add_executable(duckstation-qt consolesettingswidget.cpp consolesettingswidget.h consolesettingswidget.ui + controllersettingswidget.cpp + controllersettingswidget.h gamelistsettingswidget.cpp gamelistsettingswidget.h gamelistsettingswidget.ui @@ -35,10 +37,10 @@ add_executable(duckstation-qt mainwindow.cpp mainwindow.h mainwindow.ui + memorycardsettingswidget.cpp + memorycardsettingswidget.h openglhostdisplay.cpp openglhostdisplay.h - portsettingswidget.cpp - portsettingswidget.h qthostdisplay.cpp qthostdisplay.h qtdisplaywidget.cpp diff --git a/src/duckstation-qt/portsettingswidget.cpp b/src/duckstation-qt/controllersettingswidget.cpp similarity index 56% rename from src/duckstation-qt/portsettingswidget.cpp rename to src/duckstation-qt/controllersettingswidget.cpp index 2dfa05eed..5ad465285 100644 --- a/src/duckstation-qt/portsettingswidget.cpp +++ b/src/duckstation-qt/controllersettingswidget.cpp @@ -1,4 +1,4 @@ -#include "portsettingswidget.h" +#include "controllersettingswidget.h" #include "core/controller.h" #include "core/settings.h" #include "inputbindingwidgets.h" @@ -14,20 +14,19 @@ #include #include -static constexpr char MEMORY_CARD_IMAGE_FILTER[] = "All Memory Card Types (*.mcd *.mcr *.mc)"; static constexpr char INPUT_PROFILE_FILTER[] = "Input Profiles (*.ini)"; -PortSettingsWidget::PortSettingsWidget(QtHostInterface* host_interface, QWidget* parent /* = nullptr */) +ControllerSettingsWidget::ControllerSettingsWidget(QtHostInterface* host_interface, QWidget* parent /* = nullptr */) : QWidget(parent), m_host_interface(host_interface) { createUi(); - connect(host_interface, &QtHostInterface::inputProfileLoaded, this, &PortSettingsWidget::onProfileLoaded); + connect(host_interface, &QtHostInterface::inputProfileLoaded, this, &ControllerSettingsWidget::onProfileLoaded); } -PortSettingsWidget::~PortSettingsWidget() = default; +ControllerSettingsWidget::~ControllerSettingsWidget() = default; -void PortSettingsWidget::createUi() +void ControllerSettingsWidget::createUi() { QGridLayout* layout = new QGridLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -41,7 +40,7 @@ void PortSettingsWidget::createUi() setLayout(layout); } -void PortSettingsWidget::onProfileLoaded() +void ControllerSettingsWidget::onProfileLoaded() { for (int i = 0; i < static_cast(m_port_ui.size()); i++) { @@ -60,7 +59,7 @@ void PortSettingsWidget::onProfileLoaded() } } -void PortSettingsWidget::reloadBindingButtons() +void ControllerSettingsWidget::reloadBindingButtons() { for (PortSettingsUI& ui : m_port_ui) { @@ -73,41 +72,14 @@ void PortSettingsWidget::reloadBindingButtons() } } -void PortSettingsWidget::createPortSettingsUi(int index, PortSettingsUI* ui) +void ControllerSettingsWidget::createPortSettingsUi(int index, PortSettingsUI* ui) { ui->widget = new QWidget(m_tab_widget); ui->layout = new QVBoxLayout(ui->widget); - ui->memory_card_type = new QComboBox(ui->widget); - for (int i = 0; i < static_cast(MemoryCardType::Count); i++) - { - ui->memory_card_type->addItem( - QString::fromUtf8(Settings::GetMemoryCardTypeDisplayName(static_cast(i)))); - } - SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, ui->memory_card_type, - QStringLiteral("MemoryCards/Card%1Type").arg(index + 1), - &Settings::ParseMemoryCardTypeName, &Settings::GetMemoryCardTypeName); - ui->layout->addWidget(new QLabel(tr("Memory Card Type:"), ui->widget)); - ui->layout->addWidget(ui->memory_card_type); - - QHBoxLayout* memory_card_layout = new QHBoxLayout(); - ui->memory_card_path = new QLineEdit(ui->widget); - SettingWidgetBinder::BindWidgetToStringSetting(m_host_interface, ui->memory_card_path, - QStringLiteral("MemoryCards/Card%1Path").arg(index + 1)); - memory_card_layout->addWidget(ui->memory_card_path); - - QPushButton* memory_card_path_browse = new QPushButton(tr("Browse..."), ui->widget); - connect(memory_card_path_browse, &QPushButton::clicked, [this, index]() { onBrowseMemoryCardPathClicked(index); }); - memory_card_layout->addWidget(memory_card_path_browse); - - QPushButton* memory_card_remove = new QPushButton(tr("Remove"), ui->widget); - connect(memory_card_remove, &QPushButton::clicked, [this, index]() { onEjectMemoryCardClicked(index); }); - memory_card_layout->addWidget(memory_card_remove); - - ui->layout->addWidget(new QLabel(tr("Shared Memory Card Path:"), ui->widget)); - ui->layout->addLayout(memory_card_layout); - - ui->layout->addWidget(new QLabel(tr("Controller Type:"), ui->widget)); + QHBoxLayout* hbox = new QHBoxLayout(); + hbox->addWidget(new QLabel(tr("Controller Type:"), ui->widget)); + hbox->addSpacing(8); ui->controller_type = new QComboBox(ui->widget); for (int i = 0; i < static_cast(ControllerType::Count); i++) @@ -125,22 +97,79 @@ void PortSettingsWidget::createPortSettingsUi(int index, PortSettingsUI* ui) connect(ui->controller_type, static_cast(&QComboBox::currentIndexChanged), [this, index]() { onControllerTypeChanged(index); }); - ui->layout->addWidget(ui->controller_type); + hbox->addWidget(ui->controller_type, 1); + ui->layout->addLayout(hbox); + + ui->bindings_scroll_area = new QScrollArea(ui->widget); + ui->bindings_scroll_area->setWidgetResizable(true); + ui->bindings_scroll_area->setFrameShape(QFrame::StyledPanel); + ui->bindings_scroll_area->setFrameShadow(QFrame::Plain); createPortBindingSettingsUi(index, ui, ctype); - ui->layout->addStretch(1); + ui->bindings_scroll_area->setWidget(ui->bindings_container); + ui->layout->addWidget(ui->bindings_scroll_area, 1); + + hbox = new QHBoxLayout(); + QPushButton* load_profile_button = new QPushButton(tr("Load Profile"), ui->widget); + connect(load_profile_button, &QPushButton::clicked, this, &ControllerSettingsWidget::onLoadProfileClicked); + hbox->addWidget(load_profile_button); + + QPushButton* save_profile_button = new QPushButton(tr("Save Profile"), ui->widget); + connect(save_profile_button, &QPushButton::clicked, this, &ControllerSettingsWidget::onSaveProfileClicked); + hbox->addWidget(save_profile_button); + + hbox->addStretch(1); + + QPushButton* clear_all_button = new QPushButton(tr("Clear All"), ui->widget); + clear_all_button->connect(clear_all_button, &QPushButton::clicked, [this, index]() { + if (QMessageBox::question(this, tr("Clear Bindings"), + tr("Are you sure you want to clear all bound controls? This cannot be reversed.")) != + QMessageBox::Yes) + { + return; + } + + InputBindingWidget* widget = m_port_ui[index].first_button; + while (widget) + { + widget->clearBinding(); + widget = widget->getNextWidget(); + } + }); + + QPushButton* rebind_all_button = new QPushButton(tr("Rebind All"), ui->widget); + rebind_all_button->connect(rebind_all_button, &QPushButton::clicked, [this, index]() { + if (QMessageBox::question(this, tr("Clear Bindings"), tr("Do you want to clear all currently-bound controls?")) == + QMessageBox::Yes) + { + InputBindingWidget* widget = m_port_ui[index].first_button; + while (widget) + { + widget->clearBinding(); + widget = widget->getNextWidget(); + } + } + + if (m_port_ui[index].first_button) + m_port_ui[index].first_button->beginRebindAll(); + }); + + hbox->addWidget(clear_all_button); + hbox->addWidget(rebind_all_button); + + ui->layout->addLayout(hbox); ui->widget->setLayout(ui->layout); m_tab_widget->addTab(ui->widget, tr("Port %1").arg(index + 1)); } -void PortSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI* ui, ControllerType ctype) +void ControllerSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI* ui, ControllerType ctype) { - QWidget* container = new QWidget(ui->widget); - QGridLayout* layout = new QGridLayout(container); - layout->setContentsMargins(0, 0, 0, 0); + ui->bindings_container = new QWidget(ui->widget); + + QGridLayout* layout = new QGridLayout(ui->bindings_container); const auto buttons = Controller::GetButtonNames(ctype); InputBindingWidget* first_button = nullptr; @@ -149,8 +178,7 @@ void PortSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI* int start_row = 0; if (!buttons.empty()) { - layout->addWidget(QtUtils::CreateHorizontalLine(container), start_row++, 0, 1, 4); - layout->addWidget(new QLabel(tr("Button Bindings:"), container), start_row++, 0, 1, 4); + layout->addWidget(new QLabel(tr("Button Bindings:"), ui->bindings_container), start_row++, 0, 1, 4); const int num_rows = (static_cast(buttons.size()) + 1) / 2; int current_row = 0; @@ -165,8 +193,9 @@ void PortSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI* const QString button_name_q = QString::fromStdString(button_name); const QString setting_name = QStringLiteral("Controller%1/Button%2").arg(index + 1).arg(button_name_q); - QLabel* label = new QLabel(button_name_q, container); - InputButtonBindingWidget* button = new InputButtonBindingWidget(m_host_interface, setting_name, container); + QLabel* label = new QLabel(button_name_q, ui->bindings_container); + InputButtonBindingWidget* button = + new InputButtonBindingWidget(m_host_interface, setting_name, ui->bindings_container); layout->addWidget(label, start_row + current_row, current_column); layout->addWidget(button, start_row + current_row, current_column + 1); @@ -185,11 +214,8 @@ void PortSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI* const auto axises = Controller::GetAxisNames(ctype); if (!axises.empty()) { - QFrame* line = new QFrame(container); - line->setFrameShape(QFrame::HLine); - line->setFrameShadow(QFrame::Sunken); - layout->addWidget(line, start_row++, 0, 1, 4); - layout->addWidget(new QLabel(tr("Axis Bindings:"), container), start_row++, 0, 1, 4); + layout->addWidget(QtUtils::CreateHorizontalLine(ui->bindings_container), start_row++, 0, 1, 4); + layout->addWidget(new QLabel(tr("Axis Bindings:"), ui->bindings_container), start_row++, 0, 1, 4); const int num_rows = (static_cast(axises.size()) + 1) / 2; int current_row = 0; @@ -204,8 +230,9 @@ void PortSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI* const QString axis_name_q = QString::fromStdString(axis_name); const QString setting_name = QStringLiteral("Controller%1/Axis%2").arg(index + 1).arg(axis_name_q); - QLabel* label = new QLabel(axis_name_q, container); - InputAxisBindingWidget* button = new InputAxisBindingWidget(m_host_interface, setting_name, container); + QLabel* label = new QLabel(axis_name_q, ui->bindings_container); + InputAxisBindingWidget* button = + new InputAxisBindingWidget(m_host_interface, setting_name, ui->bindings_container); layout->addWidget(label, start_row + current_row, current_column); layout->addWidget(button, start_row + current_row, current_column + 1); @@ -227,8 +254,9 @@ void PortSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI* layout->addWidget(QtUtils::CreateHorizontalLine(ui->widget), start_row++, 0, 1, 4); const QString setting_name = QStringLiteral("Controller%1/Rumble").arg(index + 1); - QLabel* label = new QLabel(tr("Rumble"), container); - InputRumbleBindingWidget* button = new InputRumbleBindingWidget(m_host_interface, setting_name, container); + QLabel* label = new QLabel(tr("Rumble"), ui->bindings_container); + InputRumbleBindingWidget* button = + new InputRumbleBindingWidget(m_host_interface, setting_name, ui->bindings_container); layout->addWidget(label, start_row, 0); layout->addWidget(button, start_row, 1); @@ -242,78 +270,15 @@ void PortSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI* start_row++; } - layout->addWidget(QtUtils::CreateHorizontalLine(ui->widget), start_row++, 0, 1, 4); + // dummy row to fill remaining space + layout->addWidget(new QWidget(ui->bindings_container), start_row, 0, 1, 4); + layout->setRowStretch(start_row, 1); - QHBoxLayout* left_hbox = new QHBoxLayout(); - QPushButton* load_profile_button = new QPushButton(tr("Load Profile"), ui->widget); - connect(load_profile_button, &QPushButton::clicked, this, &PortSettingsWidget::onLoadProfileClicked); - left_hbox->addWidget(load_profile_button); - - QPushButton* save_profile_button = new QPushButton(tr("Save Profile"), ui->widget); - connect(save_profile_button, &QPushButton::clicked, this, &PortSettingsWidget::onSaveProfileClicked); - left_hbox->addWidget(save_profile_button); - - layout->addLayout(left_hbox, start_row, 0, 1, 2, Qt::AlignLeft); - - if (first_button) - { - QHBoxLayout* right_hbox = new QHBoxLayout(); - - QPushButton* clear_all_button = new QPushButton(tr("Clear All"), ui->widget); - clear_all_button->connect(clear_all_button, &QPushButton::clicked, [this, first_button]() { - if (QMessageBox::question(this, tr("Clear Bindings"), - tr("Are you sure you want to clear all bound controls? This cannot be reversed.")) != - QMessageBox::Yes) - { - return; - } - - InputBindingWidget* widget = first_button; - while (widget) - { - widget->clearBinding(); - widget = widget->getNextWidget(); - } - }); - - QPushButton* rebind_all_button = new QPushButton(tr("Rebind All"), ui->widget); - rebind_all_button->connect(rebind_all_button, &QPushButton::clicked, [this, first_button]() { - if (QMessageBox::question(this, tr("Clear Bindings"), tr("Do you want to clear all currently-bound controls?")) == - QMessageBox::Yes) - { - InputBindingWidget* widget = first_button; - while (widget) - { - widget->clearBinding(); - widget = widget->getNextWidget(); - } - } - - first_button->beginRebindAll(); - }); - - right_hbox->addWidget(clear_all_button); - right_hbox->addWidget(rebind_all_button); - layout->addLayout(right_hbox, start_row, 2, 1, 2, Qt::AlignRight); - } - - if (ui->button_binding_container) - { - QLayoutItem* old_item = ui->layout->replaceWidget(ui->button_binding_container, container); - Q_ASSERT(old_item != nullptr); - - delete old_item; - ui->button_binding_container->deleteLater(); - } - else - { - ui->layout->addWidget(container); - } - ui->button_binding_container = container; + ui->bindings_scroll_area->setWidget(ui->bindings_container); ui->first_button = first_button; } -void PortSettingsWidget::onControllerTypeChanged(int index) +void ControllerSettingsWidget::onControllerTypeChanged(int index) { const int type_index = m_port_ui[index].controller_type->currentIndex(); if (type_index < 0 || type_index >= static_cast(ControllerType::Count)) @@ -326,27 +291,7 @@ void PortSettingsWidget::onControllerTypeChanged(int index) createPortBindingSettingsUi(index, &m_port_ui[index], static_cast(type_index)); } -void PortSettingsWidget::onBrowseMemoryCardPathClicked(int index) -{ - QString path = - QFileDialog::getOpenFileName(this, tr("Select path to memory card image"), QString(), tr(MEMORY_CARD_IMAGE_FILTER)); - if (path.isEmpty()) - return; - - m_port_ui[index].memory_card_path->setText(path); -} - -void PortSettingsWidget::onEjectMemoryCardClicked(int index) -{ - QSignalBlocker blocker(m_port_ui[index].memory_card_path); - m_port_ui[index].memory_card_type->setCurrentIndex(0); - m_port_ui[index].memory_card_path->setText(QString()); - m_host_interface->putSettingValue(QStringLiteral("MemoryCards/Card%1Type").arg(index + 1), QStringLiteral("None")); - m_host_interface->putSettingValue(QStringLiteral("MemoryCards/Card%1Path").arg(index + 1), QString()); - m_host_interface->applySettings(); -} - -void PortSettingsWidget::onLoadProfileClicked() +void ControllerSettingsWidget::onLoadProfileClicked() { const auto profile_names = m_host_interface->getInputProfileList(); @@ -373,7 +318,7 @@ void PortSettingsWidget::onLoadProfileClicked() menu.exec(QCursor::pos()); } -void PortSettingsWidget::onSaveProfileClicked() +void ControllerSettingsWidget::onSaveProfileClicked() { const auto profile_names = m_host_interface->getInputProfileList(); diff --git a/src/duckstation-qt/portsettingswidget.h b/src/duckstation-qt/controllersettingswidget.h similarity index 74% rename from src/duckstation-qt/portsettingswidget.h rename to src/duckstation-qt/controllersettingswidget.h index ad567024e..d1b205497 100644 --- a/src/duckstation-qt/portsettingswidget.h +++ b/src/duckstation-qt/controllersettingswidget.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -15,13 +16,13 @@ class QTimer; class QtHostInterface; class InputBindingWidget; -class PortSettingsWidget : public QWidget +class ControllerSettingsWidget : public QWidget { Q_OBJECT public: - PortSettingsWidget(QtHostInterface* host_interface, QWidget* parent = nullptr); - ~PortSettingsWidget(); + ControllerSettingsWidget(QtHostInterface* host_interface, QWidget* parent = nullptr); + ~ControllerSettingsWidget(); private Q_SLOTS: void onProfileLoaded(); @@ -36,9 +37,8 @@ private: QWidget* widget; QVBoxLayout* layout; QComboBox* controller_type; - QComboBox* memory_card_type; - QLineEdit* memory_card_path; - QWidget* button_binding_container; + QScrollArea* bindings_scroll_area; + QWidget* bindings_container; InputBindingWidget* first_button; }; @@ -47,8 +47,6 @@ private: void createPortSettingsUi(int index, PortSettingsUI* ui); void createPortBindingSettingsUi(int index, PortSettingsUI* ui, ControllerType ctype); void onControllerTypeChanged(int index); - void onBrowseMemoryCardPathClicked(int index); - void onEjectMemoryCardClicked(int index); void onLoadProfileClicked(); void onSaveProfileClicked(); diff --git a/src/duckstation-qt/duckstation-qt.vcxproj b/src/duckstation-qt/duckstation-qt.vcxproj index 43cf150d8..0491e02e6 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj +++ b/src/duckstation-qt/duckstation-qt.vcxproj @@ -50,7 +50,8 @@ - + + @@ -60,7 +61,8 @@ - + + @@ -143,6 +145,7 @@ + @@ -151,7 +154,7 @@ - + @@ -166,16 +169,9 @@ false - + - + {28F14272-0EC4-41BB-849F-182ADB81AF70} diff --git a/src/duckstation-qt/duckstation-qt.vcxproj.filters b/src/duckstation-qt/duckstation-qt.vcxproj.filters index 6fc9a4551..b4a4c1c71 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj.filters +++ b/src/duckstation-qt/duckstation-qt.vcxproj.filters @@ -16,7 +16,6 @@ - @@ -35,9 +34,12 @@ - + + + + @@ -53,7 +55,7 @@ - + @@ -62,7 +64,6 @@ - @@ -71,6 +72,8 @@ + + @@ -81,6 +84,7 @@ + diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index 056209418..030a292a5 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -516,8 +516,10 @@ void MainWindow::connectSignals() [this]() { doSettings(SettingsDialog::Category::GameListSettings); }); connect(m_ui.actionHotkeySettings, &QAction::triggered, [this]() { doSettings(SettingsDialog::Category::HotkeySettings); }); - connect(m_ui.actionPortSettings, &QAction::triggered, - [this]() { doSettings(SettingsDialog::Category::PortSettings); }); + connect(m_ui.actionControllerSettings, &QAction::triggered, + [this]() { doSettings(SettingsDialog::Category::ControllerSettings); }); + connect(m_ui.actionMemoryCardSettings, &QAction::triggered, + [this]() { doSettings(SettingsDialog::Category::MemoryCardSettings); }); connect(m_ui.actionGPUSettings, &QAction::triggered, [this]() { doSettings(SettingsDialog::Category::GPUSettings); }); connect(m_ui.actionAudioSettings, &QAction::triggered, [this]() { doSettings(SettingsDialog::Category::AudioSettings); }); diff --git a/src/duckstation-qt/mainwindow.ui b/src/duckstation-qt/mainwindow.ui index ce4b3bbaa..455a93579 100644 --- a/src/duckstation-qt/mainwindow.ui +++ b/src/duckstation-qt/mainwindow.ui @@ -90,7 +90,8 @@ - + + @@ -263,16 +264,16 @@ :/icons/utilities-system-monitor.png:/icons/utilities-system-monitor.png - &Console Settings... + C&onsole Settings... - + :/icons/input-gaming.png:/icons/input-gaming.png - &Port Settings... + &Controller Settings... @@ -496,6 +497,15 @@ &Screenshot + + + + :/icons/media-flash-24.png:/icons/media-flash-24.png + + + &Memory Card Settings... + + diff --git a/src/duckstation-qt/memorycardsettingswidget.cpp b/src/duckstation-qt/memorycardsettingswidget.cpp new file mode 100644 index 000000000..46fe92f5e --- /dev/null +++ b/src/duckstation-qt/memorycardsettingswidget.cpp @@ -0,0 +1,101 @@ +#include "memorycardsettingswidget.h" +#include "core/controller.h" +#include "core/settings.h" +#include "inputbindingwidgets.h" +#include "qthostinterface.h" +#include "qtutils.h" +#include "settingwidgetbinder.h" +#include +#include +#include + +static constexpr char MEMORY_CARD_IMAGE_FILTER[] = "All Memory Card Types (*.mcd *.mcr *.mc)"; + +MemoryCardSettingsWidget::MemoryCardSettingsWidget(QtHostInterface* host_interface, QWidget* parent /* = nullptr */) + : QWidget(parent), m_host_interface(host_interface) +{ + createUi(); +} + +MemoryCardSettingsWidget::~MemoryCardSettingsWidget() = default; + +void MemoryCardSettingsWidget::createUi() +{ + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + + for (int i = 0; i < static_cast(m_port_ui.size()); i++) + { + createPortSettingsUi(i, &m_port_ui[i]); + layout->addWidget(m_port_ui[i].container); + } + + { + QGroupBox* note_box = new QGroupBox(this); + QHBoxLayout* note_layout = new QHBoxLayout(note_box); + QLabel* note_label = + new QLabel(tr("If one of the \"separate card per game\" memory card modes is chosen, these memory " + "cards will be saved to the memcards directory."), + note_box); + note_label->setWordWrap(true); + note_layout->addWidget(note_label, 1); + + QPushButton* open_memcards = new QPushButton(tr("Open..."), note_box); + connect(open_memcards, &QPushButton::clicked, this, &MemoryCardSettingsWidget::onOpenMemCardsDirectoryClicked); + note_layout->addWidget(open_memcards); + layout->addWidget(note_box); + } + + layout->addStretch(1); + + setLayout(layout); +} + +void MemoryCardSettingsWidget::createPortSettingsUi(int index, PortSettingsUI* ui) +{ + ui->container = new QGroupBox(tr("Memory Card %1").arg(index + 1), this); + ui->layout = new QVBoxLayout(ui->container); + + ui->memory_card_type = new QComboBox(ui->container); + for (int i = 0; i < static_cast(MemoryCardType::Count); i++) + { + ui->memory_card_type->addItem( + QString::fromUtf8(Settings::GetMemoryCardTypeDisplayName(static_cast(i)))); + } + SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, ui->memory_card_type, + QStringLiteral("MemoryCards/Card%1Type").arg(index + 1), + &Settings::ParseMemoryCardTypeName, &Settings::GetMemoryCardTypeName); + ui->layout->addWidget(new QLabel(tr("Memory Card Type:"), ui->container)); + ui->layout->addWidget(ui->memory_card_type); + + QHBoxLayout* memory_card_layout = new QHBoxLayout(); + ui->memory_card_path = new QLineEdit(ui->container); + SettingWidgetBinder::BindWidgetToStringSetting(m_host_interface, ui->memory_card_path, + QStringLiteral("MemoryCards/Card%1Path").arg(index + 1)); + memory_card_layout->addWidget(ui->memory_card_path); + + QPushButton* memory_card_path_browse = new QPushButton(tr("Browse..."), ui->container); + connect(memory_card_path_browse, &QPushButton::clicked, [this, index]() { onBrowseMemoryCardPathClicked(index); }); + memory_card_layout->addWidget(memory_card_path_browse); + + ui->layout->addWidget(new QLabel(tr("Shared Memory Card Path:"), ui->container)); + ui->layout->addLayout(memory_card_layout); + + ui->layout->addStretch(1); +} + +void MemoryCardSettingsWidget::onBrowseMemoryCardPathClicked(int index) +{ + QString path = + QFileDialog::getOpenFileName(this, tr("Select path to memory card image"), QString(), tr(MEMORY_CARD_IMAGE_FILTER)); + if (path.isEmpty()) + return; + + m_port_ui[index].memory_card_path->setText(path); +} + +void MemoryCardSettingsWidget::onOpenMemCardsDirectoryClicked() +{ + QtUtils::OpenURL(this, + QUrl::fromLocalFile(m_host_interface->getUserDirectoryRelativePath(QStringLiteral("memcards")))); +} diff --git a/src/duckstation-qt/memorycardsettingswidget.h b/src/duckstation-qt/memorycardsettingswidget.h new file mode 100644 index 000000000..82971b29f --- /dev/null +++ b/src/duckstation-qt/memorycardsettingswidget.h @@ -0,0 +1,38 @@ +#pragma once +#include "core/types.h" +#include +#include +#include +#include +#include +#include +#include + +class QtHostInterface; + +class MemoryCardSettingsWidget : public QWidget +{ + Q_OBJECT + +public: + MemoryCardSettingsWidget(QtHostInterface* host_interface, QWidget* parent = nullptr); + ~MemoryCardSettingsWidget(); + +private: + QtHostInterface* m_host_interface; + + struct PortSettingsUI + { + QGroupBox* container; + QVBoxLayout* layout; + QComboBox* memory_card_type; + QLineEdit* memory_card_path; + }; + + void createUi(); + void createPortSettingsUi(int index, PortSettingsUI* ui); + void onBrowseMemoryCardPathClicked(int index); + void onOpenMemCardsDirectoryClicked(); + + std::array m_port_ui = {}; +}; diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp index ed7b6705d..79bcab074 100644 --- a/src/duckstation-qt/qthostinterface.cpp +++ b/src/duckstation-qt/qthostinterface.cpp @@ -551,6 +551,22 @@ void QtHostInterface::saveInputProfile(const QString& profile_name) SaveInputProfile(profile_name.toUtf8().data(), si); } +QString QtHostInterface::getUserDirectoryRelativePath(const QString& arg) const +{ + QString result = QString::fromStdString(m_user_directory); + result += '/'; + result += arg; + return result; +} + +QString QtHostInterface::getProgramDirectoryRelativePath(const QString& arg) const +{ + QString result = QString::fromStdString(m_program_directory); + result += '/'; + result += arg; + return result; +} + void QtHostInterface::powerOffSystem() { if (!isOnWorkerThread()) diff --git a/src/duckstation-qt/qthostinterface.h b/src/duckstation-qt/qthostinterface.h index 398f4b782..f56a75085 100644 --- a/src/duckstation-qt/qthostinterface.h +++ b/src/duckstation-qt/qthostinterface.h @@ -83,6 +83,12 @@ public: } void saveInputProfile(const QString& profile_path); + /// Returns a path relative to the user directory. + QString getUserDirectoryRelativePath(const QString& arg) const; + + /// Returns a path relative to the application directory (for system files). + QString getProgramDirectoryRelativePath(const QString& arg) const; + Q_SIGNALS: void errorReported(const QString& message); void messageReported(const QString& message); diff --git a/src/duckstation-qt/resources/icons.qrc b/src/duckstation-qt/resources/icons.qrc index 356d5cc3b..920147d02 100644 --- a/src/duckstation-qt/resources/icons.qrc +++ b/src/duckstation-qt/resources/icons.qrc @@ -30,6 +30,7 @@ icons/drive-removable-media.png icons/input-gaming.png icons/media-flash.png + icons/media-flash-24.png icons/media-optical.png icons/media-optical-24.png icons/media-playback-pause.png diff --git a/src/duckstation-qt/resources/icons/media-flash-24.png b/src/duckstation-qt/resources/icons/media-flash-24.png new file mode 100644 index 000000000..c6a2d0c65 Binary files /dev/null and b/src/duckstation-qt/resources/icons/media-flash-24.png differ diff --git a/src/duckstation-qt/settingsdialog.cpp b/src/duckstation-qt/settingsdialog.cpp index 684a87a32..40b62d177 100644 --- a/src/duckstation-qt/settingsdialog.cpp +++ b/src/duckstation-qt/settingsdialog.cpp @@ -2,11 +2,12 @@ #include "advancedsettingswidget.h" #include "audiosettingswidget.h" #include "consolesettingswidget.h" +#include "controllersettingswidget.h" #include "gamelistsettingswidget.h" #include "generalsettingswidget.h" #include "gpusettingswidget.h" #include "hotkeysettingswidget.h" -#include "portsettingswidget.h" +#include "memorycardsettingswidget.h" #include "qthostinterface.h" #include @@ -24,10 +25,12 @@ static constexpr std::array(SettingsDialog::Catego "Hotkey Settings
Binding a hotkey allows you to trigger events such as a resetting, powering " "off, taking screenshots or saving/loading states at the press of a key/controller button. Hotkey titles are " "self-explanatory.", - "Port Settings
This page lets you choose the type of controller you wish to simulate for the " - "console, and rebind the keys or host game controller buttons to your choosing. Clicking a binding will start a " + "Controller Settings
This page lets you choose the type of controller you wish to simulate for " + "the console, and rebind the keys or host game controller buttons to your choosing. Clicking a binding will start a " "count-down, in which case you should press the key or controller button/axis you wish to bind. If no button is " "pressed and the timer lapses, the binding will be unchanged. To clear a binding, right-click the button.", + "Memory Card Settings
This page lets you control what mode the memory card emulation will " + "function in, and where the images for these cards will be stored on disk.", "GPU Settings
These options control the simulation of the GPU in the console. Various " "enhancements are available, mouse over each for additional information.", "Audio Settings
These options control the audio output of the console. Mouse over an option for " @@ -46,7 +49,8 @@ SettingsDialog::SettingsDialog(QtHostInterface* host_interface, QWidget* parent m_console_settings = new ConsoleSettingsWidget(host_interface, m_ui.settingsContainer); m_game_list_settings = new GameListSettingsWidget(host_interface, m_ui.settingsContainer); m_hotkey_settings = new HotkeySettingsWidget(host_interface, m_ui.settingsContainer); - m_port_settings = new PortSettingsWidget(host_interface, m_ui.settingsContainer); + m_controller_settings = new ControllerSettingsWidget(host_interface, m_ui.settingsContainer); + m_memory_card_settings = new MemoryCardSettingsWidget(host_interface, m_ui.settingsContainer); m_gpu_settings = new GPUSettingsWidget(host_interface, m_ui.settingsContainer, this); m_audio_settings = new AudioSettingsWidget(host_interface, m_ui.settingsContainer); m_advanced_settings = new AdvancedSettingsWidget(host_interface, m_ui.settingsContainer, this); @@ -55,7 +59,8 @@ SettingsDialog::SettingsDialog(QtHostInterface* host_interface, QWidget* parent m_ui.settingsContainer->insertWidget(static_cast(Category::ConsoleSettings), m_console_settings); m_ui.settingsContainer->insertWidget(static_cast(Category::GameListSettings), m_game_list_settings); m_ui.settingsContainer->insertWidget(static_cast(Category::HotkeySettings), m_hotkey_settings); - m_ui.settingsContainer->insertWidget(static_cast(Category::PortSettings), m_port_settings); + m_ui.settingsContainer->insertWidget(static_cast(Category::ControllerSettings), m_controller_settings); + m_ui.settingsContainer->insertWidget(static_cast(Category::MemoryCardSettings), m_memory_card_settings); m_ui.settingsContainer->insertWidget(static_cast(Category::GPUSettings), m_gpu_settings); m_ui.settingsContainer->insertWidget(static_cast(Category::AudioSettings), m_audio_settings); m_ui.settingsContainer->insertWidget(static_cast(Category::AdvancedSettings), m_advanced_settings); diff --git a/src/duckstation-qt/settingsdialog.h b/src/duckstation-qt/settingsdialog.h index 62ec1f1de..4315e6b84 100644 --- a/src/duckstation-qt/settingsdialog.h +++ b/src/duckstation-qt/settingsdialog.h @@ -10,7 +10,8 @@ class GeneralSettingsWidget; class GameListSettingsWidget; class HotkeySettingsWidget; class ConsoleSettingsWidget; -class PortSettingsWidget; +class ControllerSettingsWidget; +class MemoryCardSettingsWidget; class GPUSettingsWidget; class AudioSettingsWidget; class AdvancedSettingsWidget; @@ -26,7 +27,8 @@ public: ConsoleSettings, GameListSettings, HotkeySettings, - PortSettings, + ControllerSettings, + MemoryCardSettings, GPUSettings, AudioSettings, AdvancedSettings, @@ -40,7 +42,8 @@ public: ConsoleSettingsWidget* getConsoleSettingsWidget() const { return m_console_settings; } GameListSettingsWidget* getGameListSettingsWidget() const { return m_game_list_settings; } HotkeySettingsWidget* getHotkeySettingsWidget() const { return m_hotkey_settings; } - PortSettingsWidget* getPortSettingsWidget() const { return m_port_settings; } + ControllerSettingsWidget* getControllerSettingsWidget() const { return m_controller_settings; } + MemoryCardSettingsWidget* getMemoryCardSettingsWidget() const { return m_memory_card_settings; } GPUSettingsWidget* getGPUSettingsWidget() const { return m_gpu_settings; } AudioSettingsWidget* getAudioSettingsWidget() const { return m_audio_settings; } AdvancedSettingsWidget* getAdvancedSettingsWidget() const { return m_advanced_settings; } @@ -63,7 +66,8 @@ private: ConsoleSettingsWidget* m_console_settings = nullptr; GameListSettingsWidget* m_game_list_settings = nullptr; HotkeySettingsWidget* m_hotkey_settings = nullptr; - PortSettingsWidget* m_port_settings = nullptr; + ControllerSettingsWidget* m_controller_settings = nullptr; + MemoryCardSettingsWidget* m_memory_card_settings = nullptr; GPUSettingsWidget* m_gpu_settings = nullptr; AudioSettingsWidget* m_audio_settings = nullptr; AdvancedSettingsWidget* m_advanced_settings = nullptr; diff --git a/src/duckstation-qt/settingsdialog.ui b/src/duckstation-qt/settingsdialog.ui index f7bff4f2d..4274a65f8 100644 --- a/src/duckstation-qt/settingsdialog.ui +++ b/src/duckstation-qt/settingsdialog.ui @@ -10,7 +10,7 @@ 0 0 780 - 820 + 650 @@ -78,13 +78,22 @@ - Port Settings + Controller Settings :/icons/input-gaming.png:/icons/input-gaming.png + + + Memory Card Settings + + + + :/icons/media-flash.png:/icons/media-flash.png + + GPU Settings