2020-05-20 13:26:24 +00:00
|
|
|
#include "controllersettingswidget.h"
|
2021-05-15 17:25:15 +00:00
|
|
|
#include "collapsiblewidget.h"
|
2020-07-21 09:49:04 +00:00
|
|
|
#include "common/string_util.h"
|
2020-01-02 06:13:03 +00:00
|
|
|
#include "core/controller.h"
|
|
|
|
#include "core/settings.h"
|
2020-01-05 02:46:03 +00:00
|
|
|
#include "inputbindingwidgets.h"
|
2020-01-02 06:13:03 +00:00
|
|
|
#include "qthostinterface.h"
|
|
|
|
#include "qtutils.h"
|
2020-04-08 14:03:48 +00:00
|
|
|
#include "settingwidgetbinder.h"
|
2020-04-08 14:13:44 +00:00
|
|
|
#include <QtCore/QSignalBlocker>
|
2020-01-02 06:13:03 +00:00
|
|
|
#include <QtCore/QTimer>
|
2020-04-14 15:44:16 +00:00
|
|
|
#include <QtGui/QCursor>
|
2020-08-22 03:01:52 +00:00
|
|
|
#include <QtGui/QGuiApplication>
|
2020-01-02 06:13:03 +00:00
|
|
|
#include <QtGui/QKeyEvent>
|
2020-04-08 14:09:16 +00:00
|
|
|
#include <QtWidgets/QFileDialog>
|
2020-04-26 15:05:01 +00:00
|
|
|
#include <QtWidgets/QInputDialog>
|
2020-04-14 15:44:16 +00:00
|
|
|
#include <QtWidgets/QMenu>
|
2020-03-21 14:50:09 +00:00
|
|
|
#include <QtWidgets/QMessageBox>
|
2020-01-02 06:13:03 +00:00
|
|
|
|
2020-04-14 15:44:16 +00:00
|
|
|
static constexpr char INPUT_PROFILE_FILTER[] = "Input Profiles (*.ini)";
|
2020-04-08 14:09:16 +00:00
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
ControllerSettingsWidget::ControllerSettingsWidget(QtHostInterface* host_interface, QWidget* parent /* = nullptr */)
|
2020-01-02 06:13:03 +00:00
|
|
|
: QWidget(parent), m_host_interface(host_interface)
|
|
|
|
{
|
|
|
|
createUi();
|
2020-04-14 15:44:16 +00:00
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
connect(host_interface, &QtHostInterface::inputProfileLoaded, this, &ControllerSettingsWidget::onProfileLoaded);
|
2020-01-02 06:13:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
ControllerSettingsWidget::~ControllerSettingsWidget() = default;
|
2020-01-02 06:13:03 +00:00
|
|
|
|
2021-03-03 11:33:24 +00:00
|
|
|
MultitapMode ControllerSettingsWidget::getMultitapMode()
|
|
|
|
{
|
|
|
|
return Settings::ParseMultitapModeName(
|
|
|
|
QtHostInterface::GetInstance()
|
|
|
|
->GetStringSettingValue("ControllerPorts", "MultitapMode",
|
|
|
|
Settings::GetMultitapModeName(Settings::DEFAULT_MULTITAP_MODE))
|
|
|
|
.c_str())
|
|
|
|
.value_or(Settings::DEFAULT_MULTITAP_MODE);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString ControllerSettingsWidget::getTabTitleForPort(u32 index, MultitapMode mode) const
|
|
|
|
{
|
|
|
|
constexpr u32 NUM_PORTS_PER_MULTITAP = 4;
|
|
|
|
|
|
|
|
u32 port_number, subport_number;
|
|
|
|
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case MultitapMode::Port1Only:
|
|
|
|
{
|
|
|
|
if (index == NUM_PORTS_PER_MULTITAP)
|
|
|
|
return tr("Port %1").arg((index / NUM_PORTS_PER_MULTITAP) + 1);
|
|
|
|
else if (index > NUM_PORTS_PER_MULTITAP)
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
port_number = 0;
|
|
|
|
subport_number = index;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MultitapMode::Port2Only:
|
|
|
|
{
|
|
|
|
if (index == 0)
|
|
|
|
return tr("Port %1").arg(index + 1);
|
|
|
|
else if (index > NUM_PORTS_PER_MULTITAP)
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
port_number = 1;
|
|
|
|
subport_number = (index - 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MultitapMode::BothPorts:
|
|
|
|
{
|
|
|
|
port_number = index / NUM_PORTS_PER_MULTITAP;
|
|
|
|
subport_number = (index % NUM_PORTS_PER_MULTITAP);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MultitapMode::Disabled:
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
if (index >= (NUM_CONTROLLER_AND_CARD_PORTS / NUM_PORTS_PER_MULTITAP))
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
return tr("Port %1").arg(index + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tr("Port %1%2").arg(port_number + 1).arg(QChar::fromLatin1('A' + subport_number));
|
|
|
|
}
|
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
void ControllerSettingsWidget::createUi()
|
2020-01-02 06:13:03 +00:00
|
|
|
{
|
|
|
|
QGridLayout* layout = new QGridLayout(this);
|
2020-01-24 04:50:52 +00:00
|
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
2020-01-02 06:13:03 +00:00
|
|
|
|
2021-03-03 11:33:24 +00:00
|
|
|
const MultitapMode multitap_mode = getMultitapMode();
|
2020-01-02 06:13:03 +00:00
|
|
|
m_tab_widget = new QTabWidget(this);
|
|
|
|
for (int i = 0; i < static_cast<int>(m_port_ui.size()); i++)
|
2021-03-03 11:33:24 +00:00
|
|
|
createPortSettingsUi(i, &m_port_ui[i], multitap_mode);
|
2020-01-02 06:13:03 +00:00
|
|
|
|
|
|
|
layout->addWidget(m_tab_widget, 0, 0, 1, 1);
|
|
|
|
|
|
|
|
setLayout(layout);
|
|
|
|
}
|
|
|
|
|
2021-03-03 11:33:24 +00:00
|
|
|
void ControllerSettingsWidget::updateMultitapControllerTitles()
|
|
|
|
{
|
2021-03-03 14:26:01 +00:00
|
|
|
m_tab_widget->clear();
|
2021-03-03 11:33:24 +00:00
|
|
|
|
2021-03-03 14:26:01 +00:00
|
|
|
const MultitapMode multitap_mode = getMultitapMode();
|
2021-03-03 11:33:24 +00:00
|
|
|
for (int i = 0; i < static_cast<int>(m_port_ui.size()); i++)
|
2021-03-03 14:26:01 +00:00
|
|
|
createPortSettingsUi(i, &m_port_ui[i], multitap_mode);
|
2021-03-03 11:33:24 +00:00
|
|
|
}
|
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
void ControllerSettingsWidget::onProfileLoaded()
|
2020-04-14 15:44:16 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < static_cast<int>(m_port_ui.size()); i++)
|
|
|
|
{
|
2021-03-04 14:58:48 +00:00
|
|
|
if (!m_port_ui[i].widget)
|
|
|
|
continue;
|
|
|
|
|
2020-04-14 15:44:16 +00:00
|
|
|
ControllerType ctype = Settings::ParseControllerTypeName(
|
2020-07-13 16:24:11 +00:00
|
|
|
m_host_interface
|
2020-07-21 09:49:04 +00:00
|
|
|
->GetStringSettingValue(QStringLiteral("Controller%1").arg(i + 1).toStdString().c_str(),
|
2020-08-22 03:01:52 +00:00
|
|
|
QStringLiteral("Type").toStdString().c_str())
|
2020-04-14 15:44:16 +00:00
|
|
|
.c_str())
|
|
|
|
.value_or(ControllerType::None);
|
|
|
|
|
|
|
|
{
|
|
|
|
QSignalBlocker blocker(m_port_ui[i].controller_type);
|
|
|
|
m_port_ui[i].controller_type->setCurrentIndex(static_cast<int>(ctype));
|
|
|
|
}
|
|
|
|
createPortBindingSettingsUi(i, &m_port_ui[i], ctype);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
void ControllerSettingsWidget::reloadBindingButtons()
|
2020-04-14 15:44:16 +00:00
|
|
|
{
|
|
|
|
for (PortSettingsUI& ui : m_port_ui)
|
|
|
|
{
|
|
|
|
InputBindingWidget* widget = ui.first_button;
|
|
|
|
while (widget)
|
|
|
|
{
|
|
|
|
widget->reloadBinding();
|
|
|
|
widget = widget->getNextWidget();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-03 11:33:24 +00:00
|
|
|
void ControllerSettingsWidget::createPortSettingsUi(int index, PortSettingsUI* ui, MultitapMode multitap_mode)
|
2020-01-02 06:13:03 +00:00
|
|
|
{
|
2021-03-03 14:26:01 +00:00
|
|
|
if (ui->widget)
|
|
|
|
{
|
|
|
|
delete ui->widget;
|
|
|
|
*ui = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
const QString tab_title(getTabTitleForPort(index, multitap_mode));
|
|
|
|
if (tab_title.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2020-01-02 06:13:03 +00:00
|
|
|
ui->widget = new QWidget(m_tab_widget);
|
|
|
|
ui->layout = new QVBoxLayout(ui->widget);
|
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
QHBoxLayout* hbox = new QHBoxLayout();
|
|
|
|
hbox->addWidget(new QLabel(tr("Controller Type:"), ui->widget));
|
|
|
|
hbox->addSpacing(8);
|
2020-03-21 14:50:09 +00:00
|
|
|
|
2020-01-02 06:13:03 +00:00
|
|
|
ui->controller_type = new QComboBox(ui->widget);
|
|
|
|
for (int i = 0; i < static_cast<int>(ControllerType::Count); i++)
|
|
|
|
{
|
|
|
|
ui->controller_type->addItem(
|
2020-08-22 03:01:52 +00:00
|
|
|
qApp->translate("ControllerType", Settings::GetControllerTypeDisplayName(static_cast<ControllerType>(i))));
|
2020-01-02 06:13:03 +00:00
|
|
|
}
|
2020-07-21 09:49:04 +00:00
|
|
|
ControllerType ctype =
|
|
|
|
Settings::ParseControllerTypeName(
|
|
|
|
m_host_interface->GetStringSettingValue(TinyString::FromFormat("Controller%d", index + 1), "Type").c_str())
|
|
|
|
.value_or(ControllerType::None);
|
2020-01-24 04:49:49 +00:00
|
|
|
ui->controller_type->setCurrentIndex(static_cast<int>(ctype));
|
2020-01-02 06:13:03 +00:00
|
|
|
connect(ui->controller_type, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
|
|
|
[this, index]() { onControllerTypeChanged(index); });
|
2020-03-21 14:50:09 +00:00
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
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);
|
2020-01-02 06:13:03 +00:00
|
|
|
|
2020-01-24 04:49:49 +00:00
|
|
|
createPortBindingSettingsUi(index, ui, ctype);
|
2020-01-02 06:13:03 +00:00
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
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"),
|
2020-06-14 23:06:29 +00:00
|
|
|
tr("Are you sure you want to clear all bound controls? This can not be reversed.")) !=
|
2020-05-20 13:26:24 +00:00
|
|
|
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]() {
|
2020-06-14 23:06:29 +00:00
|
|
|
if (QMessageBox::question(this, tr("Rebind All"),
|
|
|
|
tr("Are you sure you want to rebind all controls? All currently-bound controls will be "
|
2020-06-30 14:34:13 +00:00
|
|
|
"irreversibly cleared. Rebinding will begin after confirmation.")) != QMessageBox::Yes)
|
2020-05-20 13:26:24 +00:00
|
|
|
{
|
2020-06-14 23:06:29 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
InputBindingWidget* widget = m_port_ui[index].first_button;
|
|
|
|
while (widget)
|
|
|
|
{
|
|
|
|
widget->clearBinding();
|
|
|
|
widget = widget->getNextWidget();
|
2020-05-20 13:26:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2020-01-02 06:13:03 +00:00
|
|
|
|
|
|
|
ui->widget->setLayout(ui->layout);
|
|
|
|
|
2021-03-03 11:33:24 +00:00
|
|
|
m_tab_widget->addTab(ui->widget, tab_title);
|
2020-01-02 06:13:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
void ControllerSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI* ui, ControllerType ctype)
|
2020-01-02 06:13:03 +00:00
|
|
|
{
|
2020-05-20 13:26:24 +00:00
|
|
|
ui->bindings_container = new QWidget(ui->widget);
|
|
|
|
|
|
|
|
QGridLayout* layout = new QGridLayout(ui->bindings_container);
|
2020-01-02 06:13:03 +00:00
|
|
|
const auto buttons = Controller::GetButtonNames(ctype);
|
2020-08-23 12:47:49 +00:00
|
|
|
const char* cname = Settings::GetControllerTypeName(ctype);
|
2020-01-02 06:13:03 +00:00
|
|
|
|
2020-03-21 14:50:09 +00:00
|
|
|
InputBindingWidget* first_button = nullptr;
|
|
|
|
InputBindingWidget* last_button = nullptr;
|
|
|
|
|
2020-02-17 15:06:28 +00:00
|
|
|
int start_row = 0;
|
2020-01-02 06:13:03 +00:00
|
|
|
if (!buttons.empty())
|
|
|
|
{
|
2020-05-20 13:26:24 +00:00
|
|
|
layout->addWidget(new QLabel(tr("Button Bindings:"), ui->bindings_container), start_row++, 0, 1, 4);
|
2020-01-02 06:13:03 +00:00
|
|
|
|
|
|
|
const int num_rows = (static_cast<int>(buttons.size()) + 1) / 2;
|
|
|
|
int current_row = 0;
|
|
|
|
int current_column = 0;
|
|
|
|
for (const auto& [button_name, button_code] : buttons)
|
|
|
|
{
|
|
|
|
if (current_row == num_rows)
|
|
|
|
{
|
|
|
|
current_row = 0;
|
|
|
|
current_column += 2;
|
|
|
|
}
|
|
|
|
|
2020-07-21 09:49:04 +00:00
|
|
|
std::string section_name = StringUtil::StdStringFromFormat("Controller%d", index + 1);
|
|
|
|
std::string key_name = StringUtil::StdStringFromFormat("Button%s", button_name.c_str());
|
2020-08-23 12:47:49 +00:00
|
|
|
QLabel* label = new QLabel(qApp->translate(cname, button_name.c_str()), ui->bindings_container);
|
2020-07-21 09:49:04 +00:00
|
|
|
InputButtonBindingWidget* button = new InputButtonBindingWidget(m_host_interface, std::move(section_name),
|
|
|
|
std::move(key_name), ui->bindings_container);
|
2020-01-02 06:13:03 +00:00
|
|
|
layout->addWidget(label, start_row + current_row, current_column);
|
|
|
|
layout->addWidget(button, start_row + current_row, current_column + 1);
|
|
|
|
|
2020-03-21 14:50:09 +00:00
|
|
|
if (!first_button)
|
|
|
|
first_button = button;
|
|
|
|
if (last_button)
|
|
|
|
last_button->setNextWidget(button);
|
|
|
|
last_button = button;
|
|
|
|
|
2020-01-02 06:13:03 +00:00
|
|
|
current_row++;
|
|
|
|
}
|
2020-02-17 15:06:28 +00:00
|
|
|
|
|
|
|
start_row += num_rows;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto axises = Controller::GetAxisNames(ctype);
|
|
|
|
if (!axises.empty())
|
|
|
|
{
|
2020-05-20 13:26:24 +00:00
|
|
|
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);
|
2020-02-17 15:06:28 +00:00
|
|
|
|
|
|
|
const int num_rows = (static_cast<int>(axises.size()) + 1) / 2;
|
|
|
|
int current_row = 0;
|
|
|
|
int current_column = 0;
|
2020-08-29 12:19:28 +00:00
|
|
|
for (const auto& [axis_name, axis_code, axis_type] : axises)
|
2020-02-17 15:06:28 +00:00
|
|
|
{
|
|
|
|
if (current_row == num_rows)
|
|
|
|
{
|
|
|
|
current_row = 0;
|
|
|
|
current_column += 2;
|
|
|
|
}
|
|
|
|
|
2020-07-21 09:49:04 +00:00
|
|
|
std::string section_name = StringUtil::StdStringFromFormat("Controller%d", index + 1);
|
|
|
|
std::string key_name = StringUtil::StdStringFromFormat("Axis%s", axis_name.c_str());
|
2020-08-23 12:47:49 +00:00
|
|
|
QLabel* label = new QLabel(qApp->translate(cname, axis_name.c_str()), ui->bindings_container);
|
2020-08-29 12:19:28 +00:00
|
|
|
InputAxisBindingWidget* button = new InputAxisBindingWidget(
|
|
|
|
m_host_interface, std::move(section_name), std::move(key_name), axis_type, ui->bindings_container);
|
2020-02-17 15:06:28 +00:00
|
|
|
layout->addWidget(label, start_row + current_row, current_column);
|
|
|
|
layout->addWidget(button, start_row + current_row, current_column + 1);
|
|
|
|
|
2020-03-21 14:50:09 +00:00
|
|
|
if (!first_button)
|
|
|
|
first_button = button;
|
|
|
|
if (last_button)
|
|
|
|
last_button->setNextWidget(button);
|
|
|
|
last_button = button;
|
|
|
|
|
2020-02-17 15:06:28 +00:00
|
|
|
current_row++;
|
|
|
|
}
|
|
|
|
|
|
|
|
start_row += num_rows;
|
2020-01-02 06:13:03 +00:00
|
|
|
}
|
|
|
|
|
2020-04-14 06:35:04 +00:00
|
|
|
const u32 num_motors = Controller::GetVibrationMotorCount(ctype);
|
|
|
|
if (num_motors > 0)
|
|
|
|
{
|
|
|
|
layout->addWidget(QtUtils::CreateHorizontalLine(ui->widget), start_row++, 0, 1, 4);
|
|
|
|
|
2020-07-21 09:49:04 +00:00
|
|
|
std::string section_name = StringUtil::StdStringFromFormat("Controller%d", index + 1);
|
2020-05-20 13:26:24 +00:00
|
|
|
QLabel* label = new QLabel(tr("Rumble"), ui->bindings_container);
|
|
|
|
InputRumbleBindingWidget* button =
|
2020-07-21 09:49:04 +00:00
|
|
|
new InputRumbleBindingWidget(m_host_interface, std::move(section_name), "Rumble", ui->bindings_container);
|
2020-04-14 06:35:04 +00:00
|
|
|
|
|
|
|
layout->addWidget(label, start_row, 0);
|
|
|
|
layout->addWidget(button, start_row, 1);
|
|
|
|
|
|
|
|
if (!first_button)
|
|
|
|
first_button = button;
|
|
|
|
if (last_button)
|
|
|
|
last_button->setNextWidget(button);
|
|
|
|
last_button = button;
|
|
|
|
|
|
|
|
start_row++;
|
|
|
|
}
|
|
|
|
|
2020-06-30 14:34:13 +00:00
|
|
|
const Controller::SettingList settings = Controller::GetSettings(ctype);
|
|
|
|
if (!settings.empty())
|
|
|
|
{
|
|
|
|
layout->addWidget(QtUtils::CreateHorizontalLine(ui->widget), start_row++, 0, 1, 4);
|
|
|
|
|
|
|
|
for (const SettingInfo& si : settings)
|
|
|
|
{
|
2020-07-21 09:49:04 +00:00
|
|
|
std::string section_name = StringUtil::StdStringFromFormat("Controller%d", index + 1);
|
|
|
|
std::string key_name = si.key;
|
2020-08-23 12:47:49 +00:00
|
|
|
const QString setting_tooltip = si.description ? qApp->translate(cname, si.description) : QString();
|
2020-06-30 14:34:13 +00:00
|
|
|
|
|
|
|
switch (si.type)
|
|
|
|
{
|
|
|
|
case SettingInfo::Type::Boolean:
|
|
|
|
{
|
2020-08-23 12:47:49 +00:00
|
|
|
QCheckBox* cb = new QCheckBox(qApp->translate(cname, si.visible_name), ui->bindings_container);
|
2020-06-30 14:34:13 +00:00
|
|
|
cb->setToolTip(setting_tooltip);
|
2020-07-21 09:49:04 +00:00
|
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, cb, std::move(section_name),
|
|
|
|
std::move(key_name), si.BooleanDefaultValue());
|
2020-06-30 14:34:13 +00:00
|
|
|
layout->addWidget(cb, start_row, 0, 1, 4);
|
|
|
|
start_row++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SettingInfo::Type::Integer:
|
|
|
|
{
|
|
|
|
QSpinBox* sb = new QSpinBox(ui->bindings_container);
|
|
|
|
sb->setToolTip(setting_tooltip);
|
|
|
|
sb->setMinimum(si.IntegerMinValue());
|
|
|
|
sb->setMaximum(si.IntegerMaxValue());
|
|
|
|
sb->setSingleStep(si.IntegerStepValue());
|
2020-07-21 09:49:04 +00:00
|
|
|
SettingWidgetBinder::BindWidgetToIntSetting(m_host_interface, sb, std::move(section_name),
|
|
|
|
std::move(key_name), si.IntegerDefaultValue());
|
2020-08-23 12:47:49 +00:00
|
|
|
layout->addWidget(new QLabel(qApp->translate(cname, si.visible_name), ui->bindings_container), start_row, 0);
|
2020-06-30 14:34:13 +00:00
|
|
|
layout->addWidget(sb, start_row, 1, 1, 3);
|
|
|
|
start_row++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SettingInfo::Type::Float:
|
|
|
|
{
|
|
|
|
QDoubleSpinBox* sb = new QDoubleSpinBox(ui->bindings_container);
|
|
|
|
sb->setToolTip(setting_tooltip);
|
|
|
|
sb->setMinimum(si.FloatMinValue());
|
|
|
|
sb->setMaximum(si.FloatMaxValue());
|
|
|
|
sb->setSingleStep(si.FloatStepValue());
|
2020-07-21 09:49:04 +00:00
|
|
|
SettingWidgetBinder::BindWidgetToFloatSetting(m_host_interface, sb, std::move(section_name),
|
|
|
|
std::move(key_name), si.FloatDefaultValue());
|
2020-08-23 12:47:49 +00:00
|
|
|
layout->addWidget(new QLabel(qApp->translate(cname, si.visible_name), ui->bindings_container), start_row, 0);
|
2020-06-30 14:34:13 +00:00
|
|
|
layout->addWidget(sb, start_row, 1, 1, 3);
|
|
|
|
start_row++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SettingInfo::Type::String:
|
|
|
|
{
|
|
|
|
QLineEdit* le = new QLineEdit(ui->bindings_container);
|
|
|
|
le->setToolTip(setting_tooltip);
|
2020-07-21 09:49:04 +00:00
|
|
|
SettingWidgetBinder::BindWidgetToStringSetting(m_host_interface, le, std::move(section_name),
|
|
|
|
std::move(key_name), si.StringDefaultValue());
|
2020-08-23 12:47:49 +00:00
|
|
|
layout->addWidget(new QLabel(qApp->translate(cname, si.visible_name), ui->bindings_container), start_row, 0);
|
2020-06-30 14:34:13 +00:00
|
|
|
layout->addWidget(le, start_row, 1, 1, 3);
|
|
|
|
start_row++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SettingInfo::Type::Path:
|
|
|
|
{
|
|
|
|
QLineEdit* le = new QLineEdit(ui->bindings_container);
|
|
|
|
le->setToolTip(setting_tooltip);
|
|
|
|
QPushButton* browse_button = new QPushButton(tr("Browse..."), ui->bindings_container);
|
2020-07-21 09:49:04 +00:00
|
|
|
SettingWidgetBinder::BindWidgetToStringSetting(m_host_interface, le, std::move(section_name),
|
|
|
|
std::move(key_name), si.StringDefaultValue());
|
2020-07-13 16:24:11 +00:00
|
|
|
connect(browse_button, &QPushButton::clicked, [this, le]() {
|
2020-06-30 14:34:13 +00:00
|
|
|
QString path = QFileDialog::getOpenFileName(this, tr("Select File"));
|
|
|
|
if (!path.isEmpty())
|
|
|
|
le->setText(path);
|
|
|
|
});
|
|
|
|
|
|
|
|
QHBoxLayout* hbox = new QHBoxLayout();
|
|
|
|
hbox->addWidget(le, 1);
|
|
|
|
hbox->addWidget(browse_button);
|
|
|
|
|
2020-08-23 12:47:49 +00:00
|
|
|
layout->addWidget(new QLabel(qApp->translate(cname, si.visible_name), ui->bindings_container), start_row, 0);
|
2020-06-30 14:34:13 +00:00
|
|
|
layout->addLayout(hbox, start_row, 1, 1, 3);
|
|
|
|
start_row++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-15 17:25:15 +00:00
|
|
|
// turbo/autofire
|
2021-06-09 02:32:28 +00:00
|
|
|
if (ctype != ControllerType::None)
|
2021-05-15 17:25:15 +00:00
|
|
|
{
|
|
|
|
layout->addWidget(QtUtils::CreateHorizontalLine(ui->widget), start_row++, 0, 1, 4);
|
|
|
|
|
|
|
|
CollapsibleWidget* collapsible = new CollapsibleWidget(tr("Auto Fire Buttons"), 100, ui->bindings_container);
|
|
|
|
QGridLayout* autofire_layout = new QGridLayout();
|
|
|
|
autofire_layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
2021-05-18 09:20:47 +00:00
|
|
|
QVector<QPair<QString, QVariant>> option_list;
|
|
|
|
option_list.push_back({});
|
2021-05-15 17:25:15 +00:00
|
|
|
for (const auto& [button_name, button_code] : buttons)
|
2021-05-18 09:20:47 +00:00
|
|
|
option_list.push_back({qApp->translate(cname, button_name.c_str()), QString::fromStdString(button_name)});
|
2021-05-15 17:25:15 +00:00
|
|
|
|
|
|
|
for (u32 autofire_index = 0; autofire_index < QtHostInterface::NUM_CONTROLLER_AUTOFIRE_BUTTONS; autofire_index++)
|
|
|
|
{
|
|
|
|
std::string section_name = StringUtil::StdStringFromFormat("Controller%d", index + 1);
|
|
|
|
autofire_layout->addWidget(new QLabel(tr("Auto Fire %1").arg(autofire_index + 1), collapsible), autofire_index,
|
|
|
|
0);
|
|
|
|
QComboBox* button_cb = new QComboBox(collapsible);
|
2021-05-18 09:20:47 +00:00
|
|
|
for (const auto& it : option_list)
|
|
|
|
button_cb->addItem(it.first, it.second);
|
2021-05-15 17:25:15 +00:00
|
|
|
autofire_layout->addWidget(button_cb, autofire_index, 1);
|
|
|
|
SettingWidgetBinder::BindWidgetToStringSetting(
|
|
|
|
m_host_interface, button_cb, section_name,
|
|
|
|
StringUtil::StdStringFromFormat("AutoFire%uButton", autofire_index + 1));
|
|
|
|
|
|
|
|
InputButtonBindingWidget* binding_button = new InputButtonBindingWidget(
|
|
|
|
m_host_interface, section_name, StringUtil::StdStringFromFormat("AutoFire%u", autofire_index + 1), collapsible);
|
|
|
|
autofire_layout->addWidget(binding_button, autofire_index, 2);
|
|
|
|
|
|
|
|
QSpinBox* frequency = new QSpinBox(collapsible);
|
|
|
|
frequency->setMinimum(1);
|
|
|
|
frequency->setMaximum(255);
|
|
|
|
frequency->setSuffix(tr(" Frames"));
|
|
|
|
autofire_layout->addWidget(frequency, autofire_index, 3);
|
|
|
|
SettingWidgetBinder::BindWidgetToIntSetting(
|
|
|
|
m_host_interface, frequency, std::move(section_name),
|
|
|
|
StringUtil::StdStringFromFormat("AutoFire%uFrequency", autofire_index + 1),
|
|
|
|
QtHostInterface::DEFAULT_AUTOFIRE_FREQUENCY);
|
|
|
|
}
|
|
|
|
|
|
|
|
collapsible->getScrollArea()->setFrameStyle(QFrame::NoFrame);
|
|
|
|
collapsible->setContentLayout(autofire_layout);
|
|
|
|
layout->addWidget(collapsible, start_row, 0, 1, 4);
|
|
|
|
|
|
|
|
start_row++;
|
|
|
|
}
|
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
// dummy row to fill remaining space
|
|
|
|
layout->addWidget(new QWidget(ui->bindings_container), start_row, 0, 1, 4);
|
|
|
|
layout->setRowStretch(start_row, 1);
|
2020-03-21 14:50:09 +00:00
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
ui->bindings_scroll_area->setWidget(ui->bindings_container);
|
2020-04-14 15:44:16 +00:00
|
|
|
ui->first_button = first_button;
|
2020-01-02 06:13:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
void ControllerSettingsWidget::onControllerTypeChanged(int index)
|
2020-01-02 06:13:03 +00:00
|
|
|
{
|
|
|
|
const int type_index = m_port_ui[index].controller_type->currentIndex();
|
|
|
|
if (type_index < 0 || type_index >= static_cast<int>(ControllerType::Count))
|
|
|
|
return;
|
|
|
|
|
2020-07-21 09:49:04 +00:00
|
|
|
m_host_interface->SetStringSettingValue(TinyString::FromFormat("Controller%d", index + 1), "Type",
|
|
|
|
Settings::GetControllerTypeName(static_cast<ControllerType>(type_index)));
|
2020-07-13 16:24:11 +00:00
|
|
|
|
2020-01-24 04:49:49 +00:00
|
|
|
m_host_interface->applySettings();
|
|
|
|
createPortBindingSettingsUi(index, &m_port_ui[index], static_cast<ControllerType>(type_index));
|
2020-01-02 06:13:03 +00:00
|
|
|
}
|
2020-04-08 14:09:16 +00:00
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
void ControllerSettingsWidget::onLoadProfileClicked()
|
2020-04-14 15:44:16 +00:00
|
|
|
{
|
|
|
|
const auto profile_names = m_host_interface->getInputProfileList();
|
|
|
|
|
|
|
|
QMenu menu;
|
|
|
|
|
|
|
|
QAction* browse = menu.addAction(tr("Browse..."));
|
|
|
|
connect(browse, &QAction::triggered, [this]() {
|
|
|
|
QString path =
|
|
|
|
QFileDialog::getOpenFileName(this, tr("Select path to input profile ini"), QString(), tr(INPUT_PROFILE_FILTER));
|
|
|
|
if (!path.isEmpty())
|
|
|
|
m_host_interface->applyInputProfile(path);
|
|
|
|
});
|
|
|
|
|
2020-04-26 15:05:01 +00:00
|
|
|
if (!profile_names.empty())
|
|
|
|
menu.addSeparator();
|
|
|
|
|
|
|
|
for (const auto& [name, path] : profile_names)
|
|
|
|
{
|
|
|
|
QAction* action = menu.addAction(QString::fromStdString(name));
|
|
|
|
QString path_qstr = QString::fromStdString(path);
|
|
|
|
connect(action, &QAction::triggered, [this, path_qstr]() { m_host_interface->applyInputProfile(path_qstr); });
|
|
|
|
}
|
|
|
|
|
2020-04-14 15:44:16 +00:00
|
|
|
menu.exec(QCursor::pos());
|
|
|
|
}
|
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
void ControllerSettingsWidget::onSaveProfileClicked()
|
2020-04-14 15:44:16 +00:00
|
|
|
{
|
|
|
|
const auto profile_names = m_host_interface->getInputProfileList();
|
|
|
|
|
|
|
|
QMenu menu;
|
2020-04-26 15:05:01 +00:00
|
|
|
|
|
|
|
QAction* new_action = menu.addAction(tr("New..."));
|
|
|
|
connect(new_action, &QAction::triggered, [this]() {
|
|
|
|
QString name = QInputDialog::getText(QtUtils::GetRootWidget(this), tr("Enter Input Profile Name"),
|
|
|
|
tr("Enter Input Profile Name"));
|
|
|
|
if (name.isEmpty())
|
|
|
|
{
|
|
|
|
QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Error"),
|
|
|
|
tr("No name entered, input profile was not saved."));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-11 16:47:39 +00:00
|
|
|
m_host_interface->saveInputProfile(m_host_interface->getSavePathForInputProfile(name));
|
2020-04-26 15:05:01 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
QAction* browse = menu.addAction(tr("Browse..."));
|
|
|
|
connect(browse, &QAction::triggered, [this]() {
|
|
|
|
QString path = QFileDialog::getSaveFileName(QtUtils::GetRootWidget(this), tr("Select path to input profile ini"),
|
|
|
|
QString(), tr(INPUT_PROFILE_FILTER));
|
|
|
|
if (path.isEmpty())
|
|
|
|
{
|
|
|
|
QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Error"),
|
|
|
|
tr("No path selected, input profile was not saved."));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_host_interface->saveInputProfile(path);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!profile_names.empty())
|
|
|
|
menu.addSeparator();
|
|
|
|
|
2020-04-14 15:44:16 +00:00
|
|
|
for (const auto& [name, path] : profile_names)
|
|
|
|
{
|
|
|
|
QAction* action = menu.addAction(QString::fromStdString(name));
|
|
|
|
QString path_qstr = QString::fromStdString(path);
|
|
|
|
connect(action, &QAction::triggered, [this, path_qstr]() { m_host_interface->saveInputProfile(path_qstr); });
|
|
|
|
}
|
|
|
|
|
|
|
|
menu.exec(QCursor::pos());
|
|
|
|
}
|