Qt: Add "Clear All" and "Rebind All" to controller bindings

This commit is contained in:
Connor McLaughlin 2020-03-22 00:50:09 +10:00
parent 45050709f2
commit ad6e4cb6e4
5 changed files with 117 additions and 19 deletions

View file

@ -22,6 +22,15 @@ InputBindingWidget::~InputBindingWidget()
Q_ASSERT(!isListeningForInput()); Q_ASSERT(!isListeningForInput());
} }
void InputBindingWidget::beginRebindAll()
{
m_is_binding_all = true;
if (isListeningForInput())
stopListeningForInput();
startListeningForInput(TIMEOUT_FOR_ALL_BINDING);
}
bool InputBindingWidget::eventFilter(QObject* watched, QEvent* event) bool InputBindingWidget::eventFilter(QObject* watched, QEvent* event)
{ {
const QEvent::Type event_type = event->type(); const QEvent::Type event_type = event->type();
@ -71,7 +80,7 @@ void InputBindingWidget::onPressed()
if (isListeningForInput()) if (isListeningForInput())
stopListeningForInput(); stopListeningForInput();
startListeningForInput(); startListeningForInput(TIMEOUT_FOR_SINGLE_BINDING);
} }
void InputBindingWidget::onInputListenTimerTimeout() void InputBindingWidget::onInputListenTimerTimeout()
@ -86,7 +95,7 @@ void InputBindingWidget::onInputListenTimerTimeout()
setText(tr("Push Button/Axis... [%1]").arg(m_input_listen_remaining_seconds)); setText(tr("Push Button/Axis... [%1]").arg(m_input_listen_remaining_seconds));
} }
void InputBindingWidget::startListeningForInput() void InputBindingWidget::startListeningForInput(u32 timeout_in_seconds)
{ {
m_input_listen_timer = new QTimer(this); m_input_listen_timer = new QTimer(this);
m_input_listen_timer->setSingleShot(false); m_input_listen_timer->setSingleShot(false);
@ -94,7 +103,7 @@ void InputBindingWidget::startListeningForInput()
m_input_listen_timer->connect(m_input_listen_timer, &QTimer::timeout, this, m_input_listen_timer->connect(m_input_listen_timer, &QTimer::timeout, this,
&InputBindingWidget::onInputListenTimerTimeout); &InputBindingWidget::onInputListenTimerTimeout);
m_input_listen_remaining_seconds = 5; m_input_listen_remaining_seconds = timeout_in_seconds;
setText(tr("Push Button/Axis... [%1]").arg(m_input_listen_remaining_seconds)); setText(tr("Push Button/Axis... [%1]").arg(m_input_listen_remaining_seconds));
installEventFilter(this); installEventFilter(this);
@ -111,6 +120,10 @@ void InputBindingWidget::stopListeningForInput()
releaseMouse(); releaseMouse();
releaseKeyboard(); releaseKeyboard();
removeEventFilter(this); removeEventFilter(this);
if (m_is_binding_all && m_next_widget)
m_next_widget->beginRebindAll();
m_is_binding_all = false;
} }
InputButtonBindingWidget::InputButtonBindingWidget(QtHostInterface* host_interface, QString setting_name, InputButtonBindingWidget::InputButtonBindingWidget(QtHostInterface* host_interface, QString setting_name,
@ -203,9 +216,9 @@ void InputButtonBindingWidget::bindToControllerButton(int controller_index, int
stopListeningForInput(); stopListeningForInput();
} }
void InputButtonBindingWidget::startListeningForInput() void InputButtonBindingWidget::startListeningForInput(u32 timeout_in_seconds)
{ {
InputBindingWidget::startListeningForInput(); InputBindingWidget::startListeningForInput(timeout_in_seconds);
hookControllerInput(); hookControllerInput();
} }
@ -266,9 +279,9 @@ void InputAxisBindingWidget::bindToControllerAxis(int controller_index, int axis
stopListeningForInput(); stopListeningForInput();
} }
void InputAxisBindingWidget::startListeningForInput() void InputAxisBindingWidget::startListeningForInput(u32 timeout_in_seconds)
{ {
InputBindingWidget::startListeningForInput(); InputBindingWidget::startListeningForInput(timeout_in_seconds);
hookControllerInput(); hookControllerInput();
} }

View file

