From 3eb9a166b2e0e1db90b76c4a148391200a244ca6 Mon Sep 17 00:00:00 2001 From: Tal Neoran Date: Sun, 6 Jun 2021 14:07:42 +0300 Subject: [PATCH 1/8] Add username completion popup menu --- chatterino.pro | 4 + src/CMakeLists.txt | 4 + src/widgets/listview/GenericListModel.hpp | 2 + src/widgets/splits/SplitInput.cpp | 105 ++++++++++++++++++---- src/widgets/splits/SplitInput.hpp | 8 +- src/widgets/splits/UsernameInputItem.cpp | 30 +++++++ src/widgets/splits/UsernameInputItem.hpp | 26 ++++++ src/widgets/splits/UsernameInputPopup.cpp | 84 +++++++++++++++++ src/widgets/splits/UsernameInputPopup.hpp | 42 +++++++++ 9 files changed, 287 insertions(+), 18 deletions(-) create mode 100644 src/widgets/splits/UsernameInputItem.cpp create mode 100644 src/widgets/splits/UsernameInputItem.hpp create mode 100644 src/widgets/splits/UsernameInputPopup.cpp create mode 100644 src/widgets/splits/UsernameInputPopup.hpp diff --git a/chatterino.pro b/chatterino.pro index 2dfee10d3d9..205b410ac5b 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -325,6 +325,8 @@ SOURCES += \ src/widgets/splits/SplitHeader.cpp \ src/widgets/splits/SplitInput.cpp \ src/widgets/splits/SplitOverlay.cpp \ + src/widgets/splits/UsernameInputItem.cpp \ + src/widgets/splits/UsernameInputPopup.cpp \ src/widgets/StreamView.cpp \ src/widgets/TooltipWidget.cpp \ src/widgets/Window.cpp \ @@ -586,6 +588,8 @@ HEADERS += \ src/widgets/splits/SplitHeader.hpp \ src/widgets/splits/SplitInput.hpp \ src/widgets/splits/SplitOverlay.hpp \ + src/widgets/splits/UsernameInputItem.hpp \ + src/widgets/splits/UsernameInputPopup.hpp \ src/widgets/StreamView.hpp \ src/widgets/TooltipWidget.hpp \ src/widgets/Window.hpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e71eceec390..cd122b8dff0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -448,6 +448,10 @@ set(SOURCE_FILES main.cpp widgets/splits/SplitInput.hpp widgets/splits/SplitOverlay.cpp widgets/splits/SplitOverlay.hpp + widgets/splits/UsernameInputItem.cpp + widgets/splits/UsernameInputItem.hpp + widgets/splits/UsernameInputPopup.cpp + widgets/splits/UsernameInputPopup.hpp autogenerated/ResourcesAutogen.cpp autogenerated/ResourcesAutogen.hpp diff --git a/src/widgets/listview/GenericListModel.hpp b/src/widgets/listview/GenericListModel.hpp index 767ff6915d8..41d4a85c929 100644 --- a/src/widgets/listview/GenericListModel.hpp +++ b/src/widgets/listview/GenericListModel.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "widgets/listview/GenericListItem.hpp" #include diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index f9fbb6f532c..8218b0c93da 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -19,6 +19,7 @@ #include "widgets/splits/Split.hpp" #include "widgets/splits/SplitContainer.hpp" #include "widgets/splits/SplitInput.hpp" +#include "widgets/splits/UsernameInputPopup.hpp" #include #include @@ -46,6 +47,7 @@ SplitInput::SplitInput(Split *_chatWidget) this->installKeyPressedEvent(); this->ui_.textEdit->focusLost.connect([this] { this->hideColonMenu(); + this->hideUsernameMenu(); }); this->scaleChangedEvent(this->scale()); } @@ -213,6 +215,17 @@ void SplitInput::installKeyPressedEvent() } } } + if (auto popup = this->usernameInputPopup_.get()) + { + if (popup->isVisible()) + { + if (popup->eventFilter(nullptr, event)) + { + event->accept(); + return; + } + } + } if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { @@ -451,17 +464,55 @@ void SplitInput::installKeyPressedEvent() void SplitInput::onTextChanged() { - this->updateColonMenu(); + this->updateCompletionMenus(); } void SplitInput::onCursorPositionChanged() { - this->updateColonMenu(); + this->updateCompletionMenus(); } -void SplitInput::updateColonMenu() +void SplitInput::showColonMenu(const QString &text) +{ + if (!this->emoteInputPopup_.get()) + { + this->emoteInputPopup_ = new EmoteInputPopup(this); + this->emoteInputPopup_->setInputAction( + [that = QObjectRef(this)](const QString &text) mutable { + if (auto this2 = that.get()) + { + this2->insertCompletionText(text); + this2->hideColonMenu(); + } + }); + } + + auto popup = this->emoteInputPopup_.get(); + assert(popup); + + popup->updateEmotes(text, this->split_->getChannel()); + + auto pos = this->mapToGlobal({0, 0}) - QPoint(0, popup->height()) + + QPoint((this->width() - popup->width()) / 2, 0); + + popup->move(pos); + popup->show(); +} + +void SplitInput::hideColonMenu() +{ + if (auto popup = this->emoteInputPopup_.get()) + popup->hide(); +} + +void SplitInput::updateCompletionMenus() { auto channel = this->split_->getChannel().get(); + if (!dynamic_cast(channel)) + { + this->hideUsernameMenu(); + return; + } if (!getSettings()->emoteCompletionWithColon || (!dynamic_cast(channel) && !(channel->getType() == Channel::Type::TwitchWhispers))) @@ -470,7 +521,7 @@ void SplitInput::updateColonMenu() return; } - // check if in : + // check if in competion prefix auto &edit = *this->ui_.textEdit; auto text = edit.toPlainText(); @@ -479,6 +530,7 @@ void SplitInput::updateColonMenu() if (text.length() == 0) { this->hideColonMenu(); + this->hideUsernameMenu(); return; } @@ -487,6 +539,7 @@ void SplitInput::updateColonMenu() if (text[i] == ' ') { this->hideColonMenu(); + this->hideUsernameMenu(); return; } else if (text[i] == ':') @@ -497,30 +550,39 @@ void SplitInput::updateColonMenu() this->hideColonMenu(); return; } + else if (text[i] == '@') + { + if (i == 0 || text[i - 1].isSpace()) + this->showUsernameMenu(text.mid(i, position - i + 1).mid(1)); + else + this->hideUsernameMenu(); + return; + } } this->hideColonMenu(); + this->hideUsernameMenu(); } -void SplitInput::showColonMenu(const QString &text) +void SplitInput::showUsernameMenu(const QString &text) { - if (!this->emoteInputPopup_.get()) + if (!this->usernameInputPopup_.get()) { - this->emoteInputPopup_ = new EmoteInputPopup(this); - this->emoteInputPopup_->setInputAction( + this->usernameInputPopup_ = new UsernameInputPopup(this); + this->usernameInputPopup_->setInputAction( [that = QObjectRef(this)](const QString &text) mutable { if (auto this2 = that.get()) { - this2->insertColonText(text); - this2->hideColonMenu(); + this2->insertCompletionText(text); + this2->hideUsernameMenu(); } }); } - auto popup = this->emoteInputPopup_.get(); + auto popup = this->usernameInputPopup_.get(); assert(popup); - popup->updateEmotes(text, this->split_->getChannel()); + popup->updateUsers(text, this->split_->getChannel()); auto pos = this->mapToGlobal({0, 0}) - QPoint(0, popup->height()) + QPoint((this->width() - popup->width()) / 2, 0); @@ -529,13 +591,13 @@ void SplitInput::showColonMenu(const QString &text) popup->show(); } -void SplitInput::hideColonMenu() +void SplitInput::hideUsernameMenu() { - if (auto popup = this->emoteInputPopup_.get()) + if (auto popup = this->usernameInputPopup_.get()) popup->hide(); } -void SplitInput::insertColonText(const QString &input_) +void SplitInput::insertCompletionText(const QString &input_) { auto &edit = *this->ui_.textEdit; auto input = input_ + ' '; @@ -545,10 +607,21 @@ void SplitInput::insertColonText(const QString &input_) for (int i = clamp(position, 0, text.length() - 1); i >= 0; i--) { + bool done = false; if (text[i] == ':') { - auto cursor = edit.textCursor(); + done = true; + } + else if (text[i] == '@') + { + input = "@" + input_ + + (getSettings()->mentionUsersWithComma ? ", " : " "); + done = true; + } + if (done) + { + auto cursor = edit.textCursor(); edit.setText(text.remove(i, position - i).insert(i, input)); cursor.setPosition(i + input.size()); diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index 7e97aa6e3f9..a3ade361e66 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -17,6 +17,7 @@ namespace chatterino { class Split; class EmotePopup; class EmoteInputPopup; +class UsernameInputPopup; class EffectLabel; class ResizingTextEdit; @@ -48,15 +49,18 @@ class SplitInput : public BaseWidget void onCursorPositionChanged(); void onTextChanged(); void updateEmoteButton(); - void updateColonMenu(); void showColonMenu(const QString &text); void hideColonMenu(); - void insertColonText(const QString &text); + void updateCompletionMenus(); + void showUsernameMenu(const QString &text); + void hideUsernameMenu(); + void insertCompletionText(const QString &text); void openEmotePopup(); Split *const split_; QObjectRef emotePopup_; QObjectRef emoteInputPopup_; + QObjectRef usernameInputPopup_; struct { ResizingTextEdit *textEdit; diff --git a/src/widgets/splits/UsernameInputItem.cpp b/src/widgets/splits/UsernameInputItem.cpp new file mode 100644 index 00000000000..4e91ec85be4 --- /dev/null +++ b/src/widgets/splits/UsernameInputItem.cpp @@ -0,0 +1,30 @@ +#include "UsernameInputItem.hpp" + +namespace chatterino { + +UsernameInputItem::UsernameInputItem(const QString &text, ActionCallback action) + : text_(text) + , action_(action) +{ +} + +void UsernameInputItem::action() +{ + if (this->action_) + this->action_(this->text_); +} + +void UsernameInputItem::paint(QPainter *painter, const QRect &rect) const +{ + auto margin = 4; + QRect textRect = QRect(rect.topLeft() + QPoint{margin, margin}, + QSize(rect.width(), rect.height())); + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, this->text_); +} + +QSize UsernameInputItem::sizeHint(const QRect &rect) const +{ + return QSize(rect.width(), ICON_SIZE.height()); +} + +} // namespace chatterino diff --git a/src/widgets/splits/UsernameInputItem.hpp b/src/widgets/splits/UsernameInputItem.hpp new file mode 100644 index 00000000000..9c4c408468a --- /dev/null +++ b/src/widgets/splits/UsernameInputItem.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include "widgets/listview/GenericListItem.hpp" + +namespace chatterino { + +class UsernameInputItem : public GenericListItem +{ + using ActionCallback = std::function; + +public: + UsernameInputItem(const QString &text, ActionCallback action); + + // GenericListItem interface +public: + virtual void action() override; + virtual void paint(QPainter *painter, const QRect &rect) const override; + virtual QSize sizeHint(const QRect &rect) const override; + +private: + QString text_; + ActionCallback action_; +}; + +} // namespace chatterino diff --git a/src/widgets/splits/UsernameInputPopup.cpp b/src/widgets/splits/UsernameInputPopup.cpp new file mode 100644 index 00000000000..dbc7cdaf960 --- /dev/null +++ b/src/widgets/splits/UsernameInputPopup.cpp @@ -0,0 +1,84 @@ +#include "UsernameInputPopup.hpp" + +#include "Application.hpp" +#include "providers/twitch/TwitchChannel.hpp" +#include "util/LayoutCreator.hpp" +#include "widgets/listview/GenericListView.hpp" +#include "widgets/splits/UsernameInputItem.hpp" + +namespace chatterino { + +UsernameInputPopup::UsernameInputPopup(QWidget *parent) + : BasePopup({BasePopup::EnableCustomFrame, BasePopup::Frameless, + BasePopup::DontFocus}, + parent) + , model_(this) +{ + this->initLayout(); + + QObject::connect(&this->redrawTimer_, &QTimer::timeout, this, [this] { + if (this->isVisible()) + this->ui_.listView->doItemsLayout(); + }); + this->redrawTimer_.setInterval(33); +} + +void UsernameInputPopup::initLayout() +{ + LayoutCreator creator = {this}; + + auto listView = + creator.emplace().assign(&this->ui_.listView); + listView->setInvokeActionOnTab(true); + + listView->setModel(&this->model_); + QObject::connect(listView.getElement(), &GenericListView::closeRequested, + this, [this] { + this->close(); + }); +} + +void UsernameInputPopup::updateUsers(const QString &text, ChannelPtr channel) +{ + std::vector usernames; + auto twitchChannel = dynamic_cast(channel.get()); + if (twitchChannel) + { + auto chatters = twitchChannel->accessChatters()->filterByPrefix(text); + this->model_.clear(); + int count = 0; + for (const auto &name : chatters) + { + this->model_.addItem( + std::make_unique(name, this->callback_)); + + if (count++ == maxUsernameCount) + break; + } + if (!chatters.empty()) + { + this->ui_.listView->setCurrentIndex(this->model_.index(0)); + } + } +} +bool UsernameInputPopup::eventFilter(QObject *watched, QEvent *event) +{ + return this->ui_.listView->eventFilter(watched, event); +} + +void UsernameInputPopup::setInputAction(ActionCallback callback) +{ + this->callback_ = std::move(callback); +} + +void UsernameInputPopup::showEvent(QShowEvent *) +{ + this->redrawTimer_.start(); +} + +void UsernameInputPopup::hideEvent(QHideEvent *) +{ + this->redrawTimer_.stop(); +} + +} // namespace chatterino diff --git a/src/widgets/splits/UsernameInputPopup.hpp b/src/widgets/splits/UsernameInputPopup.hpp new file mode 100644 index 00000000000..fc244be4a53 --- /dev/null +++ b/src/widgets/splits/UsernameInputPopup.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include "common/Channel.hpp" +#include "widgets/BasePopup.hpp" +#include "widgets/listview/GenericListModel.hpp" + +namespace chatterino { + +class GenericListView; + +class UsernameInputPopup : public BasePopup +{ + using ActionCallback = std::function; + + constexpr static int maxUsernameCount = 200; + +public: + UsernameInputPopup(QWidget *parent = nullptr); + + void updateUsers(const QString &text, ChannelPtr channel); + virtual bool eventFilter(QObject *, QEvent *event) override; + + void setInputAction(ActionCallback callback); + +protected: + void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent *event) override; + +private: + void initLayout(); + + struct { + GenericListView *listView; + } ui_; + + GenericListModel model_; + ActionCallback callback_; + QTimer redrawTimer_; +}; + +} // namespace chatterino From 153b67431a8e1da11aa4bf9edda0367fa2077c5c Mon Sep 17 00:00:00 2001 From: Tal Neoran Date: Sun, 6 Jun 2021 14:51:02 +0300 Subject: [PATCH 2/8] Add setting to disable the popup --- src/singletons/Settings.hpp | 2 ++ src/widgets/settingspages/GeneralPage.cpp | 2 ++ src/widgets/splits/SplitInput.cpp | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index e53599d380a..5980454979b 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -161,6 +161,8 @@ class Settings : public ABSettings, public ConcurrentSettings "/behaviour/autocompletion/userCompletionOnlyWithAt", false}; BoolSetting emoteCompletionWithColon = { "/behaviour/autocompletion/emoteCompletionWithColon", true}; + BoolSetting showUsernameCompletionMenu = { + "/behaviour/autocompletion/showUsernameCompletionMenu", true}; FloatSetting pauseOnHoverDuration = {"/behaviour/pauseOnHoverDuration", 0}; EnumSetting pauseChatModifier = { diff --git a/src/widgets/settingspages/GeneralPage.cpp b/src/widgets/settingspages/GeneralPage.cpp index 573dfaa74c0..400066d9c30 100644 --- a/src/widgets/settingspages/GeneralPage.cpp +++ b/src/widgets/settingspages/GeneralPage.cpp @@ -610,6 +610,8 @@ void GeneralPage::initLayout(GeneralPageView &layout) layout.addCheckbox("Color @usernames", s.colorUsernames); layout.addCheckbox("Try to find usernames without @ prefix", s.findAllUsernames); + layout.addCheckbox("Show username autocompletion popup menu", + s.showUsernameCompletionMenu); layout.addDropdown( "Username font weight", {"50", "Default", "75", "100"}, s.boldScale, [](auto val) { diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index 8218b0c93da..95d069318b0 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -508,7 +508,8 @@ void SplitInput::hideColonMenu() void SplitInput::updateCompletionMenus() { auto channel = this->split_->getChannel().get(); - if (!dynamic_cast(channel)) + if (!getSettings()->showUsernameCompletionMenu || + !dynamic_cast(channel)) { this->hideUsernameMenu(); return; From 68f983c9e3bb3a8b017b69452325f17d157bb905 Mon Sep 17 00:00:00 2001 From: Tal Neoran Date: Sun, 6 Jun 2021 15:52:24 +0300 Subject: [PATCH 3/8] Fix username menu affecting emote colon menu --- src/widgets/splits/SplitInput.cpp | 71 +++++++++++++++++++++---------- src/widgets/splits/SplitInput.hpp | 3 +- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index 95d069318b0..348f0b83885 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -464,12 +464,57 @@ void SplitInput::installKeyPressedEvent() void SplitInput::onTextChanged() { - this->updateCompletionMenus(); + this->updateColonMenu(); + this->updateUsernameMenu(); } void SplitInput::onCursorPositionChanged() { - this->updateCompletionMenus(); + this->updateColonMenu(); + this->updateUsernameMenu(); +} + +void SplitInput::updateColonMenu() +{ + auto channel = this->split_->getChannel().get(); + if (!getSettings()->emoteCompletionWithColon || + (!dynamic_cast(channel) && + !(channel->getType() == Channel::Type::TwitchWhispers))) + { + this->hideColonMenu(); + return; + } + + // check if in : + auto &edit = *this->ui_.textEdit; + + auto text = edit.toPlainText(); + auto position = edit.textCursor().position() - 1; + + if (text.length() == 0) + { + this->hideColonMenu(); + return; + } + + for (int i = clamp(position, 0, text.length() - 1); i >= 0; i--) + { + if (text[i] == ' ') + { + this->hideColonMenu(); + return; + } + else if (text[i] == ':') + { + if (i == 0 || text[i - 1].isSpace()) + this->showColonMenu(text.mid(i, position - i + 1).mid(1)); + else + this->hideColonMenu(); + return; + } + } + + this->hideColonMenu(); } void SplitInput::showColonMenu(const QString &text) @@ -505,7 +550,7 @@ void SplitInput::hideColonMenu() popup->hide(); } -void SplitInput::updateCompletionMenus() +void SplitInput::updateUsernameMenu() { auto channel = this->split_->getChannel().get(); if (!getSettings()->showUsernameCompletionMenu || @@ -514,15 +559,8 @@ void SplitInput::updateCompletionMenus() this->hideUsernameMenu(); return; } - if (!getSettings()->emoteCompletionWithColon || - (!dynamic_cast(channel) && - !(channel->getType() == Channel::Type::TwitchWhispers))) - { - this->hideColonMenu(); - return; - } - // check if in competion prefix + // check if in @ completion prefix auto &edit = *this->ui_.textEdit; auto text = edit.toPlainText(); @@ -530,7 +568,6 @@ void SplitInput::updateCompletionMenus() if (text.length() == 0) { - this->hideColonMenu(); this->hideUsernameMenu(); return; } @@ -539,18 +576,9 @@ void SplitInput::updateCompletionMenus() { if (text[i] == ' ') { - this->hideColonMenu(); this->hideUsernameMenu(); return; } - else if (text[i] == ':') - { - if (i == 0 || text[i - 1].isSpace()) - this->showColonMenu(text.mid(i, position - i + 1).mid(1)); - else - this->hideColonMenu(); - return; - } else if (text[i] == '@') { if (i == 0 || text[i - 1].isSpace()) @@ -561,7 +589,6 @@ void SplitInput::updateCompletionMenus() } } - this->hideColonMenu(); this->hideUsernameMenu(); } diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index a3ade361e66..03abcb8aeba 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -49,9 +49,10 @@ class SplitInput : public BaseWidget void onCursorPositionChanged(); void onTextChanged(); void updateEmoteButton(); + void updateColonMenu(); void showColonMenu(const QString &text); void hideColonMenu(); - void updateCompletionMenus(); + void updateUsernameMenu(); void showUsernameMenu(const QString &text); void hideUsernameMenu(); void insertCompletionText(const QString &text); From 90cbe35b3a31bdc357326298ac0355afd4aec39b Mon Sep 17 00:00:00 2001 From: Tal Neoran Date: Sun, 6 Jun 2021 16:10:03 +0300 Subject: [PATCH 4/8] Remove unused variable --- src/widgets/splits/UsernameInputPopup.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/widgets/splits/UsernameInputPopup.cpp b/src/widgets/splits/UsernameInputPopup.cpp index dbc7cdaf960..b7bdd1c8caf 100644 --- a/src/widgets/splits/UsernameInputPopup.cpp +++ b/src/widgets/splits/UsernameInputPopup.cpp @@ -40,7 +40,6 @@ void UsernameInputPopup::initLayout() void UsernameInputPopup::updateUsers(const QString &text, ChannelPtr channel) { - std::vector usernames; auto twitchChannel = dynamic_cast(channel.get()); if (twitchChannel) { From c195751cae4e671c0198ea8124a8c21a6bab69e2 Mon Sep 17 00:00:00 2001 From: Tal Neoran Date: Sun, 6 Jun 2021 16:26:21 +0300 Subject: [PATCH 5/8] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74cba16da1a..451af539510 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unversioned +- Major: Added username autocompletion popup menu when typing usernames with an @ prefix. (#1979, #2866) - Major: Added ability to toggle visibility of Channel Tabs - This can be done by right-clicking the tab area or pressing the keyboard shortcut (default: Ctrl+U). (#2600) - Minor: Searching for users in the viewer list now searches anywhere in the user's name. (#2861) - Minor: Added moderation buttons to search popup when searching in a split with moderation mode enabled. (#2148, #2803) From db56976f08f12cf6105c79370d1bcf97143e75f7 Mon Sep 17 00:00:00 2001 From: Tal Neoran Date: Mon, 7 Jun 2021 21:14:23 +0300 Subject: [PATCH 6/8] Combined handling of emote and username completion popups --- chatterino.pro | 12 +- src/CMakeLists.txt | 12 +- src/widgets/splits/EmoteInputItem.cpp | 63 -------- src/widgets/splits/InputCompletionItem.cpp | 76 +++++++++ ...eInputItem.hpp => InputCompletionItem.hpp} | 6 +- ...nputPopup.cpp => InputCompletionPopup.cpp} | 45 ++++-- ...nputPopup.hpp => InputCompletionPopup.hpp} | 7 +- src/widgets/splits/SplitInput.cpp | 149 +++++------------- src/widgets/splits/SplitInput.hpp | 15 +- src/widgets/splits/UsernameInputItem.cpp | 30 ---- src/widgets/splits/UsernameInputItem.hpp | 26 --- src/widgets/splits/UsernameInputPopup.cpp | 83 ---------- src/widgets/splits/UsernameInputPopup.hpp | 42 ----- 13 files changed, 168 insertions(+), 398 deletions(-) delete mode 100644 src/widgets/splits/EmoteInputItem.cpp create mode 100644 src/widgets/splits/InputCompletionItem.cpp rename src/widgets/splits/{EmoteInputItem.hpp => InputCompletionItem.hpp} (76%) rename src/widgets/splits/{EmoteInputPopup.cpp => InputCompletionPopup.cpp} (76%) rename src/widgets/splits/{EmoteInputPopup.hpp => InputCompletionPopup.hpp} (78%) delete mode 100644 src/widgets/splits/UsernameInputItem.cpp delete mode 100644 src/widgets/splits/UsernameInputItem.hpp delete mode 100644 src/widgets/splits/UsernameInputPopup.cpp delete mode 100644 src/widgets/splits/UsernameInputPopup.hpp diff --git a/chatterino.pro b/chatterino.pro index 205b410ac5b..7cdba86a0e9 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -318,15 +318,13 @@ SOURCES += \ src/widgets/settingspages/NotificationPage.cpp \ src/widgets/settingspages/SettingsPage.cpp \ src/widgets/splits/ClosedSplits.cpp \ - src/widgets/splits/EmoteInputItem.cpp \ - src/widgets/splits/EmoteInputPopup.cpp \ + src/widgets/splits/InputCompletionItem.cpp \ + src/widgets/splits/InputCompletionPopup.cpp \ src/widgets/splits/Split.cpp \ src/widgets/splits/SplitContainer.cpp \ src/widgets/splits/SplitHeader.cpp \ src/widgets/splits/SplitInput.cpp \ src/widgets/splits/SplitOverlay.cpp \ - src/widgets/splits/UsernameInputItem.cpp \ - src/widgets/splits/UsernameInputPopup.cpp \ src/widgets/StreamView.cpp \ src/widgets/TooltipWidget.cpp \ src/widgets/Window.cpp \ @@ -581,15 +579,13 @@ HEADERS += \ src/widgets/settingspages/NotificationPage.hpp \ src/widgets/settingspages/SettingsPage.hpp \ src/widgets/splits/ClosedSplits.hpp \ - src/widgets/splits/EmoteInputItem.hpp \ - src/widgets/splits/EmoteInputPopup.hpp \ + src/widgets/splits/InputCompletionItem.hpp \ + src/widgets/splits/InputCompletionPopup.hpp \ src/widgets/splits/Split.hpp \ src/widgets/splits/SplitContainer.hpp \ src/widgets/splits/SplitHeader.hpp \ src/widgets/splits/SplitInput.hpp \ src/widgets/splits/SplitOverlay.hpp \ - src/widgets/splits/UsernameInputItem.hpp \ - src/widgets/splits/UsernameInputPopup.hpp \ src/widgets/StreamView.hpp \ src/widgets/TooltipWidget.hpp \ src/widgets/Window.hpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd122b8dff0..1a4e4137467 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -434,10 +434,10 @@ set(SOURCE_FILES main.cpp widgets/splits/ClosedSplits.cpp widgets/splits/ClosedSplits.hpp - widgets/splits/EmoteInputItem.cpp - widgets/splits/EmoteInputItem.hpp - widgets/splits/EmoteInputPopup.cpp - widgets/splits/EmoteInputPopup.hpp + widgets/splits/InputCompletionItem.cpp + widgets/splits/InputCompletionItem.hpp + widgets/splits/InputCompletionPopup.cpp + widgets/splits/InputCompletionPopup.hpp widgets/splits/Split.cpp widgets/splits/Split.hpp widgets/splits/SplitContainer.cpp @@ -448,10 +448,6 @@ set(SOURCE_FILES main.cpp widgets/splits/SplitInput.hpp widgets/splits/SplitOverlay.cpp widgets/splits/SplitOverlay.hpp - widgets/splits/UsernameInputItem.cpp - widgets/splits/UsernameInputItem.hpp - widgets/splits/UsernameInputPopup.cpp - widgets/splits/UsernameInputPopup.hpp autogenerated/ResourcesAutogen.cpp autogenerated/ResourcesAutogen.hpp diff --git a/src/widgets/splits/EmoteInputItem.cpp b/src/widgets/splits/EmoteInputItem.cpp deleted file mode 100644 index 5612b16cd55..00000000000 --- a/src/widgets/splits/EmoteInputItem.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "EmoteInputItem.hpp" - -namespace chatterino { - -EmoteInputItem::EmoteInputItem(const EmotePtr &emote, const QString &text, - ActionCallback action) - : emote_(emote) - , text_(text) - , action_(action) -{ -} - -void EmoteInputItem::action() -{ - if (this->action_ && this->emote_) - this->action_(this->emote_->name.string); -} - -void EmoteInputItem::paint(QPainter *painter, const QRect &rect) const -{ - painter->setRenderHint(QPainter::SmoothPixmapTransform); - painter->setRenderHint(QPainter::Antialiasing); - - auto margin = 4; - auto imageHeight = ICON_SIZE.height() - margin * 2; - - QRect iconRect{ - rect.topLeft() + QPoint{margin, margin}, - QSize{imageHeight, imageHeight}, - }; - - if (this->emote_) - { - if (auto image = this->emote_->images.getImage(2)) - { - if (auto pixmap = image->pixmapOrLoad()) - { - if (image->height() != 0) - { - auto aspectRatio = - double(image->width()) / double(image->height()); - - iconRect = { - rect.topLeft() + QPoint{margin, margin}, - QSize(int(imageHeight * aspectRatio), imageHeight)}; - painter->drawPixmap(iconRect, *pixmap); - } - } - } - } - - QRect textRect = - QRect(iconRect.topRight() + QPoint{margin, 0}, - QSize(rect.width() - iconRect.width(), iconRect.height())); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, this->text_); -} - -QSize EmoteInputItem::sizeHint(const QRect &rect) const -{ - return QSize(rect.width(), ICON_SIZE.height()); -} - -} // namespace chatterino diff --git a/src/widgets/splits/InputCompletionItem.cpp b/src/widgets/splits/InputCompletionItem.cpp new file mode 100644 index 00000000000..779b751c976 --- /dev/null +++ b/src/widgets/splits/InputCompletionItem.cpp @@ -0,0 +1,76 @@ +#include "InputCompletionItem.hpp" + +namespace chatterino { + +InputCompletionItem::InputCompletionItem(const EmotePtr &emote, + const QString &text, + ActionCallback action) + : emote_(emote) + , text_(text) + , action_(action) +{ +} + +void InputCompletionItem::action() +{ + if (this->action_) + { + if (this->emote_) + this->action_(this->emote_->name.string); + else + this->action_(this->text_); + } +} + +void InputCompletionItem::paint(QPainter *painter, const QRect &rect) const +{ + auto margin = 4; + QRect textRect; + if (this->emote_) + { + painter->setRenderHint(QPainter::SmoothPixmapTransform); + painter->setRenderHint(QPainter::Antialiasing); + + auto imageHeight = ICON_SIZE.height() - margin * 2; + + QRect iconRect{ + rect.topLeft() + QPoint{margin, margin}, + QSize{imageHeight, imageHeight}, + }; + + if (auto image = this->emote_->images.getImage(2)) + { + if (auto pixmap = image->pixmapOrLoad()) + { + if (image->height() != 0) + { + auto aspectRatio = + double(image->width()) / double(image->height()); + + iconRect = { + rect.topLeft() + QPoint{margin, margin}, + QSize(int(imageHeight * aspectRatio), imageHeight)}; + painter->drawPixmap(iconRect, *pixmap); + } + } + } + + textRect = + QRect(iconRect.topRight() + QPoint{margin, 0}, + QSize(rect.width() - iconRect.width(), iconRect.height())); + } + else + { + textRect = QRect(rect.topLeft() + QPoint{margin, margin}, + QSize(rect.width(), rect.height())); + } + + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, this->text_); +} + +QSize InputCompletionItem::sizeHint(const QRect &rect) const +{ + return QSize(rect.width(), ICON_SIZE.height()); +} + +} // namespace chatterino diff --git a/src/widgets/splits/EmoteInputItem.hpp b/src/widgets/splits/InputCompletionItem.hpp similarity index 76% rename from src/widgets/splits/EmoteInputItem.hpp rename to src/widgets/splits/InputCompletionItem.hpp index d0798c2eab3..9ea1260a105 100644 --- a/src/widgets/splits/EmoteInputItem.hpp +++ b/src/widgets/splits/InputCompletionItem.hpp @@ -6,13 +6,13 @@ namespace chatterino { -class EmoteInputItem : public GenericListItem +class InputCompletionItem : public GenericListItem { using ActionCallback = std::function; public: - EmoteInputItem(const EmotePtr &emote, const QString &text, - ActionCallback action); + InputCompletionItem(const EmotePtr &emote, const QString &text, + ActionCallback action); // GenericListItem interface public: diff --git a/src/widgets/splits/EmoteInputPopup.cpp b/src/widgets/splits/InputCompletionPopup.cpp similarity index 76% rename from src/widgets/splits/EmoteInputPopup.cpp rename to src/widgets/splits/InputCompletionPopup.cpp index 2291afe6a28..689aa1c8a58 100644 --- a/src/widgets/splits/EmoteInputPopup.cpp +++ b/src/widgets/splits/InputCompletionPopup.cpp @@ -1,4 +1,4 @@ -#include "EmoteInputPopup.hpp" +#include "InputCompletionPopup.hpp" #include "Application.hpp" #include "controllers/accounts/AccountController.hpp" @@ -10,7 +10,7 @@ #include "singletons/Emotes.hpp" #include "util/LayoutCreator.hpp" #include "widgets/listview/GenericListView.hpp" -#include "widgets/splits/EmoteInputItem.hpp" +#include "widgets/splits/InputCompletionItem.hpp" namespace chatterino { namespace { @@ -41,7 +41,7 @@ namespace { } } // namespace -EmoteInputPopup::EmoteInputPopup(QWidget *parent) +InputCompletionPopup::InputCompletionPopup(QWidget *parent) : BasePopup({BasePopup::EnableCustomFrame, BasePopup::Frameless, BasePopup::DontFocus}, parent) @@ -56,7 +56,7 @@ EmoteInputPopup::EmoteInputPopup(QWidget *parent) this->redrawTimer_.setInterval(33); } -void EmoteInputPopup::initLayout() +void InputCompletionPopup::initLayout() { LayoutCreator creator = {this}; @@ -71,7 +71,7 @@ void EmoteInputPopup::initLayout() }); } -void EmoteInputPopup::updateEmotes(const QString &text, ChannelPtr channel) +void InputCompletionPopup::updateEmotes(const QString &text, ChannelPtr channel) { std::vector<_Emote> emotes; auto tc = dynamic_cast(channel.get()); @@ -122,11 +122,11 @@ void EmoteInputPopup::updateEmotes(const QString &text, ChannelPtr channel) int count = 0; for (auto &&emote : emotes) { - this->model_.addItem(std::make_unique( + this->model_.addItem(std::make_unique( emote.emote, emote.displayName + " - " + emote.providerName, this->callback_)); - if (count++ == maxEmoteCount) + if (count++ == maxEntryCount) break; } @@ -136,22 +136,45 @@ void EmoteInputPopup::updateEmotes(const QString &text, ChannelPtr channel) } } -bool EmoteInputPopup::eventFilter(QObject *watched, QEvent *event) +void InputCompletionPopup::updateUsers(const QString &text, ChannelPtr channel) +{ + auto twitchChannel = dynamic_cast(channel.get()); + if (twitchChannel) + { + auto chatters = twitchChannel->accessChatters()->filterByPrefix(text); + this->model_.clear(); + int count = 0; + for (const auto &name : chatters) + { + this->model_.addItem(std::make_unique( + nullptr, name, this->callback_)); + + if (count++ == maxEntryCount) + break; + } + if (!chatters.empty()) + { + this->ui_.listView->setCurrentIndex(this->model_.index(0)); + } + } +} + +bool InputCompletionPopup::eventFilter(QObject *watched, QEvent *event) { return this->ui_.listView->eventFilter(watched, event); } -void EmoteInputPopup::setInputAction(ActionCallback callback) +void InputCompletionPopup::setInputAction(ActionCallback callback) { this->callback_ = std::move(callback); } -void EmoteInputPopup::showEvent(QShowEvent *) +void InputCompletionPopup::showEvent(QShowEvent *) { this->redrawTimer_.start(); } -void EmoteInputPopup::hideEvent(QHideEvent *) +void InputCompletionPopup::hideEvent(QHideEvent *) { this->redrawTimer_.stop(); } diff --git a/src/widgets/splits/EmoteInputPopup.hpp b/src/widgets/splits/InputCompletionPopup.hpp similarity index 78% rename from src/widgets/splits/EmoteInputPopup.hpp rename to src/widgets/splits/InputCompletionPopup.hpp index 1d8c7e73564..6329a8a64bb 100644 --- a/src/widgets/splits/EmoteInputPopup.hpp +++ b/src/widgets/splits/InputCompletionPopup.hpp @@ -9,16 +9,17 @@ namespace chatterino { class GenericListView; -class EmoteInputPopup : public BasePopup +class InputCompletionPopup : public BasePopup { using ActionCallback = std::function; - constexpr static int maxEmoteCount = 200; + constexpr static int maxEntryCount = 200; public: - EmoteInputPopup(QWidget *parent = nullptr); + InputCompletionPopup(QWidget *parent = nullptr); void updateEmotes(const QString &text, ChannelPtr channel); + void updateUsers(const QString &text, ChannelPtr channel); virtual bool eventFilter(QObject *, QEvent *event) override; void setInputAction(ActionCallback callback); diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index 348f0b83885..91be55d62b7 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -15,11 +15,10 @@ #include "widgets/helper/ChannelView.hpp" #include "widgets/helper/EffectLabel.hpp" #include "widgets/helper/ResizingTextEdit.hpp" -#include "widgets/splits/EmoteInputPopup.hpp" +#include "widgets/splits/InputCompletionPopup.hpp" #include "widgets/splits/Split.hpp" #include "widgets/splits/SplitContainer.hpp" #include "widgets/splits/SplitInput.hpp" -#include "widgets/splits/UsernameInputPopup.hpp" #include #include @@ -46,8 +45,7 @@ SplitInput::SplitInput(Split *_chatWidget) // misc this->installKeyPressedEvent(); this->ui_.textEdit->focusLost.connect([this] { - this->hideColonMenu(); - this->hideUsernameMenu(); + this->hideCompletionPopup(); }); this->scaleChangedEvent(this->scale()); } @@ -204,18 +202,7 @@ void SplitInput::installKeyPressedEvent() auto app = getApp(); this->ui_.textEdit->keyPressed.connect([this, app](QKeyEvent *event) { - if (auto popup = this->emoteInputPopup_.get()) - { - if (popup->isVisible()) - { - if (popup->eventFilter(nullptr, event)) - { - event->accept(); - return; - } - } - } - if (auto popup = this->usernameInputPopup_.get()) + if (auto popup = this->inputCompletionPopup_.get()) { if (popup->isVisible()) { @@ -464,28 +451,30 @@ void SplitInput::installKeyPressedEvent() void SplitInput::onTextChanged() { - this->updateColonMenu(); - this->updateUsernameMenu(); + this->updateCompletionPopup(); } void SplitInput::onCursorPositionChanged() { - this->updateColonMenu(); - this->updateUsernameMenu(); + this->updateCompletionPopup(); } -void SplitInput::updateColonMenu() +void SplitInput::updateCompletionPopup() { auto channel = this->split_->getChannel().get(); - if (!getSettings()->emoteCompletionWithColon || - (!dynamic_cast(channel) && - !(channel->getType() == Channel::Type::TwitchWhispers))) + auto tc = dynamic_cast(channel); + bool showEmoteCompletion = + getSettings()->emoteCompletionWithColon && + (tc || (channel->getType() == Channel::Type::TwitchWhispers)); + bool showUsernameCompletion = + tc && getSettings()->showUsernameCompletionMenu; + if (!showEmoteCompletion && !showUsernameCompletion) { - this->hideColonMenu(); + this->hideCompletionPopup(); return; } - // check if in : + // check if in completion prefix auto &edit = *this->ui_.textEdit; auto text = edit.toPlainText(); @@ -493,7 +482,7 @@ void SplitInput::updateColonMenu() if (text.length() == 0) { - this->hideColonMenu(); + this->hideCompletionPopup(); return; } @@ -501,116 +490,54 @@ void SplitInput::updateColonMenu() { if (text[i] == ' ') { - this->hideColonMenu(); + this->hideCompletionPopup(); return; } - else if (text[i] == ':') + else if (text[i] == ':' && showEmoteCompletion) { if (i == 0 || text[i - 1].isSpace()) - this->showColonMenu(text.mid(i, position - i + 1).mid(1)); + this->showCompletionPopup(text.mid(i, position - i + 1).mid(1), + true); else - this->hideColonMenu(); + this->hideCompletionPopup(); return; } - } - - this->hideColonMenu(); -} - -void SplitInput::showColonMenu(const QString &text) -{ - if (!this->emoteInputPopup_.get()) - { - this->emoteInputPopup_ = new EmoteInputPopup(this); - this->emoteInputPopup_->setInputAction( - [that = QObjectRef(this)](const QString &text) mutable { - if (auto this2 = that.get()) - { - this2->insertCompletionText(text); - this2->hideColonMenu(); - } - }); - } - - auto popup = this->emoteInputPopup_.get(); - assert(popup); - - popup->updateEmotes(text, this->split_->getChannel()); - - auto pos = this->mapToGlobal({0, 0}) - QPoint(0, popup->height()) + - QPoint((this->width() - popup->width()) / 2, 0); - - popup->move(pos); - popup->show(); -} - -void SplitInput::hideColonMenu() -{ - if (auto popup = this->emoteInputPopup_.get()) - popup->hide(); -} - -void SplitInput::updateUsernameMenu() -{ - auto channel = this->split_->getChannel().get(); - if (!getSettings()->showUsernameCompletionMenu || - !dynamic_cast(channel)) - { - this->hideUsernameMenu(); - return; - } - - // check if in @ completion prefix - auto &edit = *this->ui_.textEdit; - - auto text = edit.toPlainText(); - auto position = edit.textCursor().position() - 1; - - if (text.length() == 0) - { - this->hideUsernameMenu(); - return; - } - - for (int i = clamp(position, 0, text.length() - 1); i >= 0; i--) - { - if (text[i] == ' ') - { - this->hideUsernameMenu(); - return; - } - else if (text[i] == '@') + else if (text[i] == '@' && showUsernameCompletion) { if (i == 0 || text[i - 1].isSpace()) - this->showUsernameMenu(text.mid(i, position - i + 1).mid(1)); + this->showCompletionPopup(text.mid(i, position - i + 1).mid(1), + false); else - this->hideUsernameMenu(); + this->hideCompletionPopup(); return; } } - this->hideUsernameMenu(); + this->hideCompletionPopup(); } -void SplitInput::showUsernameMenu(const QString &text) +void SplitInput::showCompletionPopup(const QString &text, bool emoteCompletion) { - if (!this->usernameInputPopup_.get()) + if (!this->inputCompletionPopup_.get()) { - this->usernameInputPopup_ = new UsernameInputPopup(this); - this->usernameInputPopup_->setInputAction( + this->inputCompletionPopup_ = new InputCompletionPopup(this); + this->inputCompletionPopup_->setInputAction( [that = QObjectRef(this)](const QString &text) mutable { if (auto this2 = that.get()) { this2->insertCompletionText(text); - this2->hideUsernameMenu(); + this2->hideCompletionPopup(); } }); } - auto popup = this->usernameInputPopup_.get(); + auto popup = this->inputCompletionPopup_.get(); assert(popup); - popup->updateUsers(text, this->split_->getChannel()); + if (emoteCompletion) // autocomplete emotes + popup->updateEmotes(text, this->split_->getChannel()); + else // autocomplete usernames + popup->updateUsers(text, this->split_->getChannel()); auto pos = this->mapToGlobal({0, 0}) - QPoint(0, popup->height()) + QPoint((this->width() - popup->width()) / 2, 0); @@ -619,9 +546,9 @@ void SplitInput::showUsernameMenu(const QString &text) popup->show(); } -void SplitInput::hideUsernameMenu() +void SplitInput::hideCompletionPopup() { - if (auto popup = this->usernameInputPopup_.get()) + if (auto popup = this->inputCompletionPopup_.get()) popup->hide(); } diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index 03abcb8aeba..52e9b015db1 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -16,8 +16,7 @@ namespace chatterino { class Split; class EmotePopup; -class EmoteInputPopup; -class UsernameInputPopup; +class InputCompletionPopup; class EffectLabel; class ResizingTextEdit; @@ -49,19 +48,15 @@ class SplitInput : public BaseWidget void onCursorPositionChanged(); void onTextChanged(); void updateEmoteButton(); - void updateColonMenu(); - void showColonMenu(const QString &text); - void hideColonMenu(); - void updateUsernameMenu(); - void showUsernameMenu(const QString &text); - void hideUsernameMenu(); + void updateCompletionPopup(); + void showCompletionPopup(const QString &text, bool emoteCompletion); + void hideCompletionPopup(); void insertCompletionText(const QString &text); void openEmotePopup(); Split *const split_; QObjectRef emotePopup_; - QObjectRef emoteInputPopup_; - QObjectRef usernameInputPopup_; + QObjectRef inputCompletionPopup_; struct { ResizingTextEdit *textEdit; diff --git a/src/widgets/splits/UsernameInputItem.cpp b/src/widgets/splits/UsernameInputItem.cpp deleted file mode 100644 index 4e91ec85be4..00000000000 --- a/src/widgets/splits/UsernameInputItem.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "UsernameInputItem.hpp" - -namespace chatterino { - -UsernameInputItem::UsernameInputItem(const QString &text, ActionCallback action) - : text_(text) - , action_(action) -{ -} - -void UsernameInputItem::action() -{ - if (this->action_) - this->action_(this->text_); -} - -void UsernameInputItem::paint(QPainter *painter, const QRect &rect) const -{ - auto margin = 4; - QRect textRect = QRect(rect.topLeft() + QPoint{margin, margin}, - QSize(rect.width(), rect.height())); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, this->text_); -} - -QSize UsernameInputItem::sizeHint(const QRect &rect) const -{ - return QSize(rect.width(), ICON_SIZE.height()); -} - -} // namespace chatterino diff --git a/src/widgets/splits/UsernameInputItem.hpp b/src/widgets/splits/UsernameInputItem.hpp deleted file mode 100644 index 9c4c408468a..00000000000 --- a/src/widgets/splits/UsernameInputItem.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include "widgets/listview/GenericListItem.hpp" - -namespace chatterino { - -class UsernameInputItem : public GenericListItem -{ - using ActionCallback = std::function; - -public: - UsernameInputItem(const QString &text, ActionCallback action); - - // GenericListItem interface -public: - virtual void action() override; - virtual void paint(QPainter *painter, const QRect &rect) const override; - virtual QSize sizeHint(const QRect &rect) const override; - -private: - QString text_; - ActionCallback action_; -}; - -} // namespace chatterino diff --git a/src/widgets/splits/UsernameInputPopup.cpp b/src/widgets/splits/UsernameInputPopup.cpp deleted file mode 100644 index b7bdd1c8caf..00000000000 --- a/src/widgets/splits/UsernameInputPopup.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "UsernameInputPopup.hpp" - -#include "Application.hpp" -#include "providers/twitch/TwitchChannel.hpp" -#include "util/LayoutCreator.hpp" -#include "widgets/listview/GenericListView.hpp" -#include "widgets/splits/UsernameInputItem.hpp" - -namespace chatterino { - -UsernameInputPopup::UsernameInputPopup(QWidget *parent) - : BasePopup({BasePopup::EnableCustomFrame, BasePopup::Frameless, - BasePopup::DontFocus}, - parent) - , model_(this) -{ - this->initLayout(); - - QObject::connect(&this->redrawTimer_, &QTimer::timeout, this, [this] { - if (this->isVisible()) - this->ui_.listView->doItemsLayout(); - }); - this->redrawTimer_.setInterval(33); -} - -void UsernameInputPopup::initLayout() -{ - LayoutCreator creator = {this}; - - auto listView = - creator.emplace().assign(&this->ui_.listView); - listView->setInvokeActionOnTab(true); - - listView->setModel(&this->model_); - QObject::connect(listView.getElement(), &GenericListView::closeRequested, - this, [this] { - this->close(); - }); -} - -void UsernameInputPopup::updateUsers(const QString &text, ChannelPtr channel) -{ - auto twitchChannel = dynamic_cast(channel.get()); - if (twitchChannel) - { - auto chatters = twitchChannel->accessChatters()->filterByPrefix(text); - this->model_.clear(); - int count = 0; - for (const auto &name : chatters) - { - this->model_.addItem( - std::make_unique(name, this->callback_)); - - if (count++ == maxUsernameCount) - break; - } - if (!chatters.empty()) - { - this->ui_.listView->setCurrentIndex(this->model_.index(0)); - } - } -} -bool UsernameInputPopup::eventFilter(QObject *watched, QEvent *event) -{ - return this->ui_.listView->eventFilter(watched, event); -} - -void UsernameInputPopup::setInputAction(ActionCallback callback) -{ - this->callback_ = std::move(callback); -} - -void UsernameInputPopup::showEvent(QShowEvent *) -{ - this->redrawTimer_.start(); -} - -void UsernameInputPopup::hideEvent(QHideEvent *) -{ - this->redrawTimer_.stop(); -} - -} // namespace chatterino diff --git a/src/widgets/splits/UsernameInputPopup.hpp b/src/widgets/splits/UsernameInputPopup.hpp deleted file mode 100644 index fc244be4a53..00000000000 --- a/src/widgets/splits/UsernameInputPopup.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include "common/Channel.hpp" -#include "widgets/BasePopup.hpp" -#include "widgets/listview/GenericListModel.hpp" - -namespace chatterino { - -class GenericListView; - -class UsernameInputPopup : public BasePopup -{ - using ActionCallback = std::function; - - constexpr static int maxUsernameCount = 200; - -public: - UsernameInputPopup(QWidget *parent = nullptr); - - void updateUsers(const QString &text, ChannelPtr channel); - virtual bool eventFilter(QObject *, QEvent *event) override; - - void setInputAction(ActionCallback callback); - -protected: - void showEvent(QShowEvent *event) override; - void hideEvent(QHideEvent *event) override; - -private: - void initLayout(); - - struct { - GenericListView *listView; - } ui_; - - GenericListModel model_; - ActionCallback callback_; - QTimer redrawTimer_; -}; - -} // namespace chatterino From 55705de38563620cf45798220ff3eba05389902c Mon Sep 17 00:00:00 2001 From: Tal Neoran Date: Mon, 7 Jun 2021 21:23:26 +0300 Subject: [PATCH 7/8] Remove unrelated change that's no longer needed --- src/widgets/listview/GenericListModel.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/widgets/listview/GenericListModel.hpp b/src/widgets/listview/GenericListModel.hpp index 41d4a85c929..767ff6915d8 100644 --- a/src/widgets/listview/GenericListModel.hpp +++ b/src/widgets/listview/GenericListModel.hpp @@ -1,5 +1,3 @@ -#pragma once - #include "widgets/listview/GenericListItem.hpp" #include From 47cdc19364dcbf7d3d5fcf1302a17d0a9b9d948e Mon Sep 17 00:00:00 2001 From: Tal Neoran Date: Mon, 7 Jun 2021 21:31:55 +0300 Subject: [PATCH 8/8] Center username suggestions vertically --- src/widgets/splits/InputCompletionItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/splits/InputCompletionItem.cpp b/src/widgets/splits/InputCompletionItem.cpp index 779b751c976..99994b60584 100644 --- a/src/widgets/splits/InputCompletionItem.cpp +++ b/src/widgets/splits/InputCompletionItem.cpp @@ -61,7 +61,7 @@ void InputCompletionItem::paint(QPainter *painter, const QRect &rect) const } else { - textRect = QRect(rect.topLeft() + QPoint{margin, margin}, + textRect = QRect(rect.topLeft() + QPoint{margin, 0}, QSize(rect.width(), rect.height())); }