// Copyright 2017 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "DolphinQt/Config/Mapping/MappingWidget.h" #include #include #include #include #include #include #include "DolphinQt/Config/Mapping/IOWindow.h" #include "DolphinQt/Config/Mapping/MappingButton.h" #include "DolphinQt/Config/Mapping/MappingIndicator.h" #include "DolphinQt/Config/Mapping/MappingNumeric.h" #include "DolphinQt/Config/Mapping/MappingWindow.h" #include "InputCommon/ControlReference/ControlReference.h" #include "InputCommon/ControllerEmu/Control/Control.h" #include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" #include "InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h" #include "InputCommon/ControllerEmu/ControllerEmu.h" #include "InputCommon/ControllerEmu/Setting/NumericSetting.h" #include "InputCommon/ControllerEmu/StickGate.h" MappingWidget::MappingWidget(MappingWindow* parent) : m_parent(parent) { connect(parent, &MappingWindow::Update, this, &MappingWidget::Update); connect(parent, &MappingWindow::Save, this, &MappingWidget::SaveSettings); connect(parent, &MappingWindow::ConfigChanged, this, &MappingWidget::ConfigChanged); } MappingWindow* MappingWidget::GetParent() const { return m_parent; } int MappingWidget::GetPort() const { return m_parent->GetPort(); } QGroupBox* MappingWidget::CreateGroupBox(ControllerEmu::ControlGroup* group) { return CreateGroupBox(tr(group->ui_name.c_str()), group); } QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::ControlGroup* group) { QGroupBox* group_box = new QGroupBox(name); QFormLayout* form_layout = new QFormLayout(); group_box->setLayout(form_layout); MappingIndicator* indicator = nullptr; switch (group->type) { case ControllerEmu::GroupType::Shake: indicator = new ShakeMappingIndicator(*static_cast(group)); break; case ControllerEmu::GroupType::MixedTriggers: indicator = new MixedTriggersIndicator(*static_cast(group)); break; case ControllerEmu::GroupType::Tilt: indicator = new TiltIndicator(*static_cast(group)); break; case ControllerEmu::GroupType::Cursor: indicator = new CursorIndicator(*static_cast(group)); break; case ControllerEmu::GroupType::Force: indicator = new SwingIndicator(*static_cast(group)); break; case ControllerEmu::GroupType::IMUAccelerometer: indicator = new AccelerometerMappingIndicator(*static_cast(group)); break; case ControllerEmu::GroupType::IMUGyroscope: indicator = new GyroMappingIndicator(*static_cast(group)); break; case ControllerEmu::GroupType::Stick: indicator = new AnalogStickIndicator(*static_cast(group)); break; default: break; } if (indicator) { const auto indicator_layout = new QBoxLayout(QBoxLayout::Direction::Down); indicator_layout->addWidget(indicator); indicator_layout->setAlignment(Qt::AlignCenter); form_layout->addRow(indicator_layout); connect(this, &MappingWidget::Update, indicator, qOverload<>(&MappingIndicator::update)); const bool need_calibration = group->type == ControllerEmu::GroupType::Cursor || group->type == ControllerEmu::GroupType::Stick || group->type == ControllerEmu::GroupType::Tilt || group->type == ControllerEmu::GroupType::Force; if (need_calibration) { const auto calibrate = new CalibrationWidget(*static_cast(group), *static_cast(indicator)); form_layout->addRow(calibrate); } } for (auto& control : group->controls) CreateControl(control.get(), form_layout, !indicator); for (auto& setting : group->numeric_settings) { QWidget* setting_widget = nullptr; switch (setting->GetType()) { case ControllerEmu::SettingType::Double: setting_widget = new MappingDouble( this, static_cast*>(setting.get())); break; case ControllerEmu::SettingType::Bool: setting_widget = new MappingBool(this, static_cast*>(setting.get())); break; default: // FYI: Widgets for additional types can be implemented as needed. break; } if (setting_widget) { const auto hbox = new QHBoxLayout; hbox->addWidget(setting_widget); hbox->addWidget(CreateSettingAdvancedMappingButton(*setting)); form_layout->addRow(tr(setting->GetUIName()), hbox); } } 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); }); } return group_box; } QGroupBox* MappingWidget::CreateControlsBox(const QString& name, ControllerEmu::ControlGroup* group, int columns) { auto* group_box = new QGroupBox(name); auto* hbox_layout = new QHBoxLayout(); group_box->setLayout(hbox_layout); std::vector form_layouts; for (int i = 0; i < columns; ++i) { form_layouts.push_back(new QFormLayout()); hbox_layout->addLayout(form_layouts[i]); } for (size_t i = 0; i < group->controls.size(); ++i) { CreateControl(group->controls[i].get(), form_layouts[i % columns], true); } return group_box; } void MappingWidget::CreateControl(const ControllerEmu::Control* control, QFormLayout* layout, bool indicator) { auto* button = new MappingButton(this, control->control_ref.get(), indicator); button->setMinimumWidth(100); button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); const bool translate = control->translate == ControllerEmu::Translate; const QString translated_name = translate ? tr(control->ui_name.c_str()) : QString::fromStdString(control->ui_name); layout->addRow(translated_name, button); } ControllerEmu::EmulatedController* MappingWidget::GetController() const { return m_parent->GetController(); } QPushButton* MappingWidget::CreateSettingAdvancedMappingButton(ControllerEmu::NumericSettingBase& setting) { const auto button = new QPushButton(tr("...")); button->setFixedWidth(QFontMetrics(font()).boundingRect(button->text()).width() * 2); button->connect(button, &QPushButton::clicked, [this, &setting]() { if (setting.IsSimpleValue()) setting.SetExpressionFromValue(); IOWindow io(this, GetController(), &setting.GetInputReference(), IOWindow::Type::Input); io.exec(); setting.SimplifyIfPossible(); ConfigChanged(); SaveSettings(); }); return button; }