@ -14,21 +14,32 @@ public:
InputBindingWidget(QtHostInterface* host_interface, QString setting_name, QWidget* parent); InputBindingWidget(QtHostInterface* host_interface, QString setting_name, QWidget* parent);
~InputBindingWidget(); ~InputBindingWidget();
protected: ALWAYS_INLINE InputBindingWidget* getNextWidget() const { return m_next_widget; }
virtual bool eventFilter(QObject* watched, QEvent* event) override; ALWAYS_INLINE void setNextWidget(InputBindingWidget* widget) { m_next_widget = widget; }
virtual void mouseReleaseEvent(QMouseEvent* e) override;
public Q_SLOTS:
void beginRebindAll();
void clearBinding();
protected Q_SLOTS: protected Q_SLOTS:
void onPressed(); void onPressed();
void onInputListenTimerTimeout(); void onInputListenTimerTimeout();
protected: protected:
virtual void startListeningForInput(); enum : u32
{
TIMEOUT_FOR_SINGLE_BINDING = 5,
TIMEOUT_FOR_ALL_BINDING = 10
};
virtual bool eventFilter(QObject* watched, QEvent* event) override;
virtual void mouseReleaseEvent(QMouseEvent* e) override;
virtual void startListeningForInput(u32 timeout_in_seconds);
virtual void stopListeningForInput(); virtual void stopListeningForInput();
bool isListeningForInput() const { return m_input_listen_timer != nullptr; } bool isListeningForInput() const { return m_input_listen_timer != nullptr; }
void setNewBinding(); void setNewBinding();
void clearBinding();
QtHostInterface* m_host_interface; QtHostInterface* m_host_interface;
QString m_setting_name; QString m_setting_name;
@ -36,6 +47,9 @@ protected:
QString m_new_binding_value; QString m_new_binding_value;
QTimer* m_input_listen_timer = nullptr; QTimer* m_input_listen_timer = nullptr;
u32 m_input_listen_remaining_seconds = 0; u32 m_input_listen_remaining_seconds = 0;
InputBindingWidget* m_next_widget = nullptr;
bool m_is_binding_all = false;
}; };
class InputButtonBindingWidget : public InputBindingWidget class InputButtonBindingWidget : public InputBindingWidget
@ -54,7 +68,7 @@ private Q_SLOTS:
void bindToControllerButton(int controller_index, int button_index); void bindToControllerButton(int controller_index, int button_index);
protected: protected:
void startListeningForInput() override; void startListeningForInput(u32 timeout_in_seconds) override;
void stopListeningForInput() override; void stopListeningForInput() override;
void hookControllerInput(); void hookControllerInput();
void unhookControllerInput(); void unhookControllerInput();
@ -72,7 +86,7 @@ private Q_SLOTS:
void bindToControllerAxis(int controller_index, int axis_index); void bindToControllerAxis(int controller_index, int axis_index);
protected: protected:
void startListeningForInput() override; void startListeningForInput(u32 timeout_in_seconds) override;
void stopListeningForInput() override; void stopListeningForInput() override;
void hookControllerInput(); void hookControllerInput();
void unhookControllerInput(); void unhookControllerInput();

View file

@ -6,6 +6,7 @@
#include "qtutils.h" #include "qtutils.h"
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtGui/QKeyEvent> #include <QtGui/QKeyEvent>
#include <QtWidgets/QMessageBox>
PortSettingsWidget::PortSettingsWidget(QtHostInterface* host_interface, QWidget* parent /* = nullptr */) PortSettingsWidget::PortSettingsWidget(QtHostInterface* host_interface, QWidget* parent /* = nullptr */)
: QWidget(parent), m_host_interface(host_interface) : QWidget(parent), m_host_interface(host_interface)
@ -43,6 +44,8 @@ void PortSettingsWidget::createPortSettingsUi(int index, PortSettingsUI* ui)
ui->layout->addWidget(new QLabel(tr("Memory Card Path:"), ui->widget)); ui->layout->addWidget(new QLabel(tr("Memory Card Path:"), ui->widget));
ui->layout->addLayout(memory_card_layout); ui->layout->addLayout(memory_card_layout);
ui->layout->addWidget(new QLabel(tr("Controller Type:"), ui->widget));
ui->controller_type = new QComboBox(ui->widget); ui->controller_type = new QComboBox(ui->widget);
for (int i = 0; i < static_cast<int>(ControllerType::Count); i++) for (int i = 0; i < static_cast<int>(ControllerType::Count); i++)
{ {
@ -58,7 +61,7 @@ void PortSettingsWidget::createPortSettingsUi(int index, PortSettingsUI* ui)
ui->controller_type->setCurrentIndex(static_cast<int>(ctype)); ui->controller_type->setCurrentIndex(static_cast<int>(ctype));
connect(ui->controller_type, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), connect(ui->controller_type, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
[this, index]() { onControllerTypeChanged(index); }); [this, index]() { onControllerTypeChanged(index); });
ui->layout->addWidget(new QLabel(tr("Controller Type:"), ui->widget));
ui->layout->addWidget(ui->controller_type); ui->layout->addWidget(ui->controller_type);
createPortBindingSettingsUi(index, ui, ctype); createPortBindingSettingsUi(index, ui, ctype);
@ -77,13 +80,13 @@ void PortSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI*
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
const auto buttons = Controller::GetButtonNames(ctype); const auto buttons = Controller::GetButtonNames(ctype);
InputBindingWidget* first_button = nullptr;
InputBindingWidget* last_button = nullptr;
int start_row = 0; int start_row = 0;
if (!buttons.empty()) if (!buttons.empty())
{ {
QFrame* line = new QFrame(container); layout->addWidget(QtUtils::CreateHorizontalLine(container), start_row++, 0, 1, 4);
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line, start_row++, 0, 1, 4);
layout->addWidget(new QLabel(tr("Button Bindings:"), container), start_row++, 0, 1, 4); layout->addWidget(new QLabel(tr("Button Bindings:"), container), start_row++, 0, 1, 4);
const int num_rows = (static_cast<int>(buttons.size()) + 1) / 2; const int num_rows = (static_cast<int>(buttons.size()) + 1) / 2;
@ -104,6 +107,12 @@ void PortSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI*
layout->addWidget(label, start_row + current_row, current_column); layout->addWidget(label, start_row + current_row, current_column);
layout->addWidget(button, start_row + current_row, current_column + 1); layout->addWidget(button, start_row + current_row, current_column + 1);
if (!first_button)
first_button = button;
if (last_button)
last_button->setNextWidget(button);
last_button = button;
current_row++; current_row++;
} }
@ -137,12 +146,62 @@ void PortSettingsWidget::createPortBindingSettingsUi(int index, PortSettingsUI*
layout->addWidget(label, start_row + current_row, current_column); layout->addWidget(label, start_row + current_row, current_column);
layout->addWidget(button, start_row + current_row, current_column + 1); layout->addWidget(button, start_row + current_row, current_column + 1);
if (!first_button)
first_button = button;
if (last_button)
last_button->setNextWidget(button);
last_button = button;
current_row++; current_row++;
} }
start_row += num_rows; start_row += num_rows;
} }
layout->addWidget(QtUtils::CreateHorizontalLine(ui->widget), start_row++, 0, 1, 4);
if (first_button)
{
QHBoxLayout* hbox = new QHBoxLayout();
QPushButton* clear_all_button = new QPushButton(tr("Clear All"), ui->widget);
clear_all_button->connect(clear_all_button, &QPushButton::pressed, [this, first_button]() {
if (QMessageBox::question(this, tr("Clear Bindings"),
tr("Are you sure you want to clear all bound controls? This cannot be reversed.")) !=
QMessageBox::Yes)
{
return;
}
InputBindingWidget* widget = first_button;
while (widget)
{
widget->clearBinding();
widget = widget->getNextWidget();
}
});
QPushButton* rebind_all_button = new QPushButton(tr("Rebind All"), ui->widget);
rebind_all_button->connect(rebind_all_button, &QPushButton::pressed, [this, first_button]() {
if (QMessageBox::question(this, tr("Clear Bindings"), tr("Do you want to clear all currently-bound controls?")) ==
QMessageBox::Yes)
{
InputBindingWidget* widget = first_button;
while (widget)
{
widget->clearBinding();
widget = widget->getNextWidget();
}
}
first_button->beginRebindAll();
});
hbox->addWidget(clear_all_button);
hbox->addWidget(rebind_all_button);
layout->addLayout(hbox, start_row++, 0, 1, 4, Qt::AlignRight);
}
if (ui->button_binding_container) if (ui->button_binding_container)
{ {
QLayoutItem* old_item = ui->layout->replaceWidget(ui->button_binding_container, container); QLayoutItem* old_item = ui->layout->replaceWidget(ui->button_binding_container, container);

View file

@ -13,6 +13,14 @@
namespace QtUtils { namespace QtUtils {
QFrame* CreateHorizontalLine(QWidget* parent)
{
QFrame* line = new QFrame(parent);
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
return line;
}
QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog) QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog)
{ {
QWidget* next_parent = widget->parentWidget(); QWidget* next_parent = widget->parentWidget();

View file

@ -6,12 +6,16 @@
class ByteStream; class ByteStream;
class QFrame;
class QKeyEvent; class QKeyEvent;
class QTableView; class QTableView;
class QWidget; class QWidget;
namespace QtUtils { namespace QtUtils {
/// Creates a horizontal line widget.
QFrame* CreateHorizontalLine(QWidget* parent);
/// Returns the greatest parent of a widget, i.e. its dialog/window. /// Returns the greatest parent of a widget, i.e. its dialog/window.
QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog = true); QWidget* GetRootWidget(QWidget* widget, bool stop_at_window_or_dialog = true);