DolphinQ: Mapping UI cleanups.

This commit is contained in:
Jordan Woyak 2019-03-14 20:27:49 -05:00
parent 011ecd92e8
commit 9cb17b062c
16 changed files with 185 additions and 224 deletions

View File

@ -40,7 +40,7 @@ IOWindow::IOWindow(QWidget* parent, ControllerEmu::EmulatedController* controlle
setWindowTitle(type == IOWindow::Type::Input ? tr("Configure Input") : tr("Configure Output")); setWindowTitle(type == IOWindow::Type::Input ? tr("Configure Input") : tr("Configure Output"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
Update(); ConfigChanged();
} }
void IOWindow::CreateMainLayout() void IOWindow::CreateMainLayout()
@ -115,8 +115,10 @@ void IOWindow::CreateMainLayout()
setLayout(m_main_layout); 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->setPlainText(QString::fromStdString(m_reference->GetExpression()));
m_expression_text->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); m_expression_text->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
m_range_spinbox->setValue(m_reference->range * SLIDER_TICK_COUNT); m_range_spinbox->setValue(m_reference->range * SLIDER_TICK_COUNT);
@ -126,6 +128,8 @@ void IOWindow::Update()
UpdateDeviceList(); UpdateDeviceList();
UpdateOptionList(); UpdateOptionList();
blockSignals(old_state);
} }
void IOWindow::ConnectWidgets() void IOWindow::ConnectWidgets()
@ -173,6 +177,7 @@ void IOWindow::OnDialogButtonPressed(QAbstractButton* button)
} }
m_reference->SetExpression(m_expression_text->toPlainText().toStdString()); m_reference->SetExpression(m_expression_text->toPlainText().toStdString());
m_controller->UpdateReferences(g_controller_interface);
if (button != m_apply_button) if (button != m_apply_button)
accept(); accept();
@ -234,21 +239,9 @@ void IOWindow::UpdateDeviceList()
{ {
m_devices_combo->clear(); m_devices_combo->clear();
Core::RunAsCPUThread([&] { for (const auto& name : g_controller_interface.GetAllDeviceStrings())
g_controller_interface.RefreshDevices(); m_devices_combo->addItem(QString::fromStdString(name));
m_controller->UpdateReferences(g_controller_interface);
// Adding default device regardless if it's currently connected or not m_devices_combo->setCurrentText(
const auto default_device = m_controller->GetDefaultDevice().ToString(); QString::fromStdString(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);
});
} }

View File

@ -43,7 +43,7 @@ public:
private: private:
void CreateMainLayout(); void CreateMainLayout();
void ConnectWidgets(); void ConnectWidgets();
void Update(); void ConfigChanged();
void OnDialogButtonPressed(QAbstractButton* button); void OnDialogButtonPressed(QAbstractButton* button);
void OnDeviceChanged(const QString& device); void OnDeviceChanged(const QString& device);

View File

@ -10,23 +10,20 @@
#include "InputCommon/ControllerEmu/Setting/BooleanSetting.h" #include "InputCommon/ControllerEmu/Setting/BooleanSetting.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/ControllerInterface.h"
MappingBool::MappingBool(MappingWidget* widget, ControllerEmu::BooleanSetting* setting) MappingBool::MappingBool(MappingWidget* parent, ControllerEmu::BooleanSetting* setting)
: QCheckBox(tr(setting->m_ui_name.c_str())), m_parent(widget), m_setting(setting) : QCheckBox(tr(setting->m_ui_name.c_str())), m_setting(*setting)
{ {
Update(); connect(this, &QCheckBox::stateChanged, this, [this, parent](int value) {
Connect(); m_setting.SetValue(value);
} parent->SaveSettings();
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(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);
} }

View File

@ -18,11 +18,8 @@ class MappingBool : public QCheckBox
public: public:
MappingBool(MappingWidget* widget, ControllerEmu::BooleanSetting* setting); MappingBool(MappingWidget* widget, ControllerEmu::BooleanSetting* setting);
void Update();
private: private:
void Connect(); void ConfigChanged();
MappingWidget* m_parent; ControllerEmu::BooleanSetting& m_setting;
ControllerEmu::BooleanSetting* m_setting;
}; };

