Merge pull request #10682 from jordan-woyak/gate-size-setting

ControllerEmu: Allow changing the target gate radius of octagon sticks.
This commit is contained in:
Admiral H. Curtiss 2022-06-28 02:43:30 +02:00 committed by GitHub
commit e8965c63e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 143 additions and 28 deletions

View File

@ -4,6 +4,7 @@
#include "DolphinQt/Config/Mapping/MappingWidget.h" #include "DolphinQt/Config/Mapping/MappingWidget.h"
#include <QCheckBox> #include <QCheckBox>
#include <QDialogButtonBox>
#include <QFormLayout> #include <QFormLayout>
#include <QGroupBox> #include <QGroupBox>
#include <QHBoxLayout> #include <QHBoxLayout>
@ -121,8 +122,54 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con
for (auto& control : group->controls) for (auto& control : group->controls)
CreateControl(control.get(), form_layout, !indicator); CreateControl(control.get(), form_layout, !indicator);
AddSettingWidgets(form_layout, group, ControllerEmu::SettingVisibility::Normal);
if (group->default_value != ControllerEmu::ControlGroup::DefaultValue::AlwaysEnabled)
{
QLabel* group_enable_label = new QLabel(tr("Enable"));
QCheckBox* group_enable_checkbox = new QCheckBox();
group_enable_checkbox->setChecked(group->enabled);
form_layout->insertRow(0, group_enable_label, group_enable_checkbox);
auto enable_group_by_checkbox = [group, form_layout, group_enable_label,
group_enable_checkbox] {
group->enabled = group_enable_checkbox->isChecked();
for (int i = 0; i < form_layout->count(); ++i)
{
QWidget* widget = form_layout->itemAt(i)->widget();
if (widget != nullptr && widget != group_enable_label && widget != group_enable_checkbox)
widget->setEnabled(group->enabled);
}
};
enable_group_by_checkbox();
connect(group_enable_checkbox, &QCheckBox::toggled, this, enable_group_by_checkbox);
connect(this, &MappingWidget::ConfigChanged, this,
[group_enable_checkbox, group] { group_enable_checkbox->setChecked(group->enabled); });
}
const auto advanced_setting_count = std::count_if(
group->numeric_settings.begin(), group->numeric_settings.end(), [](auto& setting) {
return setting->GetVisibility() == ControllerEmu::SettingVisibility::Advanced;
});
if (advanced_setting_count != 0)
{
const auto advanced_button = new QPushButton(tr("Advanced"));
form_layout->addRow(advanced_button);
connect(advanced_button, &QPushButton::clicked,
[this, group] { ShowAdvancedControlGroupDialog(group); });
}
return group_box;
}
void MappingWidget::AddSettingWidgets(QFormLayout* layout, ControllerEmu::ControlGroup* group,
ControllerEmu::SettingVisibility visibility)
{
for (auto& setting : group->numeric_settings) for (auto& setting : group->numeric_settings)
{ {
if (setting->GetVisibility() != visibility)
continue;
QWidget* setting_widget = nullptr; QWidget* setting_widget = nullptr;
switch (setting->GetType()) switch (setting->GetType())
@ -149,33 +196,59 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con
hbox->addWidget(setting_widget); hbox->addWidget(setting_widget);
hbox->addWidget(CreateSettingAdvancedMappingButton(*setting)); hbox->addWidget(CreateSettingAdvancedMappingButton(*setting));
form_layout->addRow(tr(setting->GetUIName()), hbox); layout->addRow(tr(setting->GetUIName()), hbox);
}
} }
} }
if (group->default_value != ControllerEmu::ControlGroup::DefaultValue::AlwaysEnabled) void MappingWidget::ShowAdvancedControlGroupDialog(ControllerEmu::ControlGroup* group)
{ {
QLabel* group_enable_label = new QLabel(tr("Enable")); QDialog dialog{this};
QCheckBox* group_enable_checkbox = new QCheckBox(); dialog.setWindowTitle(tr(group->ui_name.c_str()));
group_enable_checkbox->setChecked(group->enabled);
form_layout->insertRow(0, group_enable_label, group_enable_checkbox); const auto group_box = new QGroupBox(tr("Advanced Settings"));
auto enable_group_by_checkbox = [group, form_layout, group_enable_label,
group_enable_checkbox] { QFormLayout* form_layout = new QFormLayout();
group->enabled = group_enable_checkbox->isChecked();
for (int i = 0; i < form_layout->count(); ++i) AddSettingWidgets(form_layout, group, ControllerEmu::SettingVisibility::Advanced);
const auto reset_button = new QPushButton(tr("Reset All"));
form_layout->addRow(reset_button);
connect(reset_button, &QPushButton::clicked, [this, group] {
for (auto& setting : group->numeric_settings)
{ {
QWidget* widget = form_layout->itemAt(i)->widget(); if (setting->GetVisibility() != ControllerEmu::SettingVisibility::Advanced)
if (widget != nullptr && widget != group_enable_label && widget != group_enable_checkbox) continue;
widget->setEnabled(group->enabled);
} setting->SetToDefault();
};
enable_group_by_checkbox();
connect(group_enable_checkbox, &QCheckBox::toggled, this, enable_group_by_checkbox);
connect(this, &MappingWidget::ConfigChanged, this,
[group_enable_checkbox, group] { group_enable_checkbox->setChecked(group->enabled); });
} }
return group_box; emit ConfigChanged();
});
const auto main_layout = new QVBoxLayout();
const auto button_box = new QDialogButtonBox(QDialogButtonBox::Close);
group_box->setLayout(form_layout);
main_layout->addWidget(group_box);
main_layout->addWidget(button_box);
dialog.setLayout(main_layout);
// Focusing something else by default instead of the first spin box.
// Dynamically changing expression-backed settings pause when taking input.
// This just avoids that weird edge case behavior when the dialog is first open.
button_box->setFocus();
// Signal the newly created numeric setting widgets to display the current values.
emit ConfigChanged();
// Enable "Close" button functionality.
connect(button_box, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
dialog.exec();
} }
QGroupBox* MappingWidget::CreateControlsBox(const QString& name, ControllerEmu::ControlGroup* group, QGroupBox* MappingWidget::CreateControlsBox(const QString& name, ControllerEmu::ControlGroup* group,

View File

@ -26,6 +26,7 @@ class Control;
class ControlGroup; class ControlGroup;
class EmulatedController; class EmulatedController;
class NumericSettingBase; class NumericSettingBase;
enum class SettingVisibility;
} // namespace ControllerEmu } // namespace ControllerEmu
constexpr int INDICATOR_UPDATE_FREQ = 30; constexpr int INDICATOR_UPDATE_FREQ = 30;
@ -57,6 +58,9 @@ protected:
int columns); int columns);
void CreateControl(const ControllerEmu::Control* control, QFormLayout* layout, bool indicator); void CreateControl(const ControllerEmu::Control* control, QFormLayout* layout, bool indicator);
QPushButton* CreateSettingAdvancedMappingButton(ControllerEmu::NumericSettingBase& setting); QPushButton* CreateSettingAdvancedMappingButton(ControllerEmu::NumericSettingBase& setting);
void AddSettingWidgets(QFormLayout* layout, ControllerEmu::ControlGroup* group,
ControllerEmu::SettingVisibility visibility);
void ShowAdvancedControlGroupDialog(ControllerEmu::ControlGroup* group);
private: private:
MappingWindow* m_parent; MappingWindow* m_parent;

