Qt: Improve controller settings and add macro UI

This commit is contained in:
Connor McLaughlin 2022-08-05 23:52:16 +10:00 committed by refractionpcsx2
parent 6f40cf9beb
commit 9a7ed81759
19 changed files with 1160 additions and 246 deletions

View File

@ -56,6 +56,8 @@ target_sources(pcsx2-qt PRIVATE
Settings/ControllerGlobalSettingsWidget.cpp
Settings/ControllerGlobalSettingsWidget.h
Settings/ControllerGlobalSettingsWidget.ui
Settings/ControllerMacroEditWidget.ui
Settings/ControllerMacroWidget.ui
Settings/ControllerSettingsDialog.cpp
Settings/ControllerSettingsDialog.h
Settings/ControllerSettingsDialog.ui

View File

@ -7,13 +7,13 @@
<x>0</x>
<y>0</y>
<width>833</width>
<height>560</height>
<height>617</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
<property name="leftMargin">
<number>0</number>
</property>
@ -31,9 +31,73 @@
<property name="title">
<string>Controller Type</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QComboBox" name="controllerType"/>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="controllerType"/>
</item>
<item>
<widget class="QToolButton" name="bindings">
<property name="text">
<string>Bindings</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset theme="gamepad-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="settings">
<property name="text">
<string>Settings</string>
</property>
<property name="icon">
<iconset theme="checkbox-multiple-blank-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="macros">
<property name="text">
<string>Macros</string>
</property>
<property name="icon">
<iconset theme="flashlight-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
@ -51,25 +115,31 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="automaticBinding">
<widget class="QToolButton" name="automaticBinding">
<property name="text">
<string>Automatic binding</string>
<string>Automatic Mapping</string>
</property>
<property name="icon">
<iconset theme="gamepad-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearBindings">
<widget class="QToolButton" name="clearBindings">
<property name="text">
<string>Clear Bindings</string>
<string>Clear Mapping</string>
</property>
<property name="icon">
<iconset theme="file-reduce-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
</layout>
@ -77,6 +147,9 @@
</layout>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget" />
</item>
</layout>
</widget>
<resources>

View File

@ -415,25 +415,6 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="LargeMotorScale">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="suffix">
<string>x</string>
</property>
<property name="maximum">
<double>3.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -488,74 +469,6 @@
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QGroupBox" name="groupBox_25">
<property name="title">
<string>Select</string>
</property>
<layout class="QGridLayout" name="gridLayout_25">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="Select">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="2">
<widget class="QGroupBox" name="groupBox_26">
<property name="title">
<string>Start</string>
</property>
<layout class="QGridLayout" name="gridLayout_26">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="Start">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="3">
<widget class="QGroupBox" name="groupBox_23">
<property name="title">
@ -624,62 +537,6 @@
</layout>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QGroupBox" name="groupBox_34">
<property name="title">
<string>Pressure Modifier</string>
</property>
<layout class="QGridLayout" name="gridLayout_34">
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="PressureModifier">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="suffix">
<string>x</string>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.500000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="InputBindingWidget" name="Pressure">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="3">
<widget class="QGroupBox" name="groupBox_24">
<property name="title">
@ -714,6 +571,74 @@
</layout>
</widget>
</item>
<item row="1" column="2">
<widget class="QGroupBox" name="groupBox_26">
<property name="title">
<string>Start</string>
</property>
<layout class="QGridLayout" name="gridLayout_26">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="Start">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="groupBox_25">
<property name="title">
<string>Select</string>
</property>
<layout class="QGridLayout" name="gridLayout_25">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="Select">
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="0" column="2" rowspan="3">
@ -1093,19 +1018,6 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="SmallMotorScale">
<property name="suffix">
<string>x</string>
</property>
<property name="maximum">
<double>3.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -1181,6 +1093,19 @@
</item>
<item row="2" column="1">
<layout class="QGridLayout" name="gridLayout_32">
<item row="2" column="0" colspan="4">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox_27">
<property name="title">
@ -1221,19 +1146,6 @@
</layout>
</widget>
</item>
<item row="2" column="0" colspan="4">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="3">
<widget class="QGroupBox" name="groupBox_28">
<property name="title">
@ -1274,59 +1186,63 @@
</layout>
</widget>
</item>
<item row="1" column="2" colspan="2">
<widget class="QGroupBox" name="groupBox_30">
<item row="0" column="1">
<widget class="QGroupBox" name="groupBox_34">
<property name="title">
<string>Analog Sensitivity</string>
<string>Pressure Modifier</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QSlider" name="AxisScale">
<property name="maximum">
<number>200</number>
<layout class="QGridLayout" name="gridLayout_34">
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="PressureModifier">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
<property name="suffix">
<string>x</string>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.500000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="AxisScaleLabel">
<item row="0" column="0">
<widget class="InputBindingWidget" name="Pressure">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>100%</string>
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_33">
<property name="title">
<string>Analog Deadzone</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSlider" name="Deadzone">
<property name="maximum">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="DeadzoneLabel">
<property name="text">
<string>0%</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="1" colspan="2">
<item row="1" column="1">
<widget class="QGroupBox" name="groupBox_31">
<property name="title">
<string>Analog</string>
@ -1366,7 +1282,6 @@
</customwidgets>
<resources>
<include location="../resources/resources.qrc"/>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -15,6 +15,7 @@
#include "PrecompiledHeader.h"
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMenu>
#include <QtWidgets/QMessageBox>
#include <algorithm>
@ -45,15 +46,18 @@ ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSett
m_ui.controllerType, m_config_section, "Type", PAD::GetDefaultPadType(port));
connect(m_ui.controllerType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ControllerBindingWidget::onTypeChanged);
connect(m_ui.automaticBinding, &QPushButton::clicked, this, &ControllerBindingWidget::doAutomaticBinding);
connect(m_ui.clearBindings, &QPushButton::clicked, this, &ControllerBindingWidget::doClearBindings);
connect(m_ui.bindings, &QPushButton::clicked, this, &ControllerBindingWidget::onBindingsClicked);
connect(m_ui.settings, &QPushButton::clicked, this, &ControllerBindingWidget::onSettingsClicked);
connect(m_ui.macros, &QPushButton::clicked, this, &ControllerBindingWidget::onMacrosClicked);
connect(m_ui.automaticBinding, &QPushButton::clicked, this, &ControllerBindingWidget::onAutomaticBindingClicked);
connect(m_ui.clearBindings, &QPushButton::clicked, this, &ControllerBindingWidget::onClearBindingsClicked);
}
ControllerBindingWidget::~ControllerBindingWidget() = default;
QIcon ControllerBindingWidget::getIcon() const
{
return m_current_widget->getIcon();
return m_bindings_widget->getIcon();
}
void ControllerBindingWidget::populateControllerTypes()
@ -64,36 +68,101 @@ void ControllerBindingWidget::populateControllerTypes()
void ControllerBindingWidget::onTypeChanged()
{
const bool is_initializing = (m_current_widget == nullptr);
const bool is_initializing = (m_ui.stackedWidget->count() == 0);
m_controller_type = m_dialog->getStringValue(m_config_section.c_str(), "Type", PAD::GetDefaultPadType(m_port_number));
if (!is_initializing)
if (m_bindings_widget)
{
m_ui.verticalLayout->removeWidget(m_current_widget);
delete m_current_widget;
m_current_widget = nullptr;
m_ui.stackedWidget->removeWidget(m_bindings_widget);
delete m_bindings_widget;
m_bindings_widget = nullptr;
}
if (m_settings_widget)
{
m_ui.stackedWidget->removeWidget(m_settings_widget);
delete m_settings_widget;
m_settings_widget = nullptr;
}
if (m_macros_widget)
{
m_ui.stackedWidget->removeWidget(m_macros_widget);
delete m_macros_widget;
m_macros_widget = nullptr;
}
const int index = m_ui.controllerType->findData(QString::fromStdString(m_controller_type));
if (index >= 0 && index != m_ui.controllerType->currentIndex())
{
QSignalBlocker sb(m_ui.controllerType);
m_ui.controllerType->setCurrentIndex(index);
}
const PAD::ControllerInfo* cinfo = PAD::GetControllerInfo(m_controller_type);
const bool has_settings = (cinfo && cinfo->num_settings > 0);
const bool has_macros = (cinfo && cinfo->num_bindings > 0);
m_ui.settings->setEnabled(has_settings);
m_ui.macros->setEnabled(has_macros);
if (m_controller_type == "DualShock2")
m_current_widget = ControllerBindingWidget_DualShock2::createInstance(this);
m_bindings_widget = ControllerBindingWidget_DualShock2::createInstance(this);
else
m_current_widget = new ControllerBindingWidget_Base(this);
m_bindings_widget = new ControllerBindingWidget_Base(this);
m_ui.verticalLayout->addWidget(m_current_widget, 1);
m_ui.stackedWidget->addWidget(m_bindings_widget);
m_ui.stackedWidget->setCurrentWidget(m_bindings_widget);
if (has_settings)
{
m_settings_widget = new ControllerCustomSettingsWidget(this, m_ui.stackedWidget);
m_ui.stackedWidget->addWidget(m_settings_widget);
}
if (has_macros)
{
m_macros_widget = new ControllerMacroWidget(this);
m_ui.stackedWidget->addWidget(m_macros_widget);
}
updateHeaderToolButtons();
// no need to do this on first init, only changes
if (!is_initializing)
m_dialog->updateListDescription(m_port_number, this);
}
void ControllerBindingWidget::doAutomaticBinding()
void ControllerBindingWidget::updateHeaderToolButtons()
{
const QWidget* current_widget = m_ui.stackedWidget->currentWidget();
const QSignalBlocker bindings_sb(m_ui.bindings);
const QSignalBlocker settings_sb(m_ui.settings);
const QSignalBlocker macros_sb(m_ui.macros);
const bool is_bindings = (current_widget == m_bindings_widget);
m_ui.bindings->setChecked(is_bindings);
m_ui.automaticBinding->setEnabled(is_bindings);
m_ui.clearBindings->setEnabled(is_bindings);
m_ui.macros->setChecked(current_widget == m_macros_widget);
m_ui.settings->setChecked((current_widget == m_settings_widget));
}
void ControllerBindingWidget::onBindingsClicked()
{
m_ui.stackedWidget->setCurrentWidget(m_bindings_widget);
updateHeaderToolButtons();
}
void ControllerBindingWidget::onSettingsClicked()
{
if (!m_settings_widget)
return;
m_ui.stackedWidget->setCurrentWidget(m_settings_widget);
updateHeaderToolButtons();
}
void ControllerBindingWidget::onMacrosClicked()
{
if (!m_macros_widget)
return;
m_ui.stackedWidget->setCurrentWidget(m_macros_widget);
updateHeaderToolButtons();
}
void ControllerBindingWidget::onAutomaticBindingClicked()
{
QMenu menu(this);
bool added = false;
@ -118,7 +187,7 @@ void ControllerBindingWidget::doAutomaticBinding()
menu.exec(QCursor::pos());
}
void ControllerBindingWidget::doClearBindings()
void ControllerBindingWidget::onClearBindingsClicked()
{
if (QMessageBox::question(QtUtils::GetRootWidget(this), tr("Clear Bindings"),
tr("Are you sure you want to clear all bindings for this controller? This action cannot be undone.")) != QMessageBox::Yes)
@ -174,6 +243,388 @@ void ControllerBindingWidget::saveAndRefresh()
g_emu_thread->applySettings();
}
//////////////////////////////////////////////////////////////////////////
ControllerMacroWidget::ControllerMacroWidget(ControllerBindingWidget* parent)
: QWidget(parent)
{
m_ui.setupUi(this);
setWindowTitle(tr("Controller Port %1 Macros").arg(parent->getPortNumber() + 1u));
createWidgets(parent);
}
ControllerMacroWidget::~ControllerMacroWidget() = default;
void ControllerMacroWidget::updateListItem(u32 index)
{
m_ui.portList->item(static_cast<int>(index))
->setText(tr("Macro %1\n%2").arg(index + 1).arg(m_macros[index]->getSummary()));
}
void ControllerMacroWidget::createWidgets(ControllerBindingWidget* parent)
{
for (u32 i = 0; i < NUM_MACROS; i++)
{
m_macros[i] = new ControllerMacroEditWidget(this, parent, i);
m_ui.container->addWidget(m_macros[i]);
QListWidgetItem* item = new QListWidgetItem();
item->setIcon(QIcon::fromTheme(QStringLiteral("flashlight-line")));
m_ui.portList->addItem(item);
updateListItem(i);
}
m_ui.portList->setCurrentRow(0);
m_ui.container->setCurrentIndex(0);
connect(m_ui.portList, &QListWidget::currentRowChanged, m_ui.container, &QStackedWidget::setCurrentIndex);
}
//////////////////////////////////////////////////////////////////////////
ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* parent, ControllerBindingWidget* bwidget,
u32 index)
: QWidget(parent)
, m_parent(parent)
, m_bwidget(bwidget)
, m_index(index)
{
m_ui.setupUi(this);
ControllerSettingsDialog* dialog = m_bwidget->getDialog();
const std::string& section = m_bwidget->getConfigSection();
const PAD::ControllerInfo* cinfo = PAD::GetControllerInfo(m_bwidget->getControllerType());
if (!cinfo)
{
// Shouldn't ever happen.
return;
}
// load binds (single string joined by &)
const std::string binds_string(
dialog->getStringValue(section.c_str(), fmt::format("Macro{}Binds", index + 1u).c_str(), ""));
const std::vector<std::string_view> buttons_split(StringUtil::SplitString(binds_string, '&', true));
for (const std::string_view& button : buttons_split)
{
for (u32 i = 0; i < cinfo->num_bindings; i++)
{
if (button == cinfo->bindings[i].name)
{
m_binds.push_back(&cinfo->bindings[i]);
break;
}
}
}
// populate list view
for (u32 i = 0; i < cinfo->num_bindings; i++)
{
const PAD::ControllerBindingInfo& bi = cinfo->bindings[i];
if (bi.type == PAD::ControllerBindingType::Motor)
continue;
QListWidgetItem* item = new QListWidgetItem();
item->setText(QString::fromUtf8(bi.display_name));
item->setCheckState((std::find(m_binds.begin(), m_binds.end(), &bi) != m_binds.end()) ? Qt::Checked :
Qt::Unchecked);
m_ui.bindList->addItem(item);
}
m_frequency = dialog->getIntValue(section.c_str(), fmt::format("Macro{}Frequency", index + 1u).c_str(), 0);
updateFrequencyText();
m_ui.trigger->initialize(dialog->getProfileSettingsInterface(), section, fmt::format("Macro{}", index + 1u));
connect(m_ui.increaseFrequency, &QAbstractButton::clicked, this, [this]() { modFrequency(1); });
connect(m_ui.decreateFrequency, &QAbstractButton::clicked, this, [this]() { modFrequency(-1); });
connect(m_ui.setFrequency, &QAbstractButton::clicked, this, &ControllerMacroEditWidget::onSetFrequencyClicked);
connect(m_ui.bindList, &QListWidget::itemChanged, this, &ControllerMacroEditWidget::updateBinds);
}
ControllerMacroEditWidget::~ControllerMacroEditWidget() = default;
QString ControllerMacroEditWidget::getSummary() const
{
QString str;
for (const PAD::ControllerBindingInfo* bi : m_binds)
{
if (!str.isEmpty())
str += static_cast<QChar>('/');
str += QString::fromUtf8(bi->name);
}
return str.isEmpty() ? tr("Not Configured") : str;
}
void ControllerMacroEditWidget::onSetFrequencyClicked()
{
bool okay;
int new_freq = QInputDialog::getInt(this, tr("Set Frequency"), tr("Frequency: "), static_cast<int>(m_frequency), 0,
std::numeric_limits<int>::max(), 1, &okay);
if (!okay)
return;
m_frequency = static_cast<u32>(new_freq);
updateFrequency();
}
void ControllerMacroEditWidget::modFrequency(s32 delta)
{
if (delta < 0 && m_frequency == 0)
return;
m_frequency = static_cast<u32>(static_cast<s32>(m_frequency) + delta);
updateFrequency();
}
void ControllerMacroEditWidget::updateFrequency()
{
m_bwidget->getDialog()->setIntValue(m_bwidget->getConfigSection().c_str(),
fmt::format("Macro{}Frequency", m_index + 1u).c_str(),
static_cast<s32>(m_frequency));
updateFrequencyText();
}
void ControllerMacroEditWidget::updateFrequencyText()
{
if (m_frequency == 0)
m_ui.frequencyText->setText(tr("Macro will not repeat."));
else
m_ui.frequencyText->setText(tr("Macro will toggle buttons every %1 frames.").arg(m_frequency));
}
void ControllerMacroEditWidget::updateBinds()
{
ControllerSettingsDialog* dialog = m_bwidget->getDialog();
const PAD::ControllerInfo* cinfo = PAD::GetControllerInfo(m_bwidget->getControllerType());
if (!cinfo)
return;
std::vector<const PAD::ControllerBindingInfo*> new_binds;
for (u32 i = 0, bind_index = 0; i < cinfo->num_bindings; i++)
{
const PAD::ControllerBindingInfo& bi = cinfo->bindings[i];
if (bi.type == PAD::ControllerBindingType::Motor)
continue;
const QListWidgetItem* item = m_ui.bindList->item(static_cast<int>(bind_index));
bind_index++;
if (!item)
{
// shouldn't happen
continue;
}
if (item->checkState() == Qt::Checked)
new_binds.push_back(&bi);
}
if (m_binds == new_binds)
return;
m_binds = std::move(new_binds);
std::string binds_string;
for (const PAD::ControllerBindingInfo* bi : m_binds)
{
if (!binds_string.empty())
binds_string.append(" & ");
binds_string.append(bi->name);
}
const std::string& section = m_bwidget->getConfigSection();
const std::string key(fmt::format("Macro{}Binds", m_index + 1u));
if (binds_string.empty())
dialog->clearSettingValue(section.c_str(), key.c_str());
else
dialog->setStringValue(section.c_str(), key.c_str(), binds_string.c_str());
m_parent->updateListItem(m_index);
}
//////////////////////////////////////////////////////////////////////////
ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(ControllerBindingWidget* parent, QWidget* parent_widget)
: QWidget(parent_widget)
, m_parent(parent)
{
const PAD::ControllerInfo* cinfo = PAD::GetControllerInfo(parent->getControllerType());
if (!cinfo || cinfo->num_settings == 0)
return;
QGroupBox* gbox = new QGroupBox(tr("%1 Settings").arg(qApp->translate("PAD", cinfo->display_name)), this);
QGridLayout* gbox_layout = new QGridLayout(gbox);
createSettingWidgets(parent, gbox, gbox_layout, cinfo);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(gbox);
QHBoxLayout* bottom_hlayout = new QHBoxLayout();
QPushButton* restore_defaults = new QPushButton(tr("Restore Default Settings"), this);
restore_defaults->setIcon(QIcon::fromTheme(QStringLiteral("restart-line")));
connect(restore_defaults, &QPushButton::clicked, this, &ControllerCustomSettingsWidget::restoreDefaults);
bottom_hlayout->addStretch(1);
bottom_hlayout->addWidget(restore_defaults);
layout->addLayout(bottom_hlayout);
layout->addStretch(1);
}
ControllerCustomSettingsWidget::~ControllerCustomSettingsWidget() = default;
void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidget* parent, QWidget* widget_parent,
QGridLayout* layout, const PAD::ControllerInfo* cinfo)
{
const std::string& section = parent->getConfigSection();
SettingsInterface* sif = parent->getDialog()->getProfileSettingsInterface();
int current_row = 0;
for (u32 i = 0; i < cinfo->num_settings; i++)
{
const PAD::ControllerSettingInfo& si = cinfo->settings[i];
std::string key_name = si.key;
switch (si.type)
{
case PAD::ControllerSettingInfo::Type::Boolean:
{
QCheckBox* cb = new QCheckBox(qApp->translate(cinfo->name, si.visible_name), widget_parent);
cb->setObjectName(QString::fromUtf8(si.key));
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, cb, section, std::move(key_name),
si.BooleanDefaultValue());
layout->addWidget(cb, current_row, 0, 1, 4);
current_row++;
}
break;
case PAD::ControllerSettingInfo::Type::Integer:
{
QSpinBox* sb = new QSpinBox(widget_parent);
sb->setObjectName(QString::fromUtf8(si.key));
sb->setMinimum(si.IntegerMinValue());
sb->setMaximum(si.IntegerMaxValue());
sb->setSingleStep(si.IntegerStepValue());
SettingWidgetBinder::BindWidgetToIntSetting(sif, sb, section, std::move(key_name), si.IntegerDefaultValue());
layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.visible_name), widget_parent), current_row, 0);
layout->addWidget(sb, current_row, 1, 1, 3);
current_row++;
}
break;
case PAD::ControllerSettingInfo::Type::Float:
{
QDoubleSpinBox* sb = new QDoubleSpinBox(widget_parent);
sb->setObjectName(QString::fromUtf8(si.key));
sb->setMinimum(si.FloatMinValue());
sb->setMaximum(si.FloatMaxValue());
sb->setSingleStep(si.FloatStepValue());
SettingWidgetBinder::BindWidgetToFloatSetting(sif, sb, section, std::move(key_name), si.FloatDefaultValue());
layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.visible_name), widget_parent), current_row, 0);
layout->addWidget(sb, current_row, 1, 1, 3);
current_row++;
}
break;
case PAD::ControllerSettingInfo::Type::String:
{
QLineEdit* le = new QLineEdit(widget_parent);
le->setObjectName(QString::fromUtf8(si.key));
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, section, std::move(key_name), si.StringDefaultValue());
layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.visible_name), widget_parent), current_row, 0);
layout->addWidget(le, current_row, 1, 1, 3);
current_row++;
}
break;
case PAD::ControllerSettingInfo::Type::Path:
{
QLineEdit* le = new QLineEdit(widget_parent);
le->setObjectName(QString::fromUtf8(si.key));
QPushButton* browse_button = new QPushButton(tr("Browse..."), widget_parent);
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, section, std::move(key_name), si.StringDefaultValue());
connect(browse_button, &QPushButton::clicked, [this, le]() {
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);
layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.visible_name), widget_parent), current_row, 0);
layout->addLayout(hbox, current_row, 1, 1, 3);
current_row++;
}
break;
}
QLabel* label = new QLabel(si.description ? qApp->translate(cinfo->name, si.description) : QString(), widget_parent);
label->setWordWrap(true);
layout->addWidget(label, current_row++, 0, 1, 4);
layout->addItem(new QSpacerItem(1, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), current_row++, 0, 1, 4);
}
}
void ControllerCustomSettingsWidget::restoreDefaults()
{
const PAD::ControllerInfo* cinfo = PAD::GetControllerInfo(m_parent->getControllerType());
if (!cinfo || cinfo->num_settings == 0)
return;
for (u32 i = 0; i < cinfo->num_settings; i++)
{
const PAD::ControllerSettingInfo& si = cinfo->settings[i];
const QString key(QString::fromStdString(si.key));
switch (si.type)
{
case PAD::ControllerSettingInfo::Type::Boolean:
{
QCheckBox* widget = findChild<QCheckBox*>(QString::fromStdString(si.key));
if (widget)
widget->setChecked(si.BooleanDefaultValue());
}
break;
case PAD::ControllerSettingInfo::Type::Integer:
{
QSpinBox* widget = findChild<QSpinBox*>(QString::fromStdString(si.key));
if (widget)
widget->setValue(si.IntegerDefaultValue());
}
break;
case PAD::ControllerSettingInfo::Type::Float:
{
QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QString::fromStdString(si.key));
if (widget)
widget->setValue(si.FloatDefaultValue());
}
break;
case PAD::ControllerSettingInfo::Type::String:
{
QLineEdit* widget = findChild<QLineEdit*>(QString::fromStdString(si.key));
if (widget)
widget->setText(QString::fromUtf8(si.StringDefaultValue()));
}
break;
case PAD::ControllerSettingInfo::Type::Path:
{
QLineEdit* widget = findChild<QLineEdit*>(QString::fromStdString(si.key));
if (widget)
widget->setText(QString::fromUtf8(si.StringDefaultValue()));
}
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
ControllerBindingWidget_Base::ControllerBindingWidget_Base(ControllerBindingWidget* parent)

View File

@ -15,13 +15,20 @@
#pragma once
#include "PAD/Host/PAD.h"
#include <QtWidgets/QWidget>
#include "ui_ControllerBindingWidget.h"
#include "ui_ControllerBindingWidget_DualShock2.h"
#include "ui_ControllerMacroWidget.h"
#include "ui_ControllerMacroEditWidget.h"
class InputBindingWidget;
class ControllerSettingsDialog;
class ControllerCustomSettingsWidget;
class ControllerMacroWidget;
class ControllerMacroEditWidget;
class ControllerBindingWidget_Base;
class ControllerBindingWidget final : public QWidget
@ -41,11 +48,15 @@ public:
private Q_SLOTS:
void onTypeChanged();
void doAutomaticBinding();
void doClearBindings();
void onAutomaticBindingClicked();
void onClearBindingsClicked();
void onBindingsClicked();
void onSettingsClicked();
void onMacrosClicked();
private:
void populateControllerTypes();
void updateHeaderToolButtons();
void doDeviceAutomaticBinding(const QString& device);
void saveAndRefresh();
@ -57,9 +68,87 @@ private:
std::string m_controller_type;
u32 m_port_number;
ControllerBindingWidget_Base* m_current_widget = nullptr;
ControllerBindingWidget_Base* m_bindings_widget = nullptr;
ControllerCustomSettingsWidget* m_settings_widget = nullptr;
ControllerMacroWidget* m_macros_widget = nullptr;
};
//////////////////////////////////////////////////////////////////////////
class ControllerMacroWidget : public QWidget
{
Q_OBJECT
public:
ControllerMacroWidget(ControllerBindingWidget* parent);
~ControllerMacroWidget();
void updateListItem(u32 index);
private:
static constexpr u32 NUM_MACROS = PAD::NUM_MACRO_BUTTONS_PER_CONTROLLER;
void createWidgets(ControllerBindingWidget* parent);
Ui::ControllerMacroWidget m_ui;
ControllerSettingsDialog* m_dialog;
std::array<ControllerMacroEditWidget*, NUM_MACROS> m_macros;
};
//////////////////////////////////////////////////////////////////////////
class ControllerMacroEditWidget : public QWidget
{
Q_OBJECT
public:
ControllerMacroEditWidget(ControllerMacroWidget* parent, ControllerBindingWidget* bwidget, u32 index);
~ControllerMacroEditWidget();
QString getSummary() const;
private Q_SLOTS:
void onSetFrequencyClicked();
void updateBinds();
private:
void modFrequency(s32 delta);
void updateFrequency();
void updateFrequencyText();
Ui::ControllerMacroEditWidget m_ui;
ControllerMacroWidget* m_parent;
ControllerBindingWidget* m_bwidget;
u32 m_index;
std::vector<const PAD::ControllerBindingInfo*> m_binds;
u32 m_frequency = 0;
};
//////////////////////////////////////////////////////////////////////////
class ControllerCustomSettingsWidget : public QWidget
{
Q_OBJECT
public:
ControllerCustomSettingsWidget(ControllerBindingWidget* parent, QWidget* parent_widget);
~ControllerCustomSettingsWidget();
void createSettingWidgets(ControllerBindingWidget* parent, QWidget* widget_parent, QGridLayout* layout, const PAD::ControllerInfo* cinfo);
private Q_SLOTS:
void restoreDefaults();
private:
ControllerBindingWidget* m_parent;
};
//////////////////////////////////////////////////////////////////////////
class ControllerBindingWidget_Base : public QWidget
{
Q_OBJECT

View File

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ControllerMacroEditWidget</class>
<widget class="QWidget" name="ControllerMacroEditWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>595</width>
<height>473</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Binds/Buttons</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Select the buttons which you want to trigger with this macro. All buttons are activated concurrently.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QListWidget" name="bindList"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Trigger</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Select the trigger to activate this macro. This can be a single button, or combination of buttons (chord). Shift-click for multiple triggers.</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="InputBindingWidget" name="trigger">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Frequency</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0,0">
<item>
<widget class="QLabel" name="frequencyText">
<property name="text">
<string>Macro will toggle every N frames.</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="setFrequency">
<property name="text">
<string>Set...</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="increaseFrequency">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="arrowType">
<enum>Qt::UpArrow</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="decreateFrequency">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="arrowType">
<enum>Qt::DownArrow</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>InputBindingWidget</class>
<extends>QPushButton</extends>
<header>Settings/InputBindingWidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ControllerMacroWidget</class>
<widget class="QWidget" name="ControllerMacroWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>799</width>
<height>493</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QListWidget" name="portList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QStackedWidget" name="container"/>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -266,6 +266,14 @@ bool ControllerSettingsDialog::getBoolValue(const char* section, const char* key
return Host::GetBaseBoolSettingValue(section, key, default_value);
}
s32 ControllerSettingsDialog::getIntValue(const char* section, const char* key, s32 default_value) const
{
if (m_profile_interface)
return m_profile_interface->GetIntValue(section, key, default_value);
else
return Host::GetBaseIntSettingValue(section, key, default_value);
}
std::string ControllerSettingsDialog::getStringValue(const char* section, const char* key, const char* default_value) const
{
std::string value;
@ -291,6 +299,21 @@ void ControllerSettingsDialog::setBoolValue(const char* section, const char* key
}
}
void ControllerSettingsDialog::setIntValue(const char* section, const char* key, s32 value)
{
if (m_profile_interface)
{
m_profile_interface->SetIntValue(section, key, value);
m_profile_interface->Save();
g_emu_thread->reloadGameSettings();
}
else
{
QtHost::SetBaseIntSettingValue(section, key, value);
g_emu_thread->applySettings();
}
}
void ControllerSettingsDialog::setStringValue(const char* section, const char* key, const char* value)
{
if (m_profile_interface)
@ -301,7 +324,7 @@ void ControllerSettingsDialog::setStringValue(const char* section, const char* k
}
else
{
QtHost::SetBaseStringSettingValue(key, section, value);
QtHost::SetBaseStringSettingValue(section, key, value);
g_emu_thread->applySettings();
}
}

View File

@ -64,8 +64,10 @@ public:
// Helper functions for updating setting values globally or in the profile.
bool getBoolValue(const char* section, const char* key, bool default_value) const;
s32 getIntValue(const char* section, const char* key, s32 default_value) const;
std::string getStringValue(const char* section, const char* key, const char* default_value) const;
void setBoolValue(const char* section, const char* key, bool value);
void setIntValue(const char* section, const char* key, s32 value);
void setStringValue(const char* section, const char* key, const char* value);
void clearSettingValue(const char* section, const char* key);

View File

@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>1276</width>
<height>672</height>
<width>1300</width>
<height>680</height>
</rect>
</property>
<property name="sizePolicy">

View File

@ -335,6 +335,12 @@
</QtUi>
</ItemGroup>
<ItemGroup>
<QtUi Include="Settings\ControllerMacroEditWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\ControllerMacroWidget.ui">
<FileType>Document</FileType>
</QtUi>
<None Include="Settings\FolderSettingsWidget.ui" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -405,6 +405,12 @@
<QtUi Include="Tools\InputRecording\NewInputRecordingDlg.ui">
<Filter>Tools\Input Recording</Filter>
</QtUi>
<QtUi Include="Settings\ControllerMacroWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\ControllerMacroEditWidget.ui">
<Filter>Settings</Filter>
</QtUi>
</ItemGroup>
<ItemGroup>
<None Include="Settings\FolderSettingsWidget.ui">

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M7 7V3a1 1 0 0 1 1-1h13a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-4v3.993c0 .556-.449 1.007-1.007 1.007H3.007A1.006 1.006 0 0 1 2 20.993l.003-12.986C2.003 7.451 2.452 7 3.01 7H7zm2 0h6.993C16.549 7 17 7.449 17 8.007V15h3V4H9v3zM4.003 9L4 20h11V9H4.003z" fill="#000000"/></svg>

After

Width:  |  Height:  |  Size: 395 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M13 9h8L11 24v-9H4l9-15v9zm-2 2V7.22L7.532 13H13v4.394L17.263 11H11z" fill="#000000"/></svg>

After

Width:  |  Height:  |  Size: 221 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M7 7V3a1 1 0 0 1 1-1h13a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-4v3.993c0 .556-.449 1.007-1.007 1.007H3.007A1.006 1.006 0 0 1 2 20.993l.003-12.986C2.003 7.451 2.452 7 3.01 7H7zm2 0h6.993C16.549 7 17 7.449 17 8.007V15h3V4H9v3zM4.003 9L4 20h11V9H4.003z" fill="#ffffff"/></svg>

After

Width:  |  Height:  |  Size: 395 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M13 9h8L11 24v-9H4l9-15v9zm-2 2V7.22L7.532 13H13v4.394L17.263 11H11z" fill="#ffffff"/></svg>

After

Width:  |  Height:  |  Size: 221 B

View File

@ -7,6 +7,7 @@
<file>icons/black/svg/artboard-2-line.svg</file>
<file>icons/black/svg/book-open-line.svg</file>
<file>icons/black/svg/brush-line.svg</file>
<file>icons/black/svg/checkbox-multiple-blank-line.svg</file>
<file>icons/black/svg/close-line.svg</file>
<file>icons/black/svg/dashboard-line.svg</file>
<file>icons/black/svg/disc-line.svg</file>
@ -21,6 +22,7 @@
<file>icons/black/svg/file-search-line.svg</file>
<file>icons/black/svg/file-settings-line.svg</file>
<file>icons/black/svg/filter-line.svg</file>
<file>icons/black/svg/flashlight-line.svg</file>
<file>icons/black/svg/flask-line.svg</file>
<file>icons/black/svg/folder-add-line.svg</file>
<file>icons/black/svg/folder-open-line.svg</file>
@ -59,6 +61,7 @@
<file>icons/white/svg/artboard-2-line.svg</file>
<file>icons/white/svg/book-open-line.svg</file>
<file>icons/white/svg/brush-line.svg</file>
<file>icons/white/svg/checkbox-multiple-blank-line.svg</file>
<file>icons/white/svg/close-line.svg</file>
<file>icons/white/svg/dashboard-line.svg</file>
<file>icons/white/svg/disc-line.svg</file>
@ -73,6 +76,7 @@
<file>icons/white/svg/file-search-line.svg</file>
<file>icons/white/svg/file-settings-line.svg</file>
<file>icons/white/svg/filter-line.svg</file>
<file>icons/white/svg/flashlight-line.svg</file>
<file>icons/white/svg/flask-line.svg</file>
<file>icons/white/svg/folder-add-line.svg</file>
<file>icons/white/svg/folder-open-line.svg</file>

View File

@ -183,6 +183,62 @@ u8 PADpoll(u8 value)
return pad_poll(value);
}
const char* PAD::ControllerSettingInfo::StringDefaultValue() const
{
return default_value ? default_value : "";
}
bool PAD::ControllerSettingInfo::BooleanDefaultValue() const
{
return default_value ? StringUtil::FromChars<bool>(default_value).value_or(false) : false;
}
s32 PAD::ControllerSettingInfo::IntegerDefaultValue() const
{
return default_value ? StringUtil::FromChars<s32>(default_value).value_or(0) : 0;
}
s32 PAD::ControllerSettingInfo::IntegerMinValue() const
{
static constexpr s32 fallback_value = std::numeric_limits<s32>::min();
return min_value ? StringUtil::FromChars<s32>(min_value).value_or(fallback_value) : fallback_value;
}
s32 PAD::ControllerSettingInfo::IntegerMaxValue() const
{
static constexpr s32 fallback_value = std::numeric_limits<s32>::max();
return max_value ? StringUtil::FromChars<s32>(max_value).value_or(fallback_value) : fallback_value;
}
s32 PAD::ControllerSettingInfo::IntegerStepValue() const
{
static constexpr s32 fallback_value = 1;
return step_value ? StringUtil::FromChars<s32>(step_value).value_or(fallback_value) : fallback_value;
}
float PAD::ControllerSettingInfo::FloatDefaultValue() const
{
return default_value ? StringUtil::FromChars<float>(default_value).value_or(0.0f) : 0.0f;
}
float PAD::ControllerSettingInfo::FloatMinValue() const
{
static constexpr float fallback_value = std::numeric_limits<float>::min();
return min_value ? StringUtil::FromChars<float>(min_value).value_or(fallback_value) : fallback_value;
}
float PAD::ControllerSettingInfo::FloatMaxValue() const
{
static constexpr float fallback_value = std::numeric_limits<float>::max();
return max_value ? StringUtil::FromChars<float>(max_value).value_or(fallback_value) : fallback_value;
}
float PAD::ControllerSettingInfo::FloatStepValue() const
{
static constexpr float fallback_value = 0.1f;
return step_value ? StringUtil::FromChars<float>(step_value).value_or(fallback_value) : fallback_value;
}
std::string PAD::GetConfigSection(u32 pad_index)
{
return fmt::format("Pad{}", pad_index + 1);
@ -350,9 +406,31 @@ static const PAD::ControllerBindingInfo s_dualshock2_binds[] = {
{"SmallMotor", "Small (High Frequency) Motor", PAD::ControllerBindingType::Motor, GenericInputBinding::SmallMotor},
};
static const PAD::ControllerSettingInfo s_dualshock2_settings[] = {
{PAD::ControllerSettingInfo::Type::Float, "Deadzone", "Analog Deadzone",
"Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored.",
"0.00", "0.00", "1.00", "0.01"},
{PAD::ControllerSettingInfo::Type::Float, "AxisScale", "Analog Sensitivity",
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent "
"controllers, e.g. DualShock 4, Xbox One Controller.",
"1.33", "0.01", "2.00", "0.01"},
{PAD::ControllerSettingInfo::Type::Float, "LargeMotorScale", "Large Motor Vibration Scale",
"Increases or decreases the intensity of low frequency vibration sent by the game.",
"1.00", "0.00", "2.00", "0.01"},
{PAD::ControllerSettingInfo::Type::Float, "SmallMotorScale", "Small Motor Vibration Scale",
"Increases or decreases the intensity of high frequency vibration sent by the game.",
"1.00", "0.00", "2.00", "0.01"},
};
static const PAD::ControllerInfo s_controller_info[] = {
{"None", "Not Connected", nullptr, 0, PAD::ControllerType::NotConnected, PAD::VibrationCapabilities::NoVibration},
{"DualShock2", "DualShock 2", s_dualshock2_binds, std::size(s_dualshock2_binds), PAD::ControllerType::DualShock2, PAD::VibrationCapabilities::LargeSmallMotors},
{PAD::ControllerType::NotConnected, "None", "Not Connected",
nullptr, 0,
nullptr, 0,
PAD::VibrationCapabilities::NoVibration},
{PAD::ControllerType::DualShock2, "DualShock2", "DualShock 2",
s_dualshock2_binds, std::size(s_dualshock2_binds),
s_dualshock2_settings, std::size(s_dualshock2_settings),
PAD::VibrationCapabilities::LargeSmallMotors},
};
const PAD::ControllerInfo* PAD::GetControllerInfo(ControllerType type)

View File

@ -71,13 +71,48 @@ namespace PAD
GenericInputBinding generic_mapping;
};
struct ControllerSettingInfo
{
enum class Type
{
Boolean,
Integer,
Float,
String,
Path,
};
Type type;
const char* key;
const char* visible_name;
const char* description;
const char* default_value;
const char* min_value;
const char* max_value;
const char* step_value;
const char* StringDefaultValue() const;
bool BooleanDefaultValue() const;
s32 IntegerDefaultValue() const;
s32 IntegerMinValue() const;
s32 IntegerMaxValue() const;
s32 IntegerStepValue() const;
float FloatDefaultValue() const;
float FloatMinValue() const;
float FloatMaxValue() const;
float FloatStepValue() const;
};
struct ControllerInfo
{
ControllerType type;
const char* name;
const char* display_name;
const ControllerBindingInfo* bindings;
u32 num_bindings;
ControllerType type;
const ControllerSettingInfo* settings;
u32 num_settings;
PAD::VibrationCapabilities vibration_caps;
};