View File

@ -9,7 +9,6 @@
#include <QMouseEvent> #include <QMouseEvent>
#include <QRegExp> #include <QRegExp>
#include <QString> #include <QString>
#include <QTimer>
#include "Common/Thread.h" #include "Common/Thread.h"
#include "Core/Core.h" #include "Core/Core.h"
@ -42,8 +41,8 @@ bool MappingButton::IsInput() const
return m_reference->IsInput(); return m_reference->IsInput();
} }
MappingButton::MappingButton(MappingWidget* widget, ControlReference* ref, bool indicator) MappingButton::MappingButton(MappingWidget* parent, ControlReference* ref, bool indicator)
: ElidedButton(ToDisplayString(QString::fromStdString(ref->GetExpression()))), m_parent(widget), : ElidedButton(ToDisplayString(QString::fromStdString(ref->GetExpression()))), m_parent(parent),
m_reference(ref) m_reference(ref)
{ {
// Force all mapping buttons to stay at a minimal height. // 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); setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
Connect();
setToolTip( setToolTip(
tr("Left-click to detect input.\nMiddle-click to clear.\nRight-click for more options.")); 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(this, &MappingButton::pressed, this, &MappingButton::Detect);
connect(m_timer, &QTimer::timeout, this, [this] {
if (!isActiveWindow())
return;
Settings::Instance().SetControllerStateNeeded(true); if (indicator)
connect(parent, &MappingWidget::Update, this, &MappingButton::UpdateIndicator);
if (Core::GetState() == Core::State::Uninitialized || Core::GetState() == Core::State::Paused) connect(parent, &MappingWidget::ConfigChanged, this, &MappingButton::ConfigChanged);
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);
} }
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() void MappingButton::Detect()
{ {
if (m_parent->GetDevice() == nullptr || !m_reference->IsInput()) if (!m_reference->IsInput())
return; return;
const auto default_device_qualifier = m_parent->GetController()->GetDefaultDevice(); const auto default_device_qualifier = m_parent->GetController()->GetDefaultDevice();
@ -121,27 +100,48 @@ void MappingButton::Detect()
return; return;
m_reference->SetExpression(expression.toStdString()); m_reference->SetExpression(expression.toStdString());
m_parent->SaveSettings();
Update();
m_parent->GetController()->UpdateReferences(g_controller_interface); m_parent->GetController()->UpdateReferences(g_controller_interface);
ConfigChanged();
m_parent->SaveSettings();
if (m_parent->IsIterativeInput()) if (m_parent->IsIterativeInput())
m_parent->NextButton(this); m_parent->NextButton(this);
} }
void MappingButton::Clear() void MappingButton::Clear()
{ {
m_reference->SetExpression("");
m_reference->range = 100.0 / SLIDER_TICK_COUNT; m_reference->range = 100.0 / SLIDER_TICK_COUNT;
m_reference->SetExpression("");
m_parent->GetController()->UpdateReferences(g_controller_interface);
m_parent->SaveSettings(); 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()))); setText(ToDisplayString(QString::fromStdString(m_reference->GetExpression())));
} }
@ -153,13 +153,13 @@ void MappingButton::mouseReleaseEvent(QMouseEvent* event)
if (m_reference->IsInput()) if (m_reference->IsInput())
QPushButton::mouseReleaseEvent(event); QPushButton::mouseReleaseEvent(event);
else else
emit AdvancedPressed(); AdvancedPressed();
return; return;
case Qt::MouseButton::MidButton: case Qt::MouseButton::MidButton:
Clear(); Clear();
return; return;
case Qt::MouseButton::RightButton: case Qt::MouseButton::RightButton:
emit AdvancedPressed(); AdvancedPressed();
return; return;
default: default:
return; return;

View File

