diff --git a/.clang-tidy b/.clang-tidy index c97a71aa7..302faf980 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -51,3 +51,5 @@ CheckOptions: value: UPPER_CASE - key: readability-identifier-naming.VariableCase value: camelBack + - key: readability-implicit-bool-conversion.AllowPointerConditions + value: true diff --git a/src/widgets/splits/InputCompletionPopup.cpp b/src/widgets/splits/InputCompletionPopup.cpp index c907bc58c..2f7aabd63 100644 --- a/src/widgets/splits/InputCompletionPopup.cpp +++ b/src/widgets/splits/InputCompletionPopup.cpp @@ -13,35 +13,47 @@ #include "widgets/listview/GenericListView.hpp" #include "widgets/splits/InputCompletionItem.hpp" -namespace chatterino { namespace { - struct _Emote { - EmotePtr emote; - QString displayName; - QString providerName; - }; +using namespace chatterino; - void addEmotes(std::vector<_Emote> &out, const EmoteMap &map, - const QString &text, const QString &providerName) - { - for (auto &&emote : map) - if (emote.first.string.contains(text, Qt::CaseInsensitive)) - out.push_back( - {emote.second, emote.second->name.string, providerName}); - } +struct CompletionEmote { + EmotePtr emote; + QString displayName; + QString providerName; +}; - void addEmojis(std::vector<_Emote> &out, const EmojiMap &map, - const QString &text) +void addEmotes(std::vector &out, const EmoteMap &map, + const QString &text, const QString &providerName) +{ + for (auto &&emote : map) { - map.each([&](const QString &, const std::shared_ptr &emoji) { - for (auto &&shortCode : emoji->shortCodes) - if (shortCode.contains(text, Qt::CaseInsensitive)) - out.push_back({emoji->emote, shortCode, "Emoji"}); - }); + if (emote.first.string.contains(text, Qt::CaseInsensitive)) + { + out.push_back( + {emote.second, emote.second->name.string, providerName}); + } } +} + +void addEmojis(std::vector &out, const EmojiMap &map, + const QString &text) +{ + map.each([&](const QString &, const std::shared_ptr &emoji) { + for (auto &&shortCode : emoji->shortCodes) + { + if (shortCode.contains(text, Qt::CaseInsensitive)) + { + out.push_back({emoji->emote, shortCode, "Emoji"}); + } + } + }); +} + } // namespace +namespace chatterino { + InputCompletionPopup::InputCompletionPopup(QWidget *parent) : BasePopup({BasePopup::EnableCustomFrame, BasePopup::Frameless, BasePopup::DontFocus, BaseWindow::DisableLayoutSave}, @@ -52,30 +64,17 @@ InputCompletionPopup::InputCompletionPopup(QWidget *parent) QObject::connect(&this->redrawTimer_, &QTimer::timeout, this, [this] { if (this->isVisible()) + { this->ui_.listView->doItemsLayout(); + } }); this->redrawTimer_.setInterval(33); } -void InputCompletionPopup::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 InputCompletionPopup::updateEmotes(const QString &text, ChannelPtr channel) { - std::vector<_Emote> emotes; - auto tc = dynamic_cast(channel.get()); + std::vector emotes; + auto *tc = dynamic_cast(channel.get()); // returns true also for special Twitch channels (/live, /mentions, /whispers, etc.) if (channel->isTwitchChannel()) { @@ -90,7 +89,7 @@ void InputCompletionPopup::updateEmotes(const QString &text, ChannelPtr channel) if (tc && localEmoteData->find(tc->roomId()) != localEmoteData->end()) { - if (auto localEmotes = &localEmoteData->at(tc->roomId())) + if (const auto *localEmotes = &localEmoteData->at(tc->roomId())) { addEmotes(emotes, *localEmotes, text, "Local Twitch Emotes"); @@ -102,9 +101,13 @@ void InputCompletionPopup::updateEmotes(const QString &text, ChannelPtr channel) { // TODO extract "Channel {BetterTTV,7TV,FrankerFaceZ}" text into a #define. if (auto bttv = tc->bttvEmotes()) + { addEmotes(emotes, *bttv, text, "Channel BetterTTV"); + } if (auto ffz = tc->ffzEmotes()) + { addEmotes(emotes, *ffz, text, "Channel FrankerFaceZ"); + } if (auto seventv = tc->seventvEmotes()) { addEmotes(emotes, *seventv, text, "Channel 7TV"); @@ -112,9 +115,13 @@ void InputCompletionPopup::updateEmotes(const QString &text, ChannelPtr channel) } if (auto bttvG = getApp()->twitch->getBttvEmotes().emotes()) + { addEmotes(emotes, *bttvG, text, "Global BetterTTV"); + } if (auto ffzG = getApp()->twitch->getFfzEmotes().emotes()) + { addEmotes(emotes, *ffzG, text, "Global FrankerFaceZ"); + } if (auto seventvG = getApp()->twitch->getSeventvEmotes().globalEmotes()) { addEmotes(emotes, *seventvG, text, "Global 7TV"); @@ -148,8 +155,10 @@ void InputCompletionPopup::updateEmotes(const QString &text, ChannelPtr channel) emote.emote, emote.displayName + " - " + emote.providerName, this->callback_)); - if (count++ == maxEntryCount) + if (count++ == MAX_ENTRY_COUNT) + { break; + } } if (!emotes.empty()) @@ -160,30 +169,33 @@ void InputCompletionPopup::updateEmotes(const QString &text, ChannelPtr channel) void InputCompletionPopup::updateUsers(const QString &text, ChannelPtr channel) { - auto twitchChannel = dynamic_cast(channel.get()); - if (twitchChannel) + auto *tc = dynamic_cast(channel.get()); + if (!tc) { - 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_)); + return; + } - if (count++ == maxEntryCount) - break; - } - if (!chatters.empty()) + auto chatters = tc->accessChatters()->filterByPrefix(text); + this->model_.clear(); + + if (chatters.empty()) + { + return; + } + + int count = 0; + for (const auto &name : chatters) + { + this->model_.addItem(std::make_unique( + nullptr, name, this->callback_)); + + if (count++ == MAX_ENTRY_COUNT) { - this->ui_.listView->setCurrentIndex(this->model_.index(0)); + break; } } -} -bool InputCompletionPopup::eventFilter(QObject *watched, QEvent *event) -{ - return this->ui_.listView->eventFilter(watched, event); + this->ui_.listView->setCurrentIndex(this->model_.index(0)); } void InputCompletionPopup::setInputAction(ActionCallback callback) @@ -191,14 +203,34 @@ void InputCompletionPopup::setInputAction(ActionCallback callback) this->callback_ = std::move(callback); } -void InputCompletionPopup::showEvent(QShowEvent *) +bool InputCompletionPopup::eventFilter(QObject *watched, QEvent *event) +{ + return this->ui_.listView->eventFilter(watched, event); +} + +void InputCompletionPopup::showEvent(QShowEvent * /*event*/) { this->redrawTimer_.start(); } -void InputCompletionPopup::hideEvent(QHideEvent *) +void InputCompletionPopup::hideEvent(QHideEvent * /*event*/) { this->redrawTimer_.stop(); } +void InputCompletionPopup::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(); + }); +} + } // namespace chatterino diff --git a/src/widgets/splits/InputCompletionPopup.hpp b/src/widgets/splits/InputCompletionPopup.hpp index 7a7937f02..38eec2256 100644 --- a/src/widgets/splits/InputCompletionPopup.hpp +++ b/src/widgets/splits/InputCompletionPopup.hpp @@ -14,17 +14,18 @@ class InputCompletionPopup : public BasePopup { using ActionCallback = std::function; - constexpr static int maxEntryCount = 200; + constexpr static int MAX_ENTRY_COUNT = 200; public: 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); + bool eventFilter(QObject *watched, QEvent *event) override; + protected: void showEvent(QShowEvent *event) override; void hideEvent(QHideEvent *event) override; diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index c2bd517aa..58e0ddb30 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -625,7 +625,7 @@ void SplitInput::installKeyPressedEvent() { this->ui_.textEdit->keyPressed.disconnectAll(); this->ui_.textEdit->keyPressed.connect([this](QKeyEvent *event) { - if (auto popup = this->inputCompletionPopup_.get()) + if (auto *popup = this->inputCompletionPopup_.get()) { if (popup->isVisible()) { @@ -674,11 +674,11 @@ void SplitInput::onCursorPositionChanged() void SplitInput::updateCompletionPopup() { - auto channel = this->split_->getChannel().get(); - auto tc = dynamic_cast(channel); + auto *channel = this->split_->getChannel().get(); + auto *tc = dynamic_cast(channel); bool showEmoteCompletion = getSettings()->emoteCompletionWithColon; bool showUsernameCompletion = - tc && getSettings()->showUsernameCompletionMenu; + tc != nullptr && getSettings()->showUsernameCompletionMenu; if (!showEmoteCompletion && !showUsernameCompletion) { this->hideCompletionPopup(); @@ -704,22 +704,32 @@ void SplitInput::updateCompletionPopup() this->hideCompletionPopup(); return; } - else if (text[i] == ':' && showEmoteCompletion) + + if (text[i] == ':' && showEmoteCompletion) { if (i == 0 || text[i - 1].isSpace()) + { this->showCompletionPopup(text.mid(i, position - i + 1).mid(1), true); + } else + { this->hideCompletionPopup(); + } return; } - else if (text[i] == '@' && showUsernameCompletion) + + if (text[i] == '@' && showUsernameCompletion) { if (i == 0 || text[i - 1].isSpace()) + { this->showCompletionPopup(text.mid(i, position - i + 1).mid(1), false); + } else + { this->hideCompletionPopup(); + } return; } } @@ -734,7 +744,7 @@ void SplitInput::showCompletionPopup(const QString &text, bool emoteCompletion) this->inputCompletionPopup_ = new InputCompletionPopup(this); this->inputCompletionPopup_->setInputAction( [that = QObjectRef(this)](const QString &text) mutable { - if (auto this2 = that.get()) + if (auto *this2 = that.get()) { this2->insertCompletionText(text); this2->hideCompletionPopup(); @@ -742,13 +752,17 @@ void SplitInput::showCompletionPopup(const QString &text, bool emoteCompletion) }); } - auto popup = this->inputCompletionPopup_.get(); + auto *popup = this->inputCompletionPopup_.get(); assert(popup); - if (emoteCompletion) // autocomplete emotes + if (emoteCompletion) + { popup->updateEmotes(text, this->split_->getChannel()); - else // autocomplete usernames + } + else + { popup->updateUsers(text, this->split_->getChannel()); + } auto pos = this->mapToGlobal({0, 0}) - QPoint(0, popup->height()) + QPoint((this->width() - popup->width()) / 2, 0); @@ -759,11 +773,13 @@ void SplitInput::showCompletionPopup(const QString &text, bool emoteCompletion) void SplitInput::hideCompletionPopup() { - if (auto popup = this->inputCompletionPopup_.get()) + if (auto *popup = this->inputCompletionPopup_.get()) + { popup->hide(); + } } -void SplitInput::insertCompletionText(const QString &input_) +void SplitInput::insertCompletionText(const QString &input_) const { auto &edit = *this->ui_.textEdit; auto input = input_ + ' '; diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index 23d6a4a80..865cf4012 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -112,7 +112,7 @@ protected: void updateCompletionPopup(); void showCompletionPopup(const QString &text, bool emoteCompletion); void hideCompletionPopup(); - void insertCompletionText(const QString &text); + void insertCompletionText(const QString &input_) const; void openEmotePopup(); void updateCancelReplyButton();