Qt: Split memory card/controller config, make bindings scroll

This commit is contained in:
Connor McLaughlin 2020-05-20 23:26:24 +10:00
parent e7778ea86e
commit dfe0dcb56c
16 changed files with 328 additions and 191 deletions

View file

@ -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

View file

@ -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 <QtWidgets/QMenu>
#include <QtWidgets/QMessageBox>
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<int>(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<int>(MemoryCardType::Count); i++)
{
ui->memory_card_type->addItem(
QString::fromUtf8(Settings::GetMemoryCardTypeDisplayName(static_cast<MemoryCardType>(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<int>(ControllerType::Count); i++)
@ -125,22 +97,79 @@ void PortSettingsWidget::createPortSettingsUi(int index, PortSettingsUI* ui)
connect(ui->controller_type, static_cast<void (QComboBox::*)(int)>(&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<int>(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<int>(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<int>(ControllerType::Count))
@ -326,27 +291,7 @@ void PortSettingsWidget::onControllerTypeChanged(int index)
createPortBindingSettingsUi(index, &m_port_ui[index], static_cast<ControllerType>(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();

View file

@ -5,6 +5,7 @@
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QScrollArea>
#include <QtWidgets/QTabWidget>
#include <QtWidgets/QWidget>
#include <array>
@ -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();

View file

@ -50,7 +50,8 @@
<ClCompile Include="main.cpp" />
<ClCompile Include="mainwindow.cpp" />
<ClCompile Include="openglhostdisplay.cpp" />
<ClCompile Include="portsettingswidget.cpp" />
<ClCompile Include="controllersettingswidget.cpp" />
<ClCompile Include="memorycardsettingswidget.cpp" />
<ClCompile Include="qthostdisplay.cpp" />
<ClCompile Include="qthostinterface.cpp" />
<ClCompile Include="qtprogresscallback.cpp" />
@ -60,7 +61,8 @@
</ItemGroup>
<ItemGroup>
<QtMoc Include="audiosettingswidget.h" />
<QtMoc Include="portsettingswidget.h" />
<QtMoc Include="controllersettingswidget.h" />
<QtMoc Include="memorycardsettingswidget.h" />
<QtMoc Include="qtdisplaywidget.h" />
<QtMoc Include="generalsettingswidget.h" />
<QtMoc Include="gpusettingswidget.h" />
@ -143,6 +145,7 @@
<ClCompile Include="$(IntDir)moc_audiosettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_advancedsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_consolesettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_controllersettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_gamelistsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_gamelistwidget.cpp" />
<ClCompile Include="$(IntDir)moc_gamepropertiesdialog.cpp" />
@ -151,7 +154,7 @@
<ClCompile Include="$(IntDir)moc_hotkeysettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_inputbindingwidgets.cpp" />
<ClCompile Include="$(IntDir)moc_mainwindow.cpp" />
<ClCompile Include="$(IntDir)moc_portsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_memorycardsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_qtdisplaywidget.cpp" />
<ClCompile Include="$(IntDir)moc_qthostinterface.cpp" />
<ClCompile Include="$(IntDir)moc_qtprogresscallback.cpp" />
@ -166,16 +169,9 @@
<InProject>false</InProject>
</CommonDataFiles>
</ItemGroup>
<Target Name="CopyCommonDataFiles"
AfterTargets="Build"
Inputs="@(CommonDataFiles)"
Outputs="@(CommonDataFiles -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)')">
<Target Name="CopyCommonDataFiles" AfterTargets="Build" Inputs="@(CommonDataFiles)" Outputs="@(CommonDataFiles -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)')">
<Message Text="Copying common data files" Importance="High" />
<Copy
SourceFiles="@(CommonDataFiles)"
DestinationFolder="$(BinaryOutputDir)\%(RecursiveDir)"
SkipUnchangedFiles="true"
/>
<Copy SourceFiles="@(CommonDataFiles)" DestinationFolder="$(BinaryOutputDir)\%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>
<PropertyGroup Label="Globals">
<ProjectGuid>{28F14272-0EC4-41BB-849F-182ADB81AF70}</ProjectGuid>

View file

@ -16,7 +16,6 @@
<ClCompile Include="$(IntDir)moc_mainwindow.cpp" />
<ClCompile Include="$(IntDir)moc_qthostinterface.cpp" />
<ClCompile Include="$(IntDir)moc_settingsdialog.cpp" />
<ClCompile Include="portsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_portsettingswidget.cpp" />
<ClCompile Include="gpusettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_gpusettingswidget.cpp" />
@ -35,9 +34,12 @@
<ClCompile Include="qthostdisplay.cpp" />
<ClCompile Include="openglhostdisplay.cpp" />
<ClCompile Include="d3d11hostdisplay.cpp" />
<ClCompile Include="$(IntDir)qrc_resources.cpp" />
<ClCompile Include="advancedsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_advancedsettingswidget.cpp" />
<ClCompile Include="gamepropertiesdialog.cpp" />
<ClCompile Include="$(IntDir)moc_gamepropertiesdialog.cpp" />
<ClCompile Include="$(IntDir)qrc_icons.cpp" />
<ClCompile Include="controllersettingswidget.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="qtsettingsinterface.h" />
@ -53,7 +55,7 @@
</Filter>
</ItemGroup>
<ItemGroup>
<QtResource Include="resources\resources.qrc" />
<QtResource Include="resources\icons.qrc" />
</ItemGroup>
<ItemGroup>
<QtMoc Include="consolesettingswidget.h" />
@ -62,7 +64,6 @@
<QtMoc Include="mainwindow.h" />
<QtMoc Include="qthostinterface.h" />
<QtMoc Include="settingsdialog.h" />
<QtMoc Include="portsettingswidget.h" />
<QtMoc Include="gpusettingswidget.h" />
<QtMoc Include="hotkeysettingswidget.h" />
<QtMoc Include="inputbindingwidgets.h" />
@ -71,6 +72,8 @@
<QtMoc Include="generalsettingswidget.h" />
<QtMoc Include="qtprogresscallback.h" />
<QtMoc Include="advancedsettingswidget.h" />
<QtMoc Include="gamepropertiesdialog.h" />
<QtMoc Include="controllersettingswidget.h" />
</ItemGroup>
<ItemGroup>
<QtUi Include="consolesettingswidget.ui" />
@ -81,6 +84,7 @@
<QtUi Include="audiosettingswidget.ui" />
<QtUi Include="generalsettingswidget.ui" />
<QtUi Include="advancedsettingswidget.ui" />
<QtUi Include="gamepropertiesdialog.ui" />
</ItemGroup>
<ItemGroup>
<Natvis Include="qt5.natvis" />

View file

@ -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); });

View file

@ -90,7 +90,8 @@
<addaction name="actionConsoleSettings"/>
<addaction name="actionGameListSettings"/>
<addaction name="actionHotkeySettings"/>
<addaction name="actionPortSettings"/>
<addaction name="actionControllerSettings"/>
<addaction name="actionMemoryCardSettings"/>
<addaction name="actionGPUSettings"/>
<addaction name="actionAudioSettings"/>
<addaction name="actionAdvancedSettings"/>
@ -263,16 +264,16 @@
<normaloff>:/icons/utilities-system-monitor.png</normaloff>:/icons/utilities-system-monitor.png</iconset>
</property>
<property name="text">
<string>&amp;Console Settings...</string>
<string>C&amp;onsole Settings...</string>
</property>
</action>
<action name="actionPortSettings">
<action name="actionControllerSettings">
<property name="icon">
<iconset resource="resources/icons.qrc">
<normaloff>:/icons/input-gaming.png</normaloff>:/icons/input-gaming.png</iconset>
</property>
<property name="text">
<string>&amp;Port Settings...</string>
<string>&amp;Controller Settings...</string>
</property>
</action>
<action name="actionHotkeySettings">
@ -496,6 +497,15 @@
<string>&amp;Screenshot</string>
</property>
</action>
<action name="actionMemoryCardSettings">
<property name="icon">
<iconset resource="resources/icons.qrc">
<normaloff>:/icons/media-flash-24.png</normaloff>:/icons/media-flash-24.png</iconset>
</property>
<property name="text">
<string>&amp;Memory Card Settings...</string>
</property>
</action>
</widget>
<resources>
<include location="resources/icons.qrc"/>

View file

@ -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 <QtCore/QUrl>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QLabel>
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<int>(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<int>(MemoryCardType::Count); i++)
{
ui->memory_card_type->addItem(
QString::fromUtf8(Settings::GetMemoryCardTypeDisplayName(static_cast<MemoryCardType>(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"))));
}

View file

@ -0,0 +1,38 @@
#pragma once
#include "core/types.h"
#include <QtWidgets/QComboBox>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
#include <array>
#include <vector>
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<PortSettingsUI, 2> m_port_ui = {};
};

View file

@ -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())

View file

@ -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);

View file

@ -30,6 +30,7 @@
<file>icons/drive-removable-media.png</file>
<file>icons/input-gaming.png</file>
<file>icons/media-flash.png</file>
<file>icons/media-flash-24.png</file>
<file>icons/media-optical.png</file>
<file>icons/media-optical-24.png</file>
<file>icons/media-playback-pause.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

View file

@ -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 <QtWidgets/QTextEdit>
@ -24,10 +25,12 @@ static constexpr std::array<const char*, static_cast<int>(SettingsDialog::Catego
"<strong>Hotkey Settings</strong><hr>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.",
"<strong>Port Settings</strong><hr>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 "
"<strong>Controller Settings</strong><hr>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.",
"<strong>Memory Card Settings</strong><hr>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.",
"<strong>GPU Settings</strong><hr>These options control the simulation of the GPU in the console. Various "
"enhancements are available, mouse over each for additional information.",
"<strong>Audio Settings</strong><hr>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<int>(Category::ConsoleSettings), m_console_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::GameListSettings), m_game_list_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::HotkeySettings), m_hotkey_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::PortSettings), m_port_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::ControllerSettings), m_controller_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::MemoryCardSettings), m_memory_card_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::GPUSettings), m_gpu_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::AudioSettings), m_audio_settings);
m_ui.settingsContainer->insertWidget(static_cast<int>(Category::AdvancedSettings), m_advanced_settings);

View file

@ -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;

View file

@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>780</width>
<height>820</height>
<height>650</height>
</rect>
</property>
<property name="windowTitle">
@ -78,13 +78,22 @@
</item>
<item>
<property name="text">
<string>Port Settings</string>
<string>Controller Settings</string>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/input-gaming.png</normaloff>:/icons/input-gaming.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>Memory Card Settings</string>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/media-flash.png</normaloff>:/icons/media-flash.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>GPU Settings</string>