@ -11,7 +11,6 @@ class ControlReference;
class MappingWidget; class MappingWidget;
class QEvent; class QEvent;
class QMouseEvent; class QMouseEvent;
class QTimer;
class MappingButton : public ElidedButton class MappingButton : public ElidedButton
{ {
@ -19,20 +18,17 @@ class MappingButton : public ElidedButton
public: public:
MappingButton(MappingWidget* widget, ControlReference* ref, bool indicator); MappingButton(MappingWidget* widget, ControlReference* ref, bool indicator);
void Clear();
void Update();
void Detect(); void Detect();
bool IsInput() const; bool IsInput() const;
signals: private:
void Clear();
void UpdateIndicator();
void ConfigChanged();
void AdvancedPressed(); void AdvancedPressed();
private:
void mouseReleaseEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override;
void Connect();
MappingWidget* m_parent; MappingWidget* m_parent;
ControlReference* m_reference; ControlReference* m_reference;
QTimer* m_timer;
}; };

View File

@ -67,6 +67,7 @@ QString DetectExpression(QPushButton* button, ciface::Core::DeviceContainer& dev
std::shared_ptr<ciface::Core::Device> device; std::shared_ptr<ciface::Core::Device> device;
ciface::Core::Device::Input* input; ciface::Core::Device::Input* input;
std::tie(device, input) = device_container.DetectInput(INPUT_DETECT_TIME, device_strings); std::tie(device, input) = device_container.DetectInput(INPUT_DETECT_TIME, device_strings);
button->releaseMouse(); button->releaseMouse();

View File

@ -23,6 +23,7 @@
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h" #include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
#include "InputCommon/ControllerInterface/Device.h" #include "InputCommon/ControllerInterface/Device.h"
#include "DolphinQt/Config/Mapping/MappingWidget.h"
#include "DolphinQt/QtUtils/ModalMessageBox.h" #include "DolphinQt/QtUtils/ModalMessageBox.h"
#include "DolphinQt/Settings.h" #include "DolphinQt/Settings.h"
@ -50,15 +51,9 @@ const QColor SWING_GATE_COLOR = 0xcea2d9;
constexpr int INPUT_DOT_RADIUS = 2; constexpr int INPUT_DOT_RADIUS = 2;
constexpr int INDICATOR_UPDATE_FREQ = 30;
MappingIndicator::MappingIndicator(ControllerEmu::ControlGroup* group) : m_group(group) MappingIndicator::MappingIndicator(ControllerEmu::ControlGroup* group) : m_group(group)
{ {
setMinimumHeight(128); setMinimumHeight(128);
const auto timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [this] { repaint(); });
timer->start(1000 / INDICATOR_UPDATE_FREQ);
} }
namespace namespace
@ -133,12 +128,8 @@ void MappingIndicator::DrawCursor(ControllerEmu::Cursor& cursor)
const QColor tv_brush_color = CURSOR_TV_COLOR; const QColor tv_brush_color = CURSOR_TV_COLOR;
const QColor tv_pen_color = tv_brush_color.darker(125); 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 raw_coord = cursor.GetState(false);
const auto adj_coord = cursor.GetState(true); const auto adj_coord = cursor.GetState(true);
Settings::Instance().SetControllerStateNeeded(false);
UpdateCalibrationWidget({raw_coord.x, raw_coord.y}); 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); 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); const auto raw_coord = stick.GetReshapableState(false);
Common::DVec2 adj_coord; Common::DVec2 adj_coord;
@ -267,8 +255,6 @@ void MappingIndicator::DrawReshapableInput(ControllerEmu::ReshapableInput& stick
adj_coord = stick.GetReshapableState(true); adj_coord = stick.GetReshapableState(true);
} }
Settings::Instance().SetControllerStateNeeded(false);
UpdateCalibrationWidget(raw_coord); UpdateCalibrationWidget(raw_coord);
// Bounding box size: // Bounding box size:
@ -343,10 +329,8 @@ void MappingIndicator::DrawMixedTriggers()
const std::array<u16, TRIGGER_COUNT> button_masks = {0x1, 0x2}; const std::array<u16, TRIGGER_COUNT> button_masks = {0x1, 0x2};
u16 button_state = 0; 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(), raw_analog_state.data(), false);
triggers.GetState(&button_state, button_masks.data(), adj_analog_state.data(), true); triggers.GetState(&button_state, button_masks.data(), adj_analog_state.data(), true);
Settings::Instance().SetControllerStateNeeded(false);
// Rectangle sizes: // Rectangle sizes:
const int trigger_height = 32; 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_brush_color = SWING_GATE_COLOR;
const QColor gate_pen_color = gate_brush_color.darker(125); 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); const auto raw_coord = force.GetState(false);
WiimoteEmu::EmulateSwing(&m_motion_state, &force, 1.f / INDICATOR_UPDATE_FREQ); WiimoteEmu::EmulateSwing(&m_motion_state, &force, 1.f / INDICATOR_UPDATE_FREQ);
const auto& adj_coord = m_motion_state.position; const auto& adj_coord = m_motion_state.position;
Settings::Instance().SetControllerStateNeeded(false);
UpdateCalibrationWidget({raw_coord.x, raw_coord.y}); UpdateCalibrationWidget({raw_coord.x, raw_coord.y});
@ -520,6 +500,9 @@ void MappingIndicator::DrawForce(ControllerEmu::Force& force)
void MappingIndicator::paintEvent(QPaintEvent*) void MappingIndicator::paintEvent(QPaintEvent*)
{ {
// TODO: The SetControllerStateNeeded interface leaks input into the game.
Settings::Instance().SetControllerStateNeeded(true);
switch (m_group->type) switch (m_group->type)
{ {
case ControllerEmu::GroupType::Cursor: case ControllerEmu::GroupType::Cursor:
@ -538,6 +521,8 @@ void MappingIndicator::paintEvent(QPaintEvent*)
default: default:
break; break;
} }
Settings::Instance().SetControllerStateNeeded(false);
} }
void MappingIndicator::DrawCalibration(QPainter& p, Common::DVec2 point) void MappingIndicator::DrawCalibration(QPainter& p, Common::DVec2 point)