View File

@ -65,9 +65,19 @@ OctagonAnalogStick::OctagonAnalogStick(const char* name_, ControlState gate_radi
OctagonAnalogStick::OctagonAnalogStick(const char* name_, const char* ui_name_, OctagonAnalogStick::OctagonAnalogStick(const char* name_, const char* ui_name_,
ControlState gate_radius) ControlState gate_radius)
: AnalogStick(name_, ui_name_, std::make_unique<ControllerEmu::OctagonStickGate>(gate_radius)) : AnalogStick(name_, ui_name_, std::make_unique<ControllerEmu::OctagonStickGate>(1.0))
{ {
AddVirtualNotchSetting(&m_virtual_notch_setting, 45); AddVirtualNotchSetting(&m_virtual_notch_setting, 45);
AddSetting(
&m_gate_size_setting,
{_trans("Gate Size"),
// i18n: The percent symbol.
_trans("%"),
// i18n: Refers to plastic shell of game controller (stick gate) that limits stick movements.
_trans("Adjusts target radius of simulated stick gate."), nullptr,
SettingVisibility::Advanced},
gate_radius * 100, 0.01, 100);
} }
ControlState OctagonAnalogStick::GetVirtualNotchSize() const ControlState OctagonAnalogStick::GetVirtualNotchSize() const
@ -75,4 +85,9 @@ ControlState OctagonAnalogStick::GetVirtualNotchSize() const
return m_virtual_notch_setting.GetValue() * MathUtil::TAU / 360; return m_virtual_notch_setting.GetValue() * MathUtil::TAU / 360;
} }
ControlState OctagonAnalogStick::GetGateRadiusAtAngle(double ang) const
{
return AnalogStick::GetGateRadiusAtAngle(ang) * m_gate_size_setting.GetValue() / 100;
}
} // namespace ControllerEmu } // namespace ControllerEmu

