mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
feat: add Go to message
action in various places (#3953)
* feat: add `Go to message` action in search popup * chore: add changelog entry * fix: only scroll if the scrollbar is shown * fix: go to message when view isn't focused * feat: animate highlighted message * fix: missing includes * fix: order of initialization * fix: add `ChannelView::mayContainMessage` to filter messages * feat: add `Go to message` action in `/mentions` * fix: ignore any mentions channel when searching for split * feat: add `Go to message` action in reply-threads * fix: remove redundant `source` parameter * feat: add `Go to message` action in user-cards * feat: add link to deleted message * fix: set current time to 0 when starting animation * chore: update changelog * fix: add default case (unreachable) * chore: removed unused variable * fix: search in mentions * fix: always attempt to focus split * fix: rename `Link::MessageId` to `Link::JumpToMessage` * fix: rename `selectAndScrollToMessage` to `scrollToMessage` * fix: rename internal `scrollToMessage` to `scrollToMessageLayout` * fix: deleted message link in search popup * chore: reword explanation * fix: use for-loop instead of `std::find_if` * refactor: define highlight colors in `BaseTheme` * core: replace `iff` with `if` * fix: only return if the message found * Reword/phrase/dot changelog entries Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
parent
5655a7d718
commit
be72d73c3d
14 changed files with 344 additions and 12 deletions
|
@ -32,6 +32,8 @@
|
|||
- Minor: Add settings to toggle BTTV/FFZ global/channel emotes (#3935)
|
||||
- Minor: Add AutoMod message flag filter. (#3938)
|
||||
- Minor: Added whitespace trim to username field in nicknames (#3946)
|
||||
- Minor: Added `Go to message` context menu action to search popup, mentions, usercard and reply threads. (#3953)
|
||||
- Minor: Added link back to original message that was deleted. (#3953)
|
||||
- Bugfix: Fix crash that can occur when closing and quickly reopening a split, then running a command. (#3852)
|
||||
- Bugfix: Connection to Twitch PubSub now recovers more reliably. (#3643, #3716)
|
||||
- Bugfix: Fix crash that can occur when changing channels. (#3799)
|
||||
|
|
|
@ -168,6 +168,12 @@ void AB_THEME_CLASS::actuallyUpdate(double hue, double multiplier)
|
|||
// this->messages.seperator =
|
||||
// this->messages.seperatorInner =
|
||||
|
||||
int complementaryGray = this->isLightTheme() ? 20 : 230;
|
||||
this->messages.highlightAnimationStart =
|
||||
QColor(complementaryGray, complementaryGray, complementaryGray, 110);
|
||||
this->messages.highlightAnimationEnd =
|
||||
QColor(complementaryGray, complementaryGray, complementaryGray, 0);
|
||||
|
||||
// Scrollbar
|
||||
this->scrollbars.background = QColor(0, 0, 0, 0);
|
||||
// this->scrollbars.background = splits.background;
|
||||
|
|
|
@ -74,6 +74,9 @@ public:
|
|||
// QColor seperator;
|
||||
// QColor seperatorInner;
|
||||
QColor selection;
|
||||
|
||||
QColor highlightAnimationStart;
|
||||
QColor highlightAnimationEnd;
|
||||
} messages;
|
||||
|
||||
/// SCROLLBAR
|
||||
|
|
|
@ -25,6 +25,7 @@ public:
|
|||
CopyToClipboard,
|
||||
ReplyToMessage,
|
||||
ViewThread,
|
||||
JumpToMessage,
|
||||
};
|
||||
|
||||
Link();
|
||||
|
|
|
@ -66,6 +66,11 @@ int MessageLayout::getHeight() const
|
|||
return container_->getHeight();
|
||||
}
|
||||
|
||||
int MessageLayout::getWidth() const
|
||||
{
|
||||
return this->container_->getWidth();
|
||||
}
|
||||
|
||||
// Layout
|
||||
// return true if redraw is required
|
||||
bool MessageLayout::layout(int width, float scale, MessageElementFlags flags)
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
const MessagePtr &getMessagePtr() const;
|
||||
|
||||
int getHeight() const;
|
||||
int getWidth() const;
|
||||
|
||||
MessageLayoutFlags flags;
|
||||
|
||||
|
|
|
@ -1471,15 +1471,17 @@ void TwitchMessageBuilder::deletionMessage(const MessagePtr originalMessage,
|
|||
MessageColor::System);
|
||||
if (originalMessage->messageText.length() > 50)
|
||||
{
|
||||
builder->emplace<TextElement>(
|
||||
originalMessage->messageText.left(50) + "…",
|
||||
MessageElementFlag::Text, MessageColor::Text);
|
||||
builder
|
||||
->emplace<TextElement>(originalMessage->messageText.left(50) + "…",
|
||||
MessageElementFlag::Text, MessageColor::Text)
|
||||
->setLink({Link::JumpToMessage, originalMessage->id});
|
||||
}
|
||||
else
|
||||
{
|
||||
builder->emplace<TextElement>(originalMessage->messageText,
|
||||
MessageElementFlag::Text,
|
||||
MessageColor::Text);
|
||||
builder
|
||||
->emplace<TextElement>(originalMessage->messageText,
|
||||
MessageElementFlag::Text, MessageColor::Text)
|
||||
->setLink({Link::JumpToMessage, originalMessage->id});
|
||||
}
|
||||
builder->message().timeoutUser = "msg:" + originalMessage->id;
|
||||
}
|
||||
|
@ -1511,14 +1513,17 @@ void TwitchMessageBuilder::deletionMessage(const DeleteAction &action,
|
|||
MessageColor::System);
|
||||
if (action.messageText.length() > 50)
|
||||
{
|
||||
builder->emplace<TextElement>(action.messageText.left(50) + "…",
|
||||
MessageElementFlag::Text,
|
||||
MessageColor::Text);
|
||||
builder
|
||||
->emplace<TextElement>(action.messageText.left(50) + "…",
|
||||
MessageElementFlag::Text, MessageColor::Text)
|
||||
->setLink({Link::JumpToMessage, action.messageId});
|
||||
}
|
||||
else
|
||||
{
|
||||
builder->emplace<TextElement>(
|
||||
action.messageText, MessageElementFlag::Text, MessageColor::Text);
|
||||
builder
|
||||
->emplace<TextElement>(action.messageText, MessageElementFlag::Text,
|
||||
MessageColor::Text)
|
||||
->setLink({Link::JumpToMessage, action.messageId});
|
||||
}
|
||||
builder->message().timeoutUser = "msg:" + action.messageId;
|
||||
}
|
||||
|
|
|
@ -320,6 +320,11 @@ void WindowManager::select(SplitContainer *container)
|
|||
this->selectSplitContainer.invoke(container);
|
||||
}
|
||||
|
||||
void WindowManager::scrollToMessage(const MessagePtr &message)
|
||||
{
|
||||
this->scrollToMessageSignal.invoke(message);
|
||||
}
|
||||
|
||||
QPoint WindowManager::emotePopupPos()
|
||||
{
|
||||
return this->emotePopupPos_;
|
||||
|
|
|
@ -15,6 +15,7 @@ class Settings;
|
|||
class Paths;
|
||||
class Window;
|
||||
class SplitContainer;
|
||||
class ChannelView;
|
||||
|
||||
enum class MessageElementFlag : int64_t;
|
||||
using MessageElementFlags = FlagsEnum<MessageElementFlag>;
|
||||
|
@ -66,6 +67,13 @@ public:
|
|||
|
||||
void select(Split *split);
|
||||
void select(SplitContainer *container);
|
||||
/**
|
||||
* Scrolls to the message in a split that's not
|
||||
* a mentions view and focuses the split.
|
||||
*
|
||||
* @param message Message to scroll to.
|
||||
*/
|
||||
void scrollToMessage(const MessagePtr &message);
|
||||
|
||||
QPoint emotePopupPos();
|
||||
void setEmotePopupPos(QPoint pos);
|
||||
|
@ -105,6 +113,7 @@ public:
|
|||
|
||||
pajlada::Signals::Signal<Split *> selectSplit;
|
||||
pajlada::Signals::Signal<SplitContainer *> selectSplitContainer;
|
||||
pajlada::Signals::Signal<const MessagePtr &> scrollToMessageSignal;
|
||||
|
||||
private:
|
||||
static void encodeNodeRecursively(SplitContainer::Node *node,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "util/InitUpdateButton.hpp"
|
||||
#include "widgets/Window.hpp"
|
||||
#include "widgets/dialogs/SettingsDialog.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
#include "widgets/helper/NotebookButton.hpp"
|
||||
#include "widgets/helper/NotebookTab.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
|
@ -1006,6 +1007,29 @@ SplitNotebook::SplitNotebook(Window *parent)
|
|||
[this](SplitContainer *sc) {
|
||||
this->select(sc);
|
||||
});
|
||||
|
||||
this->signalHolder_.managedConnect(
|
||||
getApp()->windows->scrollToMessageSignal,
|
||||
[this](const MessagePtr &message) {
|
||||
for (auto &&item : this->items())
|
||||
{
|
||||
if (auto sc = dynamic_cast<SplitContainer *>(item.page))
|
||||
{
|
||||
for (auto *split : sc->getSplits())
|
||||
{
|
||||
if (split->getChannel()->getType() !=
|
||||
Channel::Type::TwitchMentions)
|
||||
{
|
||||
if (split->getChannelView().scrollToMessage(
|
||||
message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void SplitNotebook::showEvent(QShowEvent *)
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
#include "ChannelView.hpp"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QColor>
|
||||
#include <QDate>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QEasingCurve>
|
||||
#include <QGraphicsBlurEffect>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
#include <QScreen>
|
||||
#include <QVariantAnimation>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
|
@ -118,12 +121,23 @@ namespace {
|
|||
addPageLink("FFZ");
|
||||
}
|
||||
}
|
||||
|
||||
// Current function: https://www.desmos.com/calculator/vdyamchjwh
|
||||
qreal highlightEasingFunction(qreal progress)
|
||||
{
|
||||
if (progress <= 0.1)
|
||||
{
|
||||
return 1.0 - pow(10.0 * progress, 3.0);
|
||||
}
|
||||
return 1.0 + pow((20.0 / 9.0) * (0.5 * progress - 0.5), 3.0);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ChannelView::ChannelView(BaseWidget *parent, Split *split, Context context)
|
||||
: BaseWidget(parent)
|
||||
, split_(split)
|
||||
, scrollBar_(new Scrollbar(this))
|
||||
, highlightAnimation_(this)
|
||||
, context_(context)
|
||||
{
|
||||
this->setMouseTracking(true);
|
||||
|
@ -164,6 +178,12 @@ ChannelView::ChannelView(BaseWidget *parent, Split *split, Context context)
|
|||
// of any place where you can, or where it would make sense,
|
||||
// to tab to a ChannelVieChannelView
|
||||
this->setFocusPolicy(Qt::FocusPolicy::ClickFocus);
|
||||
|
||||
this->setupHighlightAnimationColors();
|
||||
this->highlightAnimation_.setDuration(1500);
|
||||
auto curve = QEasingCurve();
|
||||
curve.setCustomType(highlightEasingFunction);
|
||||
this->highlightAnimation_.setEasingCurve(curve);
|
||||
}
|
||||
|
||||
void ChannelView::initializeLayout()
|
||||
|
@ -339,9 +359,18 @@ void ChannelView::themeChangedEvent()
|
|||
{
|
||||
BaseWidget::themeChangedEvent();
|
||||
|
||||
this->setupHighlightAnimationColors();
|
||||
this->queueLayout();
|
||||
}
|
||||
|
||||
void ChannelView::setupHighlightAnimationColors()
|
||||
{
|
||||
this->highlightAnimation_.setStartValue(
|
||||
this->theme->messages.highlightAnimationStart);
|
||||
this->highlightAnimation_.setEndValue(
|
||||
this->theme->messages.highlightAnimationEnd);
|
||||
}
|
||||
|
||||
void ChannelView::scaleChangedEvent(float scale)
|
||||
{
|
||||
BaseWidget::scaleChangedEvent(scale);
|
||||
|
@ -392,7 +421,8 @@ void ChannelView::performLayout(bool causedByScrollbar)
|
|||
auto &messages = this->getMessagesSnapshot();
|
||||
|
||||
this->showingLatestMessages_ =
|
||||
this->scrollBar_->isAtBottom() || !this->scrollBar_->isVisible();
|
||||
this->scrollBar_->isAtBottom() ||
|
||||
(!this->scrollBar_->isVisible() && !causedByScrollbar);
|
||||
|
||||
/// Layout visible messages
|
||||
this->layoutVisibleMessages(messages);
|
||||
|
@ -475,6 +505,7 @@ void ChannelView::updateScrollbar(
|
|||
{
|
||||
this->scrollBar_->setDesiredValue(0);
|
||||
}
|
||||
this->showScrollBar_ = showScrollbar;
|
||||
|
||||
this->scrollBar_->setMaximum(messages.size());
|
||||
|
||||
|
@ -1088,6 +1119,86 @@ MessageElementFlags ChannelView::getFlags() const
|
|||
return flags;
|
||||
}
|
||||
|
||||
bool ChannelView::scrollToMessage(const MessagePtr &message)
|
||||
{
|
||||
if (!this->mayContainMessage(message))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &messagesSnapshot = this->getMessagesSnapshot();
|
||||
if (messagesSnapshot.size() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Figure out if we can somehow binary-search here.
|
||||
// Currently, a message only sometimes stores a QDateTime,
|
||||
// but always a QTime (inaccurate on midnight).
|
||||
//
|
||||
// We're searching from the bottom since it's more likely for a user
|
||||
// wanting to go to a message that recently scrolled out of view.
|
||||
size_t messageIdx = messagesSnapshot.size() - 1;
|
||||
for (; messageIdx < SIZE_MAX; messageIdx--)
|
||||
{
|
||||
if (messagesSnapshot[messageIdx]->getMessagePtr() == message)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (messageIdx == SIZE_MAX)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->scrollToMessageLayout(messagesSnapshot[messageIdx].get(), messageIdx);
|
||||
getApp()->windows->select(this->split_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChannelView::scrollToMessageId(const QString &messageId)
|
||||
{
|
||||
auto &messagesSnapshot = this->getMessagesSnapshot();
|
||||
if (messagesSnapshot.size() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're searching from the bottom since it's more likely for a user
|
||||
// wanting to go to a message that recently scrolled out of view.
|
||||
size_t messageIdx = messagesSnapshot.size() - 1;
|
||||
for (; messageIdx < SIZE_MAX; messageIdx--)
|
||||
{
|
||||
if (messagesSnapshot[messageIdx]->getMessagePtr()->id == messageId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (messageIdx == SIZE_MAX)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this->scrollToMessageLayout(messagesSnapshot[messageIdx].get(), messageIdx);
|
||||
getApp()->windows->select(this->split_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChannelView::scrollToMessageLayout(MessageLayout *layout,
|
||||
size_t messageIdx)
|
||||
{
|
||||
this->highlightedMessage_ = layout;
|
||||
this->highlightAnimation_.setCurrentTime(0);
|
||||
this->highlightAnimation_.start(QAbstractAnimation::KeepWhenStopped);
|
||||
|
||||
if (this->showScrollBar_)
|
||||
{
|
||||
this->getScrollBar().setDesiredValue(messageIdx);
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelView::paintEvent(QPaintEvent * /*event*/)
|
||||
{
|
||||
// BenchmarkGuard benchmark("paint");
|
||||
|
@ -1144,6 +1255,17 @@ void ChannelView::drawMessages(QPainter &painter)
|
|||
layout->paint(painter, DRAW_WIDTH, y, i, this->selection_,
|
||||
isLastMessage, windowFocused, isMentions);
|
||||
|
||||
if (this->highlightedMessage_ == layout)
|
||||
{
|
||||
painter.fillRect(
|
||||
0, y, layout->getWidth(), layout->getHeight(),
|
||||
this->highlightAnimation_.currentValue().value<QColor>());
|
||||
if (this->highlightAnimation_.state() == QVariantAnimation::Stopped)
|
||||
{
|
||||
this->highlightedMessage_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
y += layout->getHeight();
|
||||
|
||||
end = layout;
|
||||
|
@ -2070,6 +2192,46 @@ void ChannelView::addMessageContextMenuItems(
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool isSearch = this->context_ == Context::Search;
|
||||
bool isReplyOrUserCard = (this->context_ == Context::ReplyThread ||
|
||||
this->context_ == Context::UserCard) &&
|
||||
this->split_;
|
||||
bool isMentions =
|
||||
this->channel()->getType() == Channel::Type::TwitchMentions;
|
||||
if (isSearch || isMentions || isReplyOrUserCard)
|
||||
{
|
||||
const auto &messagePtr = layout->getMessagePtr();
|
||||
menu.addAction("Go to message", [this, &messagePtr, isSearch,
|
||||
isMentions, isReplyOrUserCard] {
|
||||
if (isSearch)
|
||||
{
|
||||
if (const auto &search =
|
||||
dynamic_cast<SearchPopup *>(this->parentWidget()))
|
||||
{
|
||||
search->goToMessage(messagePtr);
|
||||
}
|
||||
}
|
||||
else if (isMentions)
|
||||
{
|
||||
getApp()->windows->scrollToMessage(messagePtr);
|
||||
}
|
||||
else if (isReplyOrUserCard)
|
||||
{
|
||||
// If the thread is in the mentions channel,
|
||||
// we need to find the original split.
|
||||
if (this->split_->getChannel()->getType() ==
|
||||
Channel::Type::TwitchMentions)
|
||||
{
|
||||
getApp()->windows->scrollToMessage(messagePtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->split_->getChannelView().scrollToMessage(messagePtr);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelView::addTwitchLinkContextMenuItems(
|
||||
|
@ -2321,6 +2483,30 @@ void ChannelView::showUserInfoPopup(const QString &userName,
|
|||
userPopup->show();
|
||||
}
|
||||
|
||||
bool ChannelView::mayContainMessage(const MessagePtr &message)
|
||||
{
|
||||
switch (this->channel()->getType())
|
||||
{
|
||||
case Channel::Type::Direct:
|
||||
case Channel::Type::Twitch:
|
||||
case Channel::Type::TwitchWatching:
|
||||
case Channel::Type::Irc:
|
||||
return this->channel()->getName() == message->channelName;
|
||||
case Channel::Type::TwitchWhispers:
|
||||
return message->flags.has(MessageFlag::Whisper);
|
||||
case Channel::Type::TwitchMentions:
|
||||
return message->flags.has(MessageFlag::Highlighted);
|
||||
case Channel::Type::TwitchLive:
|
||||
return message->flags.has(MessageFlag::System);
|
||||
case Channel::Type::TwitchEnd: // TODO: not used?
|
||||
case Channel::Type::None: // Unspecific
|
||||
case Channel::Type::Misc: // Unspecific
|
||||
return true;
|
||||
default:
|
||||
return true; // unreachable
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link,
|
||||
MessageLayout *layout)
|
||||
{
|
||||
|
@ -2442,6 +2628,21 @@ void ChannelView::handleLinkClick(QMouseEvent *event, const Link &link,
|
|||
this->showReplyThreadPopup(layout->getMessagePtr());
|
||||
}
|
||||
break;
|
||||
case Link::JumpToMessage: {
|
||||
if (this->context_ == Context::Search)
|
||||
{
|
||||
if (auto search =
|
||||
dynamic_cast<SearchPopup *>(this->parentWidget()))
|
||||
{
|
||||
search->goToMessageId(link.value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->scrollToMessageId(link.value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <QPaintEvent>
|
||||
#include <QScroller>
|
||||
#include <QTimer>
|
||||
#include <QVariantAnimation>
|
||||
#include <QWheelEvent>
|
||||
#include <QWidget>
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
@ -83,6 +84,17 @@ public:
|
|||
const boost::optional<MessageElementFlags> &getOverrideFlags() const;
|
||||
void updateLastReadMessage();
|
||||
|
||||
/**
|
||||
* Attempts to scroll to a message in this channel.
|
||||
* @return <code>true</code> if the message was found and highlighted.
|
||||
*/
|
||||
bool scrollToMessage(const MessagePtr &message);
|
||||
/**
|
||||
* Attempts to scroll to a message id in this channel.
|
||||
* @return <code>true</code> if the message was found and highlighted.
|
||||
*/
|
||||
bool scrollToMessageId(const QString &id);
|
||||
|
||||
/// Pausing
|
||||
bool pausable() const;
|
||||
void setPausable(bool value);
|
||||
|
@ -119,6 +131,13 @@ public:
|
|||
void showUserInfoPopup(const QString &userName,
|
||||
QString alternativePopoutChannel = QString());
|
||||
|
||||
/**
|
||||
* @brief This method is meant to be used when filtering out channels.
|
||||
* It <b>must</b> return true if a message belongs in this channel.
|
||||
* It <b>might</b> return true if a message doesn't belong in this channel.
|
||||
*/
|
||||
bool mayContainMessage(const MessagePtr &message);
|
||||
|
||||
pajlada::Signals::Signal<QMouseEvent *> mouseDown;
|
||||
pajlada::Signals::NoArgSignal selectionChanged;
|
||||
pajlada::Signals::Signal<HighlightState> tabHighlightRequested;
|
||||
|
@ -208,6 +227,14 @@ private:
|
|||
void enableScrolling(const QPointF &scrollStart);
|
||||
void disableScrolling();
|
||||
|
||||
/**
|
||||
* Scrolls to a message layout that must be from this view.
|
||||
*
|
||||
* @param layout Must be from this channel.
|
||||
* @param messageIdx Must be an index into this channel.
|
||||
*/
|
||||
void scrollToMessageLayout(MessageLayout *layout, size_t messageIdx);
|
||||
|
||||
void setInputReply(const MessagePtr &message);
|
||||
void showReplyThreadPopup(const MessagePtr &message);
|
||||
bool canReplyToMessages() const;
|
||||
|
@ -241,6 +268,7 @@ private:
|
|||
|
||||
Scrollbar *scrollBar_;
|
||||
EffectLabel *goToBottom_;
|
||||
bool showScrollBar_ = false;
|
||||
|
||||
FilterSetPtr channelFilters_;
|
||||
|
||||
|
@ -272,6 +300,11 @@ private:
|
|||
QPointF currentMousePosition_;
|
||||
QTimer scrollTimer_;
|
||||
|
||||
// We're only interested in the pointer, not the contents
|
||||
MessageLayout *highlightedMessage_;
|
||||
QVariantAnimation highlightAnimation_;
|
||||
void setupHighlightAnimationColors();
|
||||
|
||||
struct {
|
||||
QCursor neutral;
|
||||
QCursor up;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "messages/search/MessageFlagsPredicate.hpp"
|
||||
#include "messages/search/RegexPredicate.hpp"
|
||||
#include "messages/search/SubstringPredicate.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "widgets/helper/ChannelView.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
@ -106,6 +107,34 @@ void SearchPopup::addChannel(ChannelView &channel)
|
|||
this->updateWindowTitle();
|
||||
}
|
||||
|
||||
void SearchPopup::goToMessage(const MessagePtr &message)
|
||||
{
|
||||
for (const auto &view : this->searchChannels_)
|
||||
{
|
||||
if (view.get().channel()->getType() == Channel::Type::TwitchMentions)
|
||||
{
|
||||
getApp()->windows->scrollToMessage(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.get().scrollToMessage(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SearchPopup::goToMessageId(const QString &messageId)
|
||||
{
|
||||
for (const auto &view : this->searchChannels_)
|
||||
{
|
||||
if (view.get().scrollToMessageId(messageId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SearchPopup::updateWindowTitle()
|
||||
{
|
||||
QString historyName;
|
||||
|
|
|
@ -19,6 +19,14 @@ public:
|
|||
SearchPopup(QWidget *parent, Split *split = nullptr);
|
||||
|
||||
virtual void addChannel(ChannelView &channel);
|
||||
void goToMessage(const MessagePtr &message);
|
||||
/**
|
||||
* This method should only be used for searches that
|
||||
* don't include a mentions channel,
|
||||
* since it will only search in the opened channels (not globally).
|
||||
* @param messageId
|
||||
*/
|
||||
void goToMessageId(const QString &messageId);
|
||||
|
||||
protected:
|
||||
virtual void updateWindowTitle();
|
||||
|
|
Loading…
Reference in a new issue