View File

@ -10,25 +10,23 @@
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h" #include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/ControllerInterface.h"
MappingNumeric::MappingNumeric(MappingWidget* widget, ControllerEmu::NumericSetting* setting) MappingNumeric::MappingNumeric(MappingWidget* parent, ControllerEmu::NumericSetting* setting)
: m_parent(widget), m_setting(setting) : m_setting(*setting)
{ {
setRange(setting->m_low, setting->m_high); setRange(setting->m_low, setting->m_high);
Update();
Connect();
}
void MappingNumeric::Connect()
{
connect(this, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, connect(this, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
[this](int value) { [this, parent](int value) {
m_setting->SetValue(static_cast<double>(value) / 100); m_setting.SetValue(static_cast<double>(value) / 100);
m_parent->SaveSettings(); parent->SaveSettings();
m_parent->GetController()->UpdateReferences(g_controller_interface);
}); });
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);
} }

View File

@ -19,11 +19,8 @@ class MappingNumeric : public QSpinBox
public: public:
MappingNumeric(MappingWidget* widget, ControllerEmu::NumericSetting* ref); MappingNumeric(MappingWidget* widget, ControllerEmu::NumericSetting* ref);
void Update();
private: private:
void Connect(); void ConfigChanged();
MappingWidget* m_parent; ControllerEmu::NumericSetting& m_setting;
ControllerEmu::NumericSetting* m_setting;
}; };

View File

@ -10,23 +10,20 @@
#include "InputCommon/ControllerEmu/Setting/BooleanSetting.h" #include "InputCommon/ControllerEmu/Setting/BooleanSetting.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/ControllerInterface.h"
MappingRadio::MappingRadio(MappingWidget* widget, ControllerEmu::BooleanSetting* setting) MappingRadio::MappingRadio(MappingWidget* parent, ControllerEmu::BooleanSetting* setting)
: QRadioButton(tr(setting->m_ui_name.c_str())), m_parent(widget), m_setting(setting) : QRadioButton(tr(setting->m_ui_name.c_str())), m_setting(*setting)
{ {
Update(); connect(this, &QRadioButton::toggled, this, [this, parent](int value) {
Connect(); m_setting.SetValue(value);
} parent->SaveSettings();
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(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);
} }

View File

@ -18,11 +18,8 @@ class MappingRadio : public QRadioButton
public: public:
MappingRadio(MappingWidget* widget, ControllerEmu::BooleanSetting* setting); MappingRadio(MappingWidget* widget, ControllerEmu::BooleanSetting* setting);
void Update();
private: private:
void Connect(); void ConfigChanged();
MappingWidget* m_parent; ControllerEmu::BooleanSetting& m_setting;
ControllerEmu::BooleanSetting* m_setting;
}; };