View File

@ -36,9 +36,11 @@ public:
OctagonAnalogStick(const char* name, const char* ui_name, ControlState gate_radius); OctagonAnalogStick(const char* name, const char* ui_name, ControlState gate_radius);
ControlState GetVirtualNotchSize() const override; ControlState GetVirtualNotchSize() const override;
ControlState GetGateRadiusAtAngle(double ang) const override;
private: private:
SettingValue<double> m_virtual_notch_setting; SettingValue<double> m_virtual_notch_setting;
SettingValue<double> m_gate_size_setting;
}; };
} // namespace ControllerEmu } // namespace ControllerEmu

View File

@ -32,7 +32,8 @@ void ControlGroup::AddVirtualNotchSetting(SettingValue<double>* value, double ma
AddSetting(value, AddSetting(value,
{_trans("Virtual Notches"), {_trans("Virtual Notches"),
// i18n: The degrees symbol. // i18n: The degrees symbol.
_trans("°"), _trans("Snap the thumbstick position to the nearest octagonal axis.")}, _trans("°"), _trans("Snap the thumbstick position to the nearest octagonal axis."),
nullptr, SettingVisibility::Advanced},
0, 0, max_virtual_notch_deg); 0, 0, max_virtual_notch_deg);
} }

View File

@ -26,6 +26,11 @@ const char* NumericSettingBase::GetUIDescription() const
return m_details.ui_description; return m_details.ui_description;
} }
SettingVisibility NumericSettingBase::GetVisibility() const
{
return m_details.visibility;
}
template <> template <>
void NumericSetting<int>::SetExpressionFromValue() void NumericSetting<int>::SetExpressionFromValue()
{ {

View File

@ -20,13 +20,20 @@ enum class SettingType
Bool, Bool,
}; };
enum class SettingVisibility
{
Normal,
Advanced,
};
struct NumericSettingDetails struct NumericSettingDetails
{ {
NumericSettingDetails(const char* const _ini_name, const char* const _ui_suffix = nullptr, NumericSettingDetails(const char* const _ini_name, const char* const _ui_suffix = nullptr,
const char* const _ui_description = nullptr, const char* const _ui_description = nullptr,
const char* const _ui_name = nullptr) const char* const _ui_name = nullptr,
SettingVisibility _visibility = SettingVisibility::Normal)
: ini_name(_ini_name), ui_suffix(_ui_suffix), ui_description(_ui_description), : ini_name(_ini_name), ui_suffix(_ui_suffix), ui_description(_ui_description),
ui_name(_ui_name ? _ui_name : _ini_name) ui_name(_ui_name ? _ui_name : _ini_name), visibility(_visibility)
{ {
} }
@ -41,6 +48,9 @@ struct NumericSettingDetails
// The name used in the UI (if different from ini file). // The name used in the UI (if different from ini file).
const char* const ui_name; const char* const ui_name;
// Advanced settings should be harder to change in the UI. They might confuse users.
const SettingVisibility visibility;
}; };
class NumericSettingBase class NumericSettingBase
@ -66,9 +76,12 @@ public:
virtual SettingType GetType() const = 0; virtual SettingType GetType() const = 0;
virtual void SetToDefault() = 0;
const char* GetUIName() const; const char* GetUIName() const;
const char* GetUISuffix() const; const char* GetUISuffix() const;
const char* GetUIDescription() const; const char* GetUIDescription() const;
SettingVisibility GetVisibility() const;
protected: protected:
NumericSettingDetails m_details; NumericSettingDetails m_details;
@ -92,9 +105,11 @@ public:
: NumericSettingBase(details), m_value(*value), m_default_value(default_value), : NumericSettingBase(details), m_value(*value), m_default_value(default_value),
m_min_value(min_value), m_max_value(max_value) m_min_value(min_value), m_max_value(max_value)
{ {
m_value.SetValue(m_default_value); SetToDefault();
} }
void SetToDefault() override { m_value.SetValue(m_default_value); }
void LoadFromIni(const IniFile::Section& section, const std::string& group_name) override void LoadFromIni(const IniFile::Section& section, const std::string& group_name) override
{ {
std::string str_value; std::string str_value;