diff --git a/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp b/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp index 5f1b32ba83..145fef8392 100644 --- a/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp @@ -40,7 +40,7 @@ IOWindow::IOWindow(QWidget* parent, ControllerEmu::EmulatedController* controlle setWindowTitle(type == IOWindow::Type::Input ? tr("Configure Input") : tr("Configure Output")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - Update(); + ConfigChanged(); } void IOWindow::CreateMainLayout() @@ -115,8 +115,10 @@ void IOWindow::CreateMainLayout() setLayout(m_main_layout); } -void IOWindow::Update() +void IOWindow::ConfigChanged() { + const auto old_state = blockSignals(true); + m_expression_text->setPlainText(QString::fromStdString(m_reference->GetExpression())); m_expression_text->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); m_range_spinbox->setValue(m_reference->range * SLIDER_TICK_COUNT); @@ -126,6 +128,8 @@ void IOWindow::Update() UpdateDeviceList(); UpdateOptionList(); + + blockSignals(old_state); } void IOWindow::ConnectWidgets() @@ -173,6 +177,7 @@ void IOWindow::OnDialogButtonPressed(QAbstractButton* button) } m_reference->SetExpression(m_expression_text->toPlainText().toStdString()); + m_controller->UpdateReferences(g_controller_interface); if (button != m_apply_button) accept(); @@ -234,21 +239,9 @@ void IOWindow::UpdateDeviceList() { m_devices_combo->clear(); - Core::RunAsCPUThread([&] { - g_controller_interface.RefreshDevices(); - m_controller->UpdateReferences(g_controller_interface); + for (const auto& name : g_controller_interface.GetAllDeviceStrings()) + m_devices_combo->addItem(QString::fromStdString(name)); - // Adding default device regardless if it's currently connected or not - const auto default_device = m_controller->GetDefaultDevice().ToString(); - - m_devices_combo->addItem(QString::fromStdString(default_device)); - - for (const auto& name : g_controller_interface.GetAllDeviceStrings()) - { - if (name != default_device) - m_devices_combo->addItem(QString::fromStdString(name)); - } - - m_devices_combo->setCurrentIndex(0); - }); + m_devices_combo->setCurrentText( + QString::fromStdString(m_controller->GetDefaultDevice().ToString())); } diff --git a/Source/Core/DolphinQt/Config/Mapping/IOWindow.h b/Source/Core/DolphinQt/Config/Mapping/IOWindow.h index 250b016309..5921b14424 100644 --- a/Source/Core/DolphinQt/Config/Mapping/IOWindow.h +++ b/Source/Core/DolphinQt/Config/Mapping/IOWindow.h @@ -43,7 +43,7 @@ public: private: void CreateMainLayout(); void ConnectWidgets(); - void Update(); + void ConfigChanged(); void OnDialogButtonPressed(QAbstractButton* button); void OnDeviceChanged(const QString& device); diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingBool.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingBool.cpp index a05cfc1147..1112f3b5e2 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingBool.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingBool.cpp @@ -10,23 +10,20 @@ #include "InputCommon/ControllerEmu/Setting/BooleanSetting.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" -MappingBool::MappingBool(MappingWidget* widget, ControllerEmu::BooleanSetting* setting) - : QCheckBox(tr(setting->m_ui_name.c_str())), m_parent(widget), m_setting(setting) +MappingBool::MappingBool(MappingWidget* parent, ControllerEmu::BooleanSetting* setting) + : QCheckBox(tr(setting->m_ui_name.c_str())), m_setting(*setting) { - Update(); - Connect(); -} - -void MappingBool::Connect() -{ - connect(this, &QCheckBox::stateChanged, this, [this](int value) { - m_setting->SetValue(value); - m_parent->SaveSettings(); - m_parent->GetController()->UpdateReferences(g_controller_interface); + connect(this, &QCheckBox::stateChanged, this, [this, parent](int value) { + m_setting.SetValue(value); + parent->SaveSettings(); }); + + connect(parent, &MappingWidget::ConfigChanged, this, &MappingBool::ConfigChanged); } -void MappingBool::Update() +void MappingBool::ConfigChanged() { - setChecked(m_setting->GetValue()); + const bool old_state = blockSignals(true); + setChecked(m_setting.GetValue()); + blockSignals(old_state); } diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingBool.h b/Source/Core/DolphinQt/Config/Mapping/MappingBool.h index 090d644ffc..df3693d580 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingBool.h +++ b/Source/Core/DolphinQt/Config/Mapping/MappingBool.h @@ -18,11 +18,8 @@ class MappingBool : public QCheckBox public: MappingBool(MappingWidget* widget, ControllerEmu::BooleanSetting* setting); - void Update(); - private: - void Connect(); + void ConfigChanged(); - MappingWidget* m_parent; - ControllerEmu::BooleanSetting* m_setting; + ControllerEmu::BooleanSetting& m_setting; }; diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp index a068397d09..5c66f9ec94 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include "Common/Thread.h" #include "Core/Core.h" @@ -42,8 +41,8 @@ bool MappingButton::IsInput() const return m_reference->IsInput(); } -MappingButton::MappingButton(MappingWidget* widget, ControlReference* ref, bool indicator) - : ElidedButton(ToDisplayString(QString::fromStdString(ref->GetExpression()))), m_parent(widget), +MappingButton::MappingButton(MappingWidget* parent, ControlReference* ref, bool indicator) + : ElidedButton(ToDisplayString(QString::fromStdString(ref->GetExpression()))), m_parent(parent), m_reference(ref) { // Force all mapping buttons to stay at a minimal height. @@ -54,50 +53,30 @@ MappingButton::MappingButton(MappingWidget* widget, ControlReference* ref, bool setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); - Connect(); setToolTip( tr("Left-click to detect input.\nMiddle-click to clear.\nRight-click for more options.")); - if (!m_reference->IsInput() || !indicator) - return; - m_timer = new QTimer(this); - connect(m_timer, &QTimer::timeout, this, [this] { - if (!isActiveWindow()) - return; + connect(this, &MappingButton::pressed, this, &MappingButton::Detect); - Settings::Instance().SetControllerStateNeeded(true); + if (indicator) + connect(parent, &MappingWidget::Update, this, &MappingButton::UpdateIndicator); - if (Core::GetState() == Core::State::Uninitialized || Core::GetState() == Core::State::Paused) - g_controller_interface.UpdateInput(); - - auto state = m_reference->State(); - - QFont f = m_parent->font(); - QPalette p = m_parent->palette(); - - if (state > ControllerEmu::Buttons::ACTIVATION_THRESHOLD) - { - f.setBold(true); - p.setColor(QPalette::ButtonText, Qt::red); - } - - setFont(f); - setPalette(p); - - Settings::Instance().SetControllerStateNeeded(false); - }); - - m_timer->start(1000 / 30); + connect(parent, &MappingWidget::ConfigChanged, this, &MappingButton::ConfigChanged); } -void MappingButton::Connect() +void MappingButton::AdvancedPressed() { - connect(this, &MappingButton::pressed, this, &MappingButton::Detect); + IOWindow io(this, m_parent->GetController(), m_reference, + m_reference->IsInput() ? IOWindow::Type::Input : IOWindow::Type::Output); + io.exec(); + + ConfigChanged(); + m_parent->SaveSettings(); } void MappingButton::Detect() { - if (m_parent->GetDevice() == nullptr || !m_reference->IsInput()) + if (!m_reference->IsInput()) return; const auto default_device_qualifier = m_parent->GetController()->GetDefaultDevice(); @@ -121,27 +100,48 @@ void MappingButton::Detect() return; m_reference->SetExpression(expression.toStdString()); - m_parent->SaveSettings(); - Update(); m_parent->GetController()->UpdateReferences(g_controller_interface); + ConfigChanged(); + m_parent->SaveSettings(); + if (m_parent->IsIterativeInput()) m_parent->NextButton(this); } void MappingButton::Clear() { - m_reference->SetExpression(""); m_reference->range = 100.0 / SLIDER_TICK_COUNT; + + m_reference->SetExpression(""); + m_parent->GetController()->UpdateReferences(g_controller_interface); + m_parent->SaveSettings(); - Update(); + ConfigChanged(); } -void MappingButton::Update() +void MappingButton::UpdateIndicator() +{ + if (!isActiveWindow()) + return; + + const auto state = m_reference->State(); + + QFont f = m_parent->font(); + QPalette p = m_parent->palette(); + + if (state > ControllerEmu::Buttons::ACTIVATION_THRESHOLD) + { + f.setBold(true); + p.setColor(QPalette::ButtonText, Qt::red); + } + + setFont(f); + setPalette(p); +} + +void MappingButton::ConfigChanged() { - const auto lock = ControllerEmu::EmulatedController::GetStateLock(); - m_reference->UpdateReference(g_controller_interface, - m_parent->GetController()->GetDefaultDevice()); setText(ToDisplayString(QString::fromStdString(m_reference->GetExpression()))); } @@ -153,13 +153,13 @@ void MappingButton::mouseReleaseEvent(QMouseEvent* event) if (m_reference->IsInput()) QPushButton::mouseReleaseEvent(event); else - emit AdvancedPressed(); + AdvancedPressed(); return; case Qt::MouseButton::MidButton: Clear(); return; case Qt::MouseButton::RightButton: - emit AdvancedPressed(); + AdvancedPressed(); return; default: return; diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingButton.h b/Source/Core/DolphinQt/Config/Mapping/MappingButton.h index 96847775c9..464d09e9f6 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingButton.h +++ b/Source/Core/DolphinQt/Config/Mapping/MappingButton.h @@ -11,7 +11,6 @@ class ControlReference; class MappingWidget; class QEvent; class QMouseEvent; -class QTimer; class MappingButton : public ElidedButton { @@ -19,20 +18,17 @@ class MappingButton : public ElidedButton public: MappingButton(MappingWidget* widget, ControlReference* ref, bool indicator); - void Clear(); - void Update(); void Detect(); bool IsInput() const; -signals: +private: + void Clear(); + void UpdateIndicator(); + void ConfigChanged(); void AdvancedPressed(); -private: void mouseReleaseEvent(QMouseEvent* event) override; - void Connect(); - MappingWidget* m_parent; ControlReference* m_reference; - QTimer* m_timer; }; diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp index dabc4d8530..f1a5d67c91 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp @@ -67,6 +67,7 @@ QString DetectExpression(QPushButton* button, ciface::Core::DeviceContainer& dev std::shared_ptr device; ciface::Core::Device::Input* input; + std::tie(device, input) = device_container.DetectInput(INPUT_DETECT_TIME, device_strings); button->releaseMouse(); diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp index b19391acbb..44e86a9feb 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp @@ -23,6 +23,7 @@ #include "InputCommon/ControllerEmu/Setting/NumericSetting.h" #include "InputCommon/ControllerInterface/Device.h" +#include "DolphinQt/Config/Mapping/MappingWidget.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" #include "DolphinQt/Settings.h" @@ -50,15 +51,9 @@ const QColor SWING_GATE_COLOR = 0xcea2d9; constexpr int INPUT_DOT_RADIUS = 2; -constexpr int INDICATOR_UPDATE_FREQ = 30; - MappingIndicator::MappingIndicator(ControllerEmu::ControlGroup* group) : m_group(group) { setMinimumHeight(128); - - const auto timer = new QTimer(this); - connect(timer, &QTimer::timeout, this, [this] { repaint(); }); - timer->start(1000 / INDICATOR_UPDATE_FREQ); } namespace @@ -133,12 +128,8 @@ void MappingIndicator::DrawCursor(ControllerEmu::Cursor& cursor) const QColor tv_brush_color = CURSOR_TV_COLOR; const QColor tv_pen_color = tv_brush_color.darker(125); - // TODO: This SetControllerStateNeeded interface leaks input into the game - // We should probably hold the mutex for UI updates. - Settings::Instance().SetControllerStateNeeded(true); const auto raw_coord = cursor.GetState(false); const auto adj_coord = cursor.GetState(true); - Settings::Instance().SetControllerStateNeeded(false); UpdateCalibrationWidget({raw_coord.x, raw_coord.y}); @@ -250,9 +241,6 @@ void MappingIndicator::DrawReshapableInput(ControllerEmu::ReshapableInput& stick const QColor gate_pen_color = gate_brush_color.darker(125); - // TODO: This SetControllerStateNeeded interface leaks input into the game - // We should probably hold the mutex for UI updates. - Settings::Instance().SetControllerStateNeeded(true); const auto raw_coord = stick.GetReshapableState(false); Common::DVec2 adj_coord; @@ -267,8 +255,6 @@ void MappingIndicator::DrawReshapableInput(ControllerEmu::ReshapableInput& stick adj_coord = stick.GetReshapableState(true); } - Settings::Instance().SetControllerStateNeeded(false); - UpdateCalibrationWidget(raw_coord); // Bounding box size: @@ -343,10 +329,8 @@ void MappingIndicator::DrawMixedTriggers() const std::array button_masks = {0x1, 0x2}; u16 button_state = 0; - Settings::Instance().SetControllerStateNeeded(true); triggers.GetState(&button_state, button_masks.data(), raw_analog_state.data(), false); triggers.GetState(&button_state, button_masks.data(), adj_analog_state.data(), true); - Settings::Instance().SetControllerStateNeeded(false); // Rectangle sizes: const int trigger_height = 32; @@ -429,13 +413,9 @@ void MappingIndicator::DrawForce(ControllerEmu::Force& force) const QColor gate_brush_color = SWING_GATE_COLOR; const QColor gate_pen_color = gate_brush_color.darker(125); - // TODO: This SetControllerStateNeeded interface leaks input into the game - // We should probably hold the mutex for UI updates. - Settings::Instance().SetControllerStateNeeded(true); const auto raw_coord = force.GetState(false); WiimoteEmu::EmulateSwing(&m_motion_state, &force, 1.f / INDICATOR_UPDATE_FREQ); const auto& adj_coord = m_motion_state.position; - Settings::Instance().SetControllerStateNeeded(false); UpdateCalibrationWidget({raw_coord.x, raw_coord.y}); @@ -520,6 +500,9 @@ void MappingIndicator::DrawForce(ControllerEmu::Force& force) void MappingIndicator::paintEvent(QPaintEvent*) { + // TODO: The SetControllerStateNeeded interface leaks input into the game. + Settings::Instance().SetControllerStateNeeded(true); + switch (m_group->type) { case ControllerEmu::GroupType::Cursor: @@ -538,6 +521,8 @@ void MappingIndicator::paintEvent(QPaintEvent*) default: break; } + + Settings::Instance().SetControllerStateNeeded(false); } void MappingIndicator::DrawCalibration(QPainter& p, Common::DVec2 point) diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingNumeric.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingNumeric.cpp index e5fb3a4548..0de807d68c 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingNumeric.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingNumeric.cpp @@ -10,25 +10,23 @@ #include "InputCommon/ControllerEmu/Setting/NumericSetting.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" -MappingNumeric::MappingNumeric(MappingWidget* widget, ControllerEmu::NumericSetting* setting) - : m_parent(widget), m_setting(setting) +MappingNumeric::MappingNumeric(MappingWidget* parent, ControllerEmu::NumericSetting* setting) + : m_setting(*setting) { setRange(setting->m_low, setting->m_high); - Update(); - Connect(); -} -void MappingNumeric::Connect() -{ connect(this, static_cast(&QSpinBox::valueChanged), this, - [this](int value) { - m_setting->SetValue(static_cast(value) / 100); - m_parent->SaveSettings(); - m_parent->GetController()->UpdateReferences(g_controller_interface); + [this, parent](int value) { + m_setting.SetValue(static_cast(value) / 100); + parent->SaveSettings(); }); + + connect(parent, &MappingWidget::ConfigChanged, this, &MappingNumeric::ConfigChanged); } -void MappingNumeric::Update() +void MappingNumeric::ConfigChanged() { - setValue(m_setting->GetValue() * 100); + const bool old_state = blockSignals(true); + setValue(m_setting.GetValue() * 100); + blockSignals(old_state); } diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingNumeric.h b/Source/Core/DolphinQt/Config/Mapping/MappingNumeric.h index f5268a0c02..2120e972c5 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingNumeric.h +++ b/Source/Core/DolphinQt/Config/Mapping/MappingNumeric.h @@ -19,11 +19,8 @@ class MappingNumeric : public QSpinBox public: MappingNumeric(MappingWidget* widget, ControllerEmu::NumericSetting* ref); - void Update(); - private: - void Connect(); + void ConfigChanged(); - MappingWidget* m_parent; - ControllerEmu::NumericSetting* m_setting; + ControllerEmu::NumericSetting& m_setting; }; diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingRadio.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingRadio.cpp index 8d70855e33..162a18bae9 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingRadio.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingRadio.cpp @@ -10,23 +10,20 @@ #include "InputCommon/ControllerEmu/Setting/BooleanSetting.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" -MappingRadio::MappingRadio(MappingWidget* widget, ControllerEmu::BooleanSetting* setting) - : QRadioButton(tr(setting->m_ui_name.c_str())), m_parent(widget), m_setting(setting) +MappingRadio::MappingRadio(MappingWidget* parent, ControllerEmu::BooleanSetting* setting) + : QRadioButton(tr(setting->m_ui_name.c_str())), m_setting(*setting) { - Update(); - Connect(); -} - -void MappingRadio::Connect() -{ - connect(this, &QRadioButton::toggled, this, [this](int value) { - m_setting->SetValue(value); - m_parent->SaveSettings(); - m_parent->GetController()->UpdateReferences(g_controller_interface); + connect(this, &QRadioButton::toggled, this, [this, parent](int value) { + m_setting.SetValue(value); + parent->SaveSettings(); }); + + connect(parent, &MappingWidget::ConfigChanged, this, &MappingRadio::ConfigChanged); } -void MappingRadio::Update() +void MappingRadio::ConfigChanged() { - setChecked(m_setting->GetValue()); + const bool old_state = blockSignals(true); + setChecked(m_setting.GetValue()); + blockSignals(old_state); } diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingRadio.h b/Source/Core/DolphinQt/Config/Mapping/MappingRadio.h index 97682e4b54..230a311a26 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingRadio.h +++ b/Source/Core/DolphinQt/Config/Mapping/MappingRadio.h @@ -18,11 +18,8 @@ class MappingRadio : public QRadioButton public: MappingRadio(MappingWidget* widget, ControllerEmu::BooleanSetting* setting); - void Update(); - private: - void Connect(); + void ConfigChanged(); - MappingWidget* m_parent; - ControllerEmu::BooleanSetting* m_setting; + ControllerEmu::BooleanSetting& m_setting; }; diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp index 0224d4cfed..8e80672860 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "DolphinQt/Config/Mapping/IOWindow.h" #include "DolphinQt/Config/Mapping/MappingBool.h" @@ -15,18 +16,32 @@ #include "DolphinQt/Config/Mapping/MappingNumeric.h" #include "DolphinQt/Config/Mapping/MappingRadio.h" #include "DolphinQt/Config/Mapping/MappingWindow.h" +#include "DolphinQt/Settings.h" #include "InputCommon/ControlReference/ControlReference.h" #include "InputCommon/ControllerEmu/Control/Control.h" #include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" +#include "InputCommon/ControllerEmu/ControllerEmu.h" #include "InputCommon/ControllerEmu/Setting/BooleanSetting.h" #include "InputCommon/ControllerEmu/Setting/NumericSetting.h" #include "InputCommon/ControllerEmu/StickGate.h" -MappingWidget::MappingWidget(MappingWindow* window) : m_parent(window) +MappingWidget::MappingWidget(MappingWindow* parent) : m_parent(parent) { - connect(window, &MappingWindow::Update, this, &MappingWidget::Update); - connect(window, &MappingWindow::Save, this, &MappingWidget::SaveSettings); + connect(parent, &MappingWindow::Update, this, &MappingWidget::Update); + connect(parent, &MappingWindow::Save, this, &MappingWidget::SaveSettings); + connect(parent, &MappingWindow::ConfigChanged, this, &MappingWidget::ConfigChanged); + + const auto timer = new QTimer(this); + connect(timer, &QTimer::timeout, this, [this] { + // TODO: The SetControllerStateNeeded interface leaks input into the game. + const auto lock = m_parent->GetController()->GetStateLock(); + Settings::Instance().SetControllerStateNeeded(true); + emit Update(); + Settings::Instance().SetControllerStateNeeded(false); + }); + + timer->start(1000 / INDICATOR_UPDATE_FREQ); } MappingWindow* MappingWidget::GetParent() const @@ -57,11 +72,6 @@ void MappingWidget::NextButton(MappingButton* button) NextButton(next); } -std::shared_ptr MappingWidget::GetDevice() const -{ - return m_parent->GetDevice(); -} - int MappingWidget::GetPort() const { return m_parent->GetPort(); @@ -96,19 +106,6 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con translate ? tr(control->ui_name.c_str()) : QString::fromStdString(control->ui_name); form_layout->addRow(translated_name, button); - auto* control_ref = control->control_ref.get(); - - connect(button, &MappingButton::AdvancedPressed, [this, button, control_ref] { - if (m_parent->GetDevice() == nullptr) - return; - - IOWindow io(this, m_parent->GetController(), control_ref, - control_ref->IsInput() ? IOWindow::Type::Input : IOWindow::Type::Output); - io.exec(); - SaveSettings(); - button->Update(); - }); - m_buttons.push_back(button); } @@ -116,7 +113,6 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con { auto* spinbox = new MappingNumeric(this, numeric.get()); form_layout->addRow(tr(numeric->m_name.c_str()), spinbox); - m_numerics.push_back(spinbox); } for (auto& boolean : group->boolean_settings) @@ -127,7 +123,6 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con auto* checkbox = new MappingRadio(this, boolean.get()); form_layout->addRow(checkbox); - m_radio.push_back(checkbox); } for (auto& boolean : group->boolean_settings) @@ -138,12 +133,12 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con auto* checkbox = new MappingBool(this, boolean.get()); form_layout->addRow(checkbox); - m_bools.push_back(checkbox); } if (need_indicator) { auto const indicator = new MappingIndicator(group); + connect(this, &MappingWidget::Update, indicator, QOverload<>::of(&MappingIndicator::update)); if (need_calibration) { @@ -159,23 +154,6 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con return group_box; } -void MappingWidget::Update() -{ - for (auto* button : m_buttons) - button->Update(); - - for (auto* spinbox : m_numerics) - spinbox->Update(); - - for (auto* checkbox : m_bools) - checkbox->Update(); - - for (auto* radio : m_radio) - radio->Update(); - - SaveSettings(); -} - ControllerEmu::EmulatedController* MappingWidget::GetController() const { return m_parent->GetController(); diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.h b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.h index e828b48d09..80000e047a 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.h +++ b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.h @@ -35,6 +35,8 @@ class Device; } } // namespace ciface +constexpr int INDICATOR_UPDATE_FREQ = 30; + class MappingWidget : public QWidget { Q_OBJECT @@ -42,7 +44,6 @@ public: explicit MappingWidget(MappingWindow* window); ControllerEmu::EmulatedController* GetController() const; - std::shared_ptr GetDevice() const; MappingWindow* GetParent() const; @@ -53,7 +54,9 @@ public: virtual void SaveSettings() = 0; virtual InputConfig* GetConfig() = 0; +signals: void Update(); + void ConfigChanged(); protected: int GetPort() const; @@ -62,8 +65,5 @@ protected: private: MappingWindow* m_parent; bool m_first = true; - std::vector m_bools; - std::vector m_radio; std::vector m_buttons; - std::vector m_numerics; }; diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp index 1317613ace..403fbed993 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp @@ -13,13 +13,13 @@ #include #include +#include "Core/Core.h" + #include "Common/FileSearch.h" #include "Common/FileUtil.h" #include "Common/IniFile.h" #include "Common/StringUtil.h" -#include "Core/Core.h" - #include "DolphinQt/Config/Mapping/GCKeyboardEmu.h" #include "DolphinQt/Config/Mapping/GCMicrophone.h" #include "DolphinQt/Config/Mapping/GCPadEmu.h" @@ -58,6 +58,8 @@ MappingWindow::MappingWindow(QWidget* parent, Type type, int port_num) CreateMainLayout(); ConnectWidgets(); SetMappingType(type); + + emit ConfigChanged(); } void MappingWindow::CreateDevicesLayout() @@ -141,17 +143,21 @@ void MappingWindow::ConnectWidgets() { connect(&Settings::Instance(), &Settings::DevicesChanged, this, &MappingWindow::OnGlobalDevicesChanged); - connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(m_devices_refresh, &QPushButton::clicked, this, &MappingWindow::RefreshDevices); + connect(this, &MappingWindow::ConfigChanged, this, &MappingWindow::OnGlobalDevicesChanged); connect(m_devices_combo, static_cast(&QComboBox::currentIndexChanged), - this, &MappingWindow::OnDeviceChanged); + this, &MappingWindow::OnSelectDevice); + + connect(m_devices_refresh, &QPushButton::clicked, this, &MappingWindow::RefreshDevices); + connect(m_reset_clear, &QPushButton::clicked, this, &MappingWindow::OnClearFieldsPressed); connect(m_reset_default, &QPushButton::clicked, this, &MappingWindow::OnDefaultFieldsPressed); connect(m_profiles_save, &QPushButton::clicked, this, &MappingWindow::OnSaveProfilePressed); connect(m_profiles_load, &QPushButton::clicked, this, &MappingWindow::OnLoadProfilePressed); connect(m_profiles_delete, &QPushButton::clicked, this, &MappingWindow::OnDeleteProfilePressed); + // We currently use the "Close" button as an "Accept" button so we must save on reject. connect(this, &QDialog::rejected, [this] { emit Save(); }); + connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); } void MappingWindow::OnDeleteProfilePressed() @@ -206,9 +212,7 @@ void MappingWindow::OnLoadProfilePressed() m_controller->LoadConfig(ini.GetOrCreateSection("Profile")); m_controller->UpdateReferences(g_controller_interface); - emit Update(); - - RefreshDevices(); + emit ConfigChanged(); } void MappingWindow::OnSaveProfilePressed() @@ -235,13 +239,16 @@ void MappingWindow::OnSaveProfilePressed() } } -void MappingWindow::OnDeviceChanged(int index) +void MappingWindow::OnSelectDevice(int index) { if (IsMappingAllDevices()) return; - const auto device = m_devices_combo->currentText().toStdString(); + // Original string is stored in the "user-data". + const auto device = m_devices_combo->currentData().toString().toStdString(); + m_controller->SetDefaultDevice(device); + m_controller->UpdateReferences(g_controller_interface); } bool MappingWindow::IsMappingAllDevices() const @@ -256,26 +263,42 @@ void MappingWindow::RefreshDevices() void MappingWindow::OnGlobalDevicesChanged() { + const auto old_state = m_devices_combo->blockSignals(true); + m_devices_combo->clear(); - Core::RunAsCPUThread([&] { - m_controller->UpdateReferences(g_controller_interface); + for (const auto& name : g_controller_interface.GetAllDeviceStrings()) + { + const auto qname = QString::fromStdString(name); + m_devices_combo->addItem(qname, qname); + } - const auto default_device = m_controller->GetDefaultDevice().ToString(); + m_devices_combo->insertSeparator(m_devices_combo->count()); - if (!default_device.empty()) - m_devices_combo->addItem(QString::fromStdString(default_device)); + const auto default_device = m_controller->GetDefaultDevice().ToString(); - for (const auto& name : g_controller_interface.GetAllDeviceStrings()) + if (!default_device.empty()) + { + const auto default_device_index = + m_devices_combo->findText(QString::fromStdString(default_device)); + + if (default_device_index != -1) { - if (name != default_device) - m_devices_combo->addItem(QString::fromStdString(name)); + m_devices_combo->setCurrentIndex(default_device_index); } + else + { + // Selected device is not currently attached. + const auto qname = QString::fromStdString(default_device); + m_devices_combo->addItem( + QStringLiteral("[") + tr("disconnected") + QStringLiteral("] ") + qname, qname); + m_devices_combo->setCurrentIndex(m_devices_combo->count() - 1); + } + } - m_devices_combo->addItem(tr("All devices")); + m_devices_combo->addItem(tr("All devices")); - m_devices_combo->setCurrentIndex(0); - }); + m_devices_combo->blockSignals(old_state); } void MappingWindow::SetMappingType(MappingWindow::Type type) @@ -372,16 +395,11 @@ ControllerEmu::EmulatedController* MappingWindow::GetController() const return m_controller; } -std::shared_ptr MappingWindow::GetDevice() const -{ - return g_controller_interface.FindDevice(GetController()->GetDefaultDevice()); -} - void MappingWindow::OnDefaultFieldsPressed() { m_controller->LoadDefaults(g_controller_interface); m_controller->UpdateReferences(g_controller_interface); - emit Update(); + emit ConfigChanged(); emit Save(); } @@ -389,9 +407,14 @@ void MappingWindow::OnClearFieldsPressed() { // Loading an empty inifile section clears everything. IniFile::Section sec; + + // Keep the currently selected device. + const auto default_device = m_controller->GetDefaultDevice(); m_controller->LoadConfig(&sec); + m_controller->SetDefaultDevice(default_device); + m_controller->UpdateReferences(g_controller_interface); - emit Update(); + emit ConfigChanged(); emit Save(); } diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.h b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.h index 16585c89a9..ed6fe0fcb2 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.h +++ b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.h @@ -49,12 +49,14 @@ public: explicit MappingWindow(QWidget* parent, Type type, int port_num); int GetPort() const; - std::shared_ptr GetDevice() const; ControllerEmu::EmulatedController* GetController() const; bool IsIterativeInput() const; bool IsMappingAllDevices() const; signals: + // Emitted when config has changed so widgets can update to reflect the change. + void ConfigChanged(); + // Emitted at 30hz for real-time indicators to be updated. void Update(); void Save(); @@ -75,7 +77,7 @@ private: void OnSaveProfilePressed(); void OnDefaultFieldsPressed(); void OnClearFieldsPressed(); - void OnDeviceChanged(int index); + void OnSelectDevice(int index); void OnGlobalDevicesChanged(); ControllerEmu::EmulatedController* m_controller = nullptr;