View File

@ -7,6 +7,7 @@
#include <QFormLayout> #include <QFormLayout>
#include <QGroupBox> #include <QGroupBox>
#include <QPushButton> #include <QPushButton>
#include <QTimer>
#include "DolphinQt/Config/Mapping/IOWindow.h" #include "DolphinQt/Config/Mapping/IOWindow.h"
#include "DolphinQt/Config/Mapping/MappingBool.h" #include "DolphinQt/Config/Mapping/MappingBool.h"
@ -15,18 +16,32 @@
#include "DolphinQt/Config/Mapping/MappingNumeric.h" #include "DolphinQt/Config/Mapping/MappingNumeric.h"
#include "DolphinQt/Config/Mapping/MappingRadio.h" #include "DolphinQt/Config/Mapping/MappingRadio.h"
#include "DolphinQt/Config/Mapping/MappingWindow.h" #include "DolphinQt/Config/Mapping/MappingWindow.h"
#include "DolphinQt/Settings.h"
#include "InputCommon/ControlReference/ControlReference.h" #include "InputCommon/ControlReference/ControlReference.h"
#include "InputCommon/ControllerEmu/Control/Control.h" #include "InputCommon/ControllerEmu/Control/Control.h"
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" #include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
#include "InputCommon/ControllerEmu/ControllerEmu.h"
#include "InputCommon/ControllerEmu/Setting/BooleanSetting.h" #include "InputCommon/ControllerEmu/Setting/BooleanSetting.h"
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h" #include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
#include "InputCommon/ControllerEmu/StickGate.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(parent, &MappingWindow::Update, this, &MappingWidget::Update);
connect(window, &MappingWindow::Save, this, &MappingWidget::SaveSettings); 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 MappingWindow* MappingWidget::GetParent() const
@ -57,11 +72,6 @@ void MappingWidget::NextButton(MappingButton* button)
NextButton(next); NextButton(next);
} }
std::shared_ptr<ciface::Core::Device> MappingWidget::GetDevice() const
{
return m_parent->GetDevice();
}
int MappingWidget::GetPort() const int MappingWidget::GetPort() const
{ {
return m_parent->GetPort(); 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); translate ? tr(control->ui_name.c_str()) : QString::fromStdString(control->ui_name);
form_layout->addRow(translated_name, button); 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); m_buttons.push_back(button);
} }
@ -116,7 +113,6 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con
{ {
auto* spinbox = new MappingNumeric(this, numeric.get()); auto* spinbox = new MappingNumeric(this, numeric.get());
form_layout->addRow(tr(numeric->m_name.c_str()), spinbox); form_layout->addRow(tr(numeric->m_name.c_str()), spinbox);
m_numerics.push_back(spinbox);
} }
for (auto& boolean : group->boolean_settings) 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()); auto* checkbox = new MappingRadio(this, boolean.get());
form_layout->addRow(checkbox); form_layout->addRow(checkbox);
m_radio.push_back(checkbox);
} }
for (auto& boolean : group->boolean_settings) 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()); auto* checkbox = new MappingBool(this, boolean.get());
form_layout->addRow(checkbox); form_layout->addRow(checkbox);
m_bools.push_back(checkbox);
} }
if (need_indicator) if (need_indicator)
{ {
auto const indicator = new MappingIndicator(group); auto const indicator = new MappingIndicator(group);
connect(this, &MappingWidget::Update, indicator, QOverload<>::of(&MappingIndicator::update));
if (need_calibration) if (need_calibration)
{ {
@ -159,23 +154,6 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con
return group_box; 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 ControllerEmu::EmulatedController* MappingWidget::GetController() const
{ {
return m_parent->GetController(); return m_parent->GetController();

View File

@ -35,6 +35,8 @@ class Device;
} }
} // namespace ciface } // namespace ciface
constexpr int INDICATOR_UPDATE_FREQ = 30;
class MappingWidget : public QWidget class MappingWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
@ -42,7 +44,6 @@ public:
explicit MappingWidget(MappingWindow* window); explicit MappingWidget(MappingWindow* window);
ControllerEmu::EmulatedController* GetController() const; ControllerEmu::EmulatedController* GetController() const;
std::shared_ptr<ciface::Core::Device> GetDevice() const;
MappingWindow* GetParent() const; MappingWindow* GetParent() const;
@ -53,7 +54,9 @@ public:
virtual void SaveSettings() = 0; virtual void SaveSettings() = 0;
virtual InputConfig* GetConfig() = 0; virtual InputConfig* GetConfig() = 0;
signals:
void Update(); void Update();
void ConfigChanged();
protected: protected:
int GetPort() const; int GetPort() const;
@ -62,8 +65,5 @@ protected:
private: private:
MappingWindow* m_parent; MappingWindow* m_parent;
bool m_first = true; bool m_first = true;
std::vector<MappingBool*> m_bools;
std::vector<MappingRadio*> m_radio;
std::vector<MappingButton*> m_buttons; std::vector<MappingButton*> m_buttons;
std::vector<MappingNumeric*> m_numerics;
}; };

View File

@ -13,13 +13,13 @@
#include <QTabWidget> #include <QTabWidget>
#include <QVBoxLayout> #include <QVBoxLayout>
#include "Core/Core.h"
#include "Common/FileSearch.h" #include "Common/FileSearch.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/IniFile.h" #include "Common/IniFile.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Core/Core.h"
#include "DolphinQt/Config/Mapping/GCKeyboardEmu.h" #include "DolphinQt/Config/Mapping/GCKeyboardEmu.h"
#include "DolphinQt/Config/Mapping/GCMicrophone.h" #include "DolphinQt/Config/Mapping/GCMicrophone.h"
#include "DolphinQt/Config/Mapping/GCPadEmu.h" #include "DolphinQt/Config/Mapping/GCPadEmu.h"
@ -58,6 +58,8 @@ MappingWindow::MappingWindow(QWidget* parent, Type type, int port_num)
CreateMainLayout(); CreateMainLayout();
ConnectWidgets(); ConnectWidgets();
SetMappingType(type); SetMappingType(type);
emit ConfigChanged();
} }
void MappingWindow::CreateDevicesLayout() void MappingWindow::CreateDevicesLayout()
@ -141,17 +143,21 @@ void MappingWindow::ConnectWidgets()
{ {
connect(&Settings::Instance(), &Settings::DevicesChanged, this, connect(&Settings::Instance(), &Settings::DevicesChanged, this,
&MappingWindow::OnGlobalDevicesChanged); &MappingWindow::OnGlobalDevicesChanged);
connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(this, &MappingWindow::ConfigChanged, this, &MappingWindow::OnGlobalDevicesChanged);
connect(m_devices_refresh, &QPushButton::clicked, this, &MappingWindow::RefreshDevices);
connect(m_devices_combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), connect(m_devices_combo, static_cast<void (QComboBox::*)(int)>(&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_clear, &QPushButton::clicked, this, &MappingWindow::OnClearFieldsPressed);
connect(m_reset_default, &QPushButton::clicked, this, &MappingWindow::OnDefaultFieldsPressed); connect(m_reset_default, &QPushButton::clicked, this, &MappingWindow::OnDefaultFieldsPressed);
connect(m_profiles_save, &QPushButton::clicked, this, &MappingWindow::OnSaveProfilePressed); connect(m_profiles_save, &QPushButton::clicked, this, &MappingWindow::OnSaveProfilePressed);
connect(m_profiles_load, &QPushButton::clicked, this, &MappingWindow::OnLoadProfilePressed); connect(m_profiles_load, &QPushButton::clicked, this, &MappingWindow::OnLoadProfilePressed);
connect(m_profiles_delete, &QPushButton::clicked, this, &MappingWindow::OnDeleteProfilePressed); 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. // We currently use the "Close" button as an "Accept" button so we must save on reject.
connect(this, &QDialog::rejected, [this] { emit Save(); }); connect(this, &QDialog::rejected, [this] { emit Save(); });
connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
} }
void MappingWindow::OnDeleteProfilePressed() void MappingWindow::OnDeleteProfilePressed()
@ -206,9 +212,7 @@ void MappingWindow::OnLoadProfilePressed()
m_controller->LoadConfig(ini.GetOrCreateSection("Profile")); m_controller->LoadConfig(ini.GetOrCreateSection("Profile"));
m_controller->UpdateReferences(g_controller_interface); m_controller->UpdateReferences(g_controller_interface);
emit Update(); emit ConfigChanged();
RefreshDevices();
} }
void MappingWindow::OnSaveProfilePressed() void MappingWindow::OnSaveProfilePressed()
@ -235,13 +239,16 @@ void MappingWindow::OnSaveProfilePressed()
} }
} }
void MappingWindow::OnDeviceChanged(int index) void MappingWindow::OnSelectDevice(int index)
{ {
if (IsMappingAllDevices()) if (IsMappingAllDevices())
return; 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->SetDefaultDevice(device);
m_controller->UpdateReferences(g_controller_interface);
} }
bool MappingWindow::IsMappingAllDevices() const bool MappingWindow::IsMappingAllDevices() const
@ -256,26 +263,42 @@ void MappingWindow::RefreshDevices()
void MappingWindow::OnGlobalDevicesChanged() void MappingWindow::OnGlobalDevicesChanged()
{ {
const auto old_state = m_devices_combo->blockSignals(true);
m_devices_combo->clear(); m_devices_combo->clear();
Core::RunAsCPUThread([&] { for (const auto& name : g_controller_interface.GetAllDeviceStrings())
m_controller->UpdateReferences(g_controller_interface); {
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()) 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 (!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->setCurrentIndex(default_device_index);
m_devices_combo->addItem(QString::fromStdString(name));
} }
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) void MappingWindow::SetMappingType(MappingWindow::Type type)
@ -372,16 +395,11 @@ ControllerEmu::EmulatedController* MappingWindow::GetController() const
return m_controller; return m_controller;
} }
std::shared_ptr<ciface::Core::Device> MappingWindow::GetDevice() const
{
return g_controller_interface.FindDevice(GetController()->GetDefaultDevice());
}
void MappingWindow::OnDefaultFieldsPressed() void MappingWindow::OnDefaultFieldsPressed()
{ {
m_controller->LoadDefaults(g_controller_interface); m_controller->LoadDefaults(g_controller_interface);
m_controller->UpdateReferences(g_controller_interface); m_controller->UpdateReferences(g_controller_interface);
emit Update(); emit ConfigChanged();
emit Save(); emit Save();
} }
@ -389,9 +407,14 @@ void MappingWindow::OnClearFieldsPressed()
{ {
// Loading an empty inifile section clears everything. // Loading an empty inifile section clears everything.
IniFile::Section sec; IniFile::Section sec;
// Keep the currently selected device.
const auto default_device = m_controller->GetDefaultDevice();
m_controller->LoadConfig(&sec); m_controller->LoadConfig(&sec);
m_controller->SetDefaultDevice(default_device);
m_controller->UpdateReferences(g_controller_interface); m_controller->UpdateReferences(g_controller_interface);
emit Update(); emit ConfigChanged();
emit Save(); emit Save();
} }

View File

@ -49,12 +49,14 @@ public:
explicit MappingWindow(QWidget* parent, Type type, int port_num); explicit MappingWindow(QWidget* parent, Type type, int port_num);
int GetPort() const; int GetPort() const;
std::shared_ptr<ciface::Core::Device> GetDevice() const;
ControllerEmu::EmulatedController* GetController() const; ControllerEmu::EmulatedController* GetController() const;
bool IsIterativeInput() const; bool IsIterativeInput() const;
bool IsMappingAllDevices() const; bool IsMappingAllDevices() const;
signals: 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 Update();
void Save(); void Save();
@ -75,7 +77,7 @@ private:
void OnSaveProfilePressed(); void OnSaveProfilePressed();
void OnDefaultFieldsPressed(); void OnDefaultFieldsPressed();
void OnClearFieldsPressed(); void OnClearFieldsPressed();
void OnDeviceChanged(int index); void OnSelectDevice(int index);
void OnGlobalDevicesChanged(); void OnGlobalDevicesChanged();
ControllerEmu::EmulatedController* m_controller = nullptr; ControllerEmu::EmulatedController* m_controller = nullptr;