From 1d664f88e56179a0f5da0cd687df2e19bfb79c4b Mon Sep 17 00:00:00 2001 From: pajlada Date: Sun, 15 Aug 2021 15:59:52 +0200 Subject: [PATCH] Keyboard integration for Streamlink quality confirmation (#3169) Co-authored-by: zneix --- src/util/StreamLink.cpp | 2 +- src/widgets/BasePopup.cpp | 64 ++++++++++++++++++++++++++++ src/widgets/BasePopup.hpp | 8 ++++ src/widgets/dialogs/QualityPopup.cpp | 50 +++++++++++++--------- src/widgets/dialogs/QualityPopup.hpp | 18 ++++---- 5 files changed, 111 insertions(+), 31 deletions(-) diff --git a/src/util/StreamLink.cpp b/src/util/StreamLink.cpp index 2ac42cfa6..b631cad51 100644 --- a/src/util/StreamLink.cpp +++ b/src/util/StreamLink.cpp @@ -200,7 +200,7 @@ void openStreamlinkForChannel(const QString &channel) if (preferredQuality == "choose") { getStreamQualities(channelURL, [=](QStringList qualityOptions) { - QualityPopup::showDialog(channel, qualityOptions); + QualityPopup::showDialog(channelURL, qualityOptions); }); return; diff --git a/src/widgets/BasePopup.cpp b/src/widgets/BasePopup.cpp index 0f3ed3c1d..afae740b6 100644 --- a/src/widgets/BasePopup.cpp +++ b/src/widgets/BasePopup.cpp @@ -1,5 +1,7 @@ #include "widgets/BasePopup.hpp" +#include +#include #include namespace chatterino { @@ -20,4 +22,66 @@ void BasePopup::keyPressEvent(QKeyEvent *e) BaseWindow::keyPressEvent(e); } +bool BasePopup::handleEscape(QKeyEvent *e, QDialogButtonBox *buttonBox) +{ + assert(buttonBox != nullptr); + + if (e->key() == Qt::Key_Escape) + { + auto buttons = buttonBox->buttons(); + for (auto *button : buttons) + { + if (auto role = buttonBox->buttonRole(button); + role == QDialogButtonBox::ButtonRole::RejectRole) + { + button->click(); + return true; + } + } + } + + return false; +} + +bool BasePopup::handleEnter(QKeyEvent *e, QDialogButtonBox *buttonBox) +{ + assert(buttonBox != nullptr); + + if (!e->modifiers() || + (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) + { + switch (e->key()) + { + case Qt::Key_Enter: + case Qt::Key_Return: { + auto buttons = buttonBox->buttons(); + QAbstractButton *acceptButton = nullptr; + for (auto *button : buttons) + { + if (button->hasFocus()) + { + button->click(); + return true; + } + + if (auto role = buttonBox->buttonRole(button); + role == QDialogButtonBox::ButtonRole::AcceptRole) + { + acceptButton = button; + } + } + + if (acceptButton != nullptr) + { + acceptButton->click(); + return true; + } + } + break; + } + } + + return false; +} + } // namespace chatterino diff --git a/src/widgets/BasePopup.hpp b/src/widgets/BasePopup.hpp index 5741b0006..d7942f2fc 100644 --- a/src/widgets/BasePopup.hpp +++ b/src/widgets/BasePopup.hpp @@ -3,6 +3,8 @@ #include "common/FlagsEnum.hpp" #include "widgets/BaseWindow.hpp" +class QDialogButtonBox; + namespace chatterino { class BasePopup : public BaseWindow @@ -13,6 +15,12 @@ public: protected: void keyPressEvent(QKeyEvent *e) override; + + // handleEscape is a helper function for clicking the "Reject" role button of a button box when the Escape button is pressed + bool handleEscape(QKeyEvent *e, QDialogButtonBox *buttonBox); + + // handleEnter is a helper function for clicking the "Accept" role button of a button box when Return or Enter is pressed + bool handleEnter(QKeyEvent *e, QDialogButtonBox *buttonBox); }; } // namespace chatterino diff --git a/src/widgets/dialogs/QualityPopup.cpp b/src/widgets/dialogs/QualityPopup.cpp index 414ab2548..52f7dba47 100644 --- a/src/widgets/dialogs/QualityPopup.cpp +++ b/src/widgets/dialogs/QualityPopup.cpp @@ -7,35 +7,32 @@ namespace chatterino { -QualityPopup::QualityPopup(const QString &_channelName, QStringList options) +QualityPopup::QualityPopup(const QString &channelURL, QStringList options) : BasePopup({}, static_cast(&(getApp()->windows->getMainWindow()))) - , channelName_(_channelName) + , channelURL_(channelURL) { - this->ui_.okButton.setText("OK"); - this->ui_.cancelButton.setText("Cancel"); + this->ui_.selector = new QComboBox(this); + this->ui_.vbox = new QVBoxLayout(this); + this->ui_.buttonBox = new QDialogButtonBox( + QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - QObject::connect(&this->ui_.okButton, &QPushButton::clicked, this, + QObject::connect(this->ui_.buttonBox, &QDialogButtonBox::accepted, this, &QualityPopup::okButtonClicked); - QObject::connect(&this->ui_.cancelButton, &QPushButton::clicked, this, + QObject::connect(this->ui_.buttonBox, &QDialogButtonBox::rejected, this, &QualityPopup::cancelButtonClicked); - this->ui_.buttonBox.addButton(&this->ui_.okButton, - QDialogButtonBox::ButtonRole::AcceptRole); - this->ui_.buttonBox.addButton(&this->ui_.cancelButton, - QDialogButtonBox::ButtonRole::RejectRole); + this->ui_.selector->addItems(options); - this->ui_.selector.addItems(options); + this->ui_.vbox->addWidget(this->ui_.selector); + this->ui_.vbox->addWidget(this->ui_.buttonBox); - this->ui_.vbox.addWidget(&this->ui_.selector); - this->ui_.vbox.addWidget(&this->ui_.buttonBox); - - this->setLayout(&this->ui_.vbox); + this->setLayout(this->ui_.vbox); } -void QualityPopup::showDialog(const QString &channelName, QStringList options) +void QualityPopup::showDialog(const QString &channelURL, QStringList options) { - QualityPopup *instance = new QualityPopup(channelName, options); + QualityPopup *instance = new QualityPopup(channelURL, options); instance->window()->setWindowTitle("Chatterino - select stream quality"); instance->setAttribute(Qt::WA_DeleteOnClose, true); @@ -43,16 +40,27 @@ void QualityPopup::showDialog(const QString &channelName, QStringList options) instance->show(); instance->activateWindow(); instance->raise(); - instance->setFocus(); +} + +void QualityPopup::keyPressEvent(QKeyEvent *e) +{ + if (this->handleEscape(e, this->ui_.buttonBox)) + { + return; + } + if (this->handleEnter(e, this->ui_.buttonBox)) + { + return; + } + + BasePopup::keyPressEvent(e); } void QualityPopup::okButtonClicked() { - QString channelURL = "twitch.tv/" + this->channelName_; - try { - openStreamlink(channelURL, this->ui_.selector.currentText()); + openStreamlink(this->channelURL_, this->ui_.selector->currentText()); } catch (const Exception &ex) { diff --git a/src/widgets/dialogs/QualityPopup.hpp b/src/widgets/dialogs/QualityPopup.hpp index cb5f06205..f0820218d 100644 --- a/src/widgets/dialogs/QualityPopup.hpp +++ b/src/widgets/dialogs/QualityPopup.hpp @@ -4,7 +4,6 @@ #include #include -#include #include namespace chatterino { @@ -12,22 +11,23 @@ namespace chatterino { class QualityPopup : public BasePopup { public: - QualityPopup(const QString &_channelName, QStringList options); - static void showDialog(const QString &_channelName, QStringList options); + QualityPopup(const QString &channelURL, QStringList options); + static void showDialog(const QString &channelURL, QStringList options); + +protected: + void keyPressEvent(QKeyEvent *e) override; private: void okButtonClicked(); void cancelButtonClicked(); struct { - QVBoxLayout vbox; - QComboBox selector; - QDialogButtonBox buttonBox; - QPushButton okButton; - QPushButton cancelButton; + QVBoxLayout *vbox; + QComboBox *selector; + QDialogButtonBox *buttonBox; } ui_; - QString channelName_; + QString channelURL_; }; } // namespace chatterino