From d24e1f8314e19ad7596b39a442a9fd2f9bb5bd6a Mon Sep 17 00:00:00 2001 From: fourtf Date: Thu, 17 May 2018 12:16:13 +0200 Subject: [PATCH] fixed selections moving when new messages come in while selecting --- src/messages/selection.hpp | 5 ++ src/providers/twitch/twitchchannel.cpp | 7 +- src/widgets/helper/channelview.cpp | 115 +++++++++++++++++++------ src/widgets/helper/channelview.hpp | 9 +- src/widgets/helper/splitheader.cpp | 2 +- src/widgets/helper/splitoverlay.cpp | 2 +- src/widgets/scrollbar.cpp | 4 +- 7 files changed, 112 insertions(+), 32 deletions(-) diff --git a/src/messages/selection.hpp b/src/messages/selection.hpp index 62a3ba6a9..805f48a8d 100644 --- a/src/messages/selection.hpp +++ b/src/messages/selection.hpp @@ -42,6 +42,11 @@ struct SelectionItem { { return this->messageIndex == b.messageIndex && this->charIndex == b.charIndex; } + + bool operator!=(const SelectionItem &b) const + { + return this->operator==(b); + } }; struct Selection { diff --git a/src/providers/twitch/twitchchannel.cpp b/src/providers/twitch/twitchchannel.cpp index 4acff566a..49d297309 100644 --- a/src/providers/twitch/twitchchannel.cpp +++ b/src/providers/twitch/twitchchannel.cpp @@ -45,7 +45,8 @@ TwitchChannel::TwitchChannel(const QString &channelName, Communi::IrcConnection this->refreshLiveStatus(); // }); - this->managedConnect(app->accounts->Twitch.currentUserChanged, [this]() { this->setMod(false); }); + this->managedConnect(app->accounts->Twitch.currentUserChanged, + [this]() { this->setMod(false); }); auto refreshPubSubState = [=]() { if (!this->hasModRights()) { @@ -102,6 +103,10 @@ TwitchChannel::TwitchChannel(const QString &channelName, Communi::IrcConnection this->chattersListTimer = new QTimer; QObject::connect(this->chattersListTimer, &QTimer::timeout, doRefreshChatters); this->chattersListTimer->start(5 * 60 * 1000); + + for (int i = 0; i < 1000; i++) { + this->addMessage(messages::Message::createSystemMessage("asdf")); + } } TwitchChannel::~TwitchChannel() diff --git a/src/widgets/helper/channelview.cpp b/src/widgets/helper/channelview.cpp index a62e0b51a..f30ab2323 100644 --- a/src/widgets/helper/channelview.cpp +++ b/src/widgets/helper/channelview.cpp @@ -28,6 +28,8 @@ #include #define LAYOUT_WIDTH (this->width() - (this->scrollBar.isVisible() ? 16 : 4) * this->getScale()) +#define SELECTION_RESUME_SCROLLING_MSG_THRESHOLD 3 +#define CHAT_HOVER_PAUSE_DURATION 300 using namespace chatterino::messages; using namespace chatterino::providers::twitch; @@ -42,9 +44,6 @@ ChannelView::ChannelView(BaseWidget *parent) { auto app = getApp(); -#ifndef Q_OS_MAC -// this->setAttribute(Qt::WA_OpaquePaintEvent); -#endif this->setMouseTracking(true); this->managedConnections.emplace_back(app->settings->wordFlagsChanged.connect([=] { @@ -56,7 +55,8 @@ ChannelView::ChannelView(BaseWidget *parent) // Whenever the scrollbar value has been changed, re-render the ChatWidgetView this->actuallyLayoutMessages(true); this->goToBottom->setVisible(this->enableScrollingToBottom && this->scrollBar.isVisible() && - !this->scrollBar.isAtBottom()); + !this->scrollBar.isAtBottom() && + !this->scrollToBottomAfterTemporaryPause); this->queueUpdate(); }); @@ -97,12 +97,21 @@ ChannelView::ChannelView(BaseWidget *parent) // }); this->pauseTimeout.setSingleShot(true); + QObject::connect(&this->pauseTimeout, &QTimer::timeout, [this] { + + this->pausedTemporarily = false; + if (!this->isPaused() && this->scrollToBottomAfterTemporaryPause) { + this->scrollBar.scrollToBottom(); + } + + this->scrollToBottomAfterTemporaryPause = false; + }); // auto e = new QResizeEvent(this->size(), this->size()); // this->resizeEvent(e); // delete e; - this->scrollBar.resize(this->scrollBar.width(), this->height() + 1); + // this->scrollBar.resize(this->scrollBar.width(), this->height() + 1); app->settings->showLastMessageIndicator.connect( [this](auto, auto) { @@ -120,6 +129,11 @@ ChannelView::ChannelView(BaseWidget *parent) this->layoutQueued = false; } }); + + QTimer::singleShot(1, this, [this] { + this->scrollBar.setGeometry(this->width() - this->scrollBar.width(), 0, + this->scrollBar.width(), this->height()); + }); } ChannelView::~ChannelView() @@ -336,10 +350,11 @@ const boost::optional &ChannelView::getOverride messages::LimitedQueueSnapshot ChannelView::getMessagesSnapshot() { - if (!this->paused) { - this->snapshot = this->messages.getSnapshot(); - } + // if (!this->isPaused()) { + this->snapshot = this->messages.getSnapshot(); + // } + // return this->snapshot; return this->snapshot; } @@ -363,14 +378,18 @@ void ChannelView::setChannel(ChannelPtr newChannel) } this->lastMessageHasAlternateBackground = !this->lastMessageHasAlternateBackground; + if (this->isPaused()) { + this->messagesAddedSinceSelectionPause++; + } + if (this->messages.pushBack(MessageLayoutPtr(messageRef), deleted)) { - if (!this->paused) { - if (this->scrollBar.isAtBottom()) { - this->scrollBar.scrollToBottom(); - } else { - this->scrollBar.offset(-1); - } + // if (!this->isPaused()) { + if (this->scrollBar.isAtBottom()) { + this->scrollBar.scrollToBottom(); + } else { + this->scrollBar.offset(-1); } + // } } if (!(message->flags & Message::DoNotTriggerNotification)) { @@ -395,7 +414,7 @@ void ChannelView::setChannel(ChannelPtr newChannel) messageRefs.at(i) = MessageLayoutPtr(new MessageLayout(messages.at(i))); } - if (!this->paused) { + if (!this->isPaused()) { if (this->messages.pushFront(messageRefs).size() > 0) { if (this->scrollBar.isAtBottom()) { this->scrollBar.scrollToBottom(); @@ -474,7 +493,15 @@ void ChannelView::detachChannel() void ChannelView::pause(int msecTimeout) { - this->paused = true; + if (!this->pauseTimeout.isActive()) { + this->scrollToBottomAfterTemporaryPause = this->scrollBar.isAtBottom(); + } + + this->beginPause(); + + // this->scrollBar.setDesiredValue(this->scrollBar.getDesiredValue() - 0.01); + + this->pausedTemporarily = true; this->pauseTimeout.start(msecTimeout); } @@ -492,8 +519,8 @@ void ChannelView::updateLastReadMessage() void ChannelView::resizeEvent(QResizeEvent *) { - this->scrollBar.resize(this->scrollBar.width(), this->height()); - this->scrollBar.move(this->width() - this->scrollBar.width(), 0); + this->scrollBar.setGeometry(this->width() - this->scrollBar.width(), 0, this->scrollBar.width(), + this->height()); this->goToBottom->setGeometry(0, this->height() - 32, this->width(), 32); @@ -507,6 +534,15 @@ void ChannelView::resizeEvent(QResizeEvent *) void ChannelView::setSelection(const SelectionItem &start, const SelectionItem &end) { // selections + if (!this->selecting && start != end) { + this->messagesAddedSinceSelectionPause = + (this->scrollToBottomAfterTemporaryPause || this->scrollBar.isAtBottom()) ? 0 : 100; + + this->beginPause(); + this->selecting = true; + this->pausedBySelection = true; + } + this->selection = Selection(start, end); this->selectionChanged.invoke(); @@ -536,6 +572,23 @@ messages::MessageElement::Flags ChannelView::getFlags() const return flags; } +bool ChannelView::isPaused() +{ + return this->pausedTemporarily || this->pausedBySelection; +} + +void ChannelView::beginPause() +{ + if (this->scrollBar.isAtBottom()) { + this->scrollBar.setDesiredValue(this->scrollBar.getDesiredValue() - 0.001); + this->layoutMessages(); + } +} + +void ChannelView::endPause() +{ +} + void ChannelView::paintEvent(QPaintEvent * /*event*/) { // BENCH(timer); @@ -691,7 +744,7 @@ void ChannelView::enterEvent(QEvent *) void ChannelView::leaveEvent(QEvent *) { - this->paused = false; + this->pausedTemporarily = false; } void ChannelView::mouseMoveEvent(QMouseEvent *event) @@ -706,7 +759,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event) auto app = getApp(); if (app->settings->pauseChatHover.getValue()) { - this->pause(300); + this->pause(CHAT_HOVER_PAUSE_DURATION); } auto tooltipWidget = TooltipWidget::getInstance(); @@ -722,8 +775,8 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event) } // is selecting - if (this->selecting) { - this->pause(500); + if (this->isMouseDown) { + this->pause(300); int index = layout->getSelectionIndex(relativePos); this->setSelection(this->selection.start, SelectionItem(messageIndex, index)); @@ -804,7 +857,6 @@ void ChannelView::mousePressEvent(QMouseEvent *event) SelectionItem selectionItem(lastMessageIndex, lastCharacterIndex); this->setSelection(selectionItem, selectionItem); - this->selecting = true; return; } @@ -818,7 +870,6 @@ void ChannelView::mousePressEvent(QMouseEvent *event) auto selectionItem = SelectionItem(messageIndex, index); this->setSelection(selectionItem, selectionItem); - this->selecting = true; this->repaint(); } @@ -841,11 +892,23 @@ void ChannelView::mouseReleaseEvent(QMouseEvent *event) auto app = getApp(); if (this->selecting) { - this->paused = false; + if (this->messagesAddedSinceSelectionPause <= SELECTION_RESUME_SCROLLING_MSG_THRESHOLD) { + // don't scroll + this->scrollBar.scrollToBottom(false); + // this->scrollBar.setDesiredValue(this->scrollBar.getDesiredValue() - + // this->messagesAddedSinceSelectionPause); + } + + this->scrollToBottomAfterTemporaryPause = false; + this->pausedBySelection = false; + this->selecting = false; + this->pauseTimeout.stop(); + this->pausedTemporarily = false; + + this->layoutMessages(); } this->isMouseDown = false; - this->selecting = false; float distance = util::distanceBetweenPoints(this->lastPressPosition, event->screenPos()); diff --git a/src/widgets/helper/channelview.hpp b/src/widgets/helper/channelview.hpp index 472626322..a3c9b6632 100644 --- a/src/widgets/helper/channelview.hpp +++ b/src/widgets/helper/channelview.hpp @@ -86,7 +86,10 @@ private: bool updateQueued = false; bool messageWasAdded = false; bool lastMessageHasAlternateBackground = false; - bool paused = false; + bool pausedTemporarily = false; + bool pausedBySelection = false; + bool scrollToBottomAfterTemporaryPause = false; + int messagesAddedSinceSelectionPause = 0; QTimer pauseTimeout; boost::optional overrideFlags; messages::MessageLayoutPtr lastReadMessage; @@ -99,6 +102,10 @@ private: void drawMessages(QPainter &painter); void setSelection(const messages::SelectionItem &start, const messages::SelectionItem &end); messages::MessageElement::Flags getFlags() const; + bool isPaused(); + + void beginPause(); + void endPause(); ChannelPtr channel; diff --git a/src/widgets/helper/splitheader.cpp b/src/widgets/helper/splitheader.cpp index 845f037b7..7264f81ab 100644 --- a/src/widgets/helper/splitheader.cpp +++ b/src/widgets/helper/splitheader.cpp @@ -253,7 +253,7 @@ void SplitHeader::mouseReleaseEvent(QMouseEvent *event) TooltipWidget *widget = new TooltipWidget(); - widget->setText("Double click or press to change the channel.\nClick and " + widget->setText("Double click or press to change the channel.\nClick and " "drag to move the split."); widget->setAttribute(Qt::WA_DeleteOnClose); widget->move(pos); diff --git a/src/widgets/helper/splitoverlay.cpp b/src/widgets/helper/splitoverlay.cpp index cded62114..1c78a9de2 100644 --- a/src/widgets/helper/splitoverlay.cpp +++ b/src/widgets/helper/splitoverlay.cpp @@ -86,7 +86,7 @@ SplitOverlay::SplitOverlay(Split *parent) void SplitOverlay::paintEvent(QPaintEvent *event) { QPainter painter(this); - painter.fillRect(this->rect(), QColor(0, 0, 0, 90)); + painter.fillRect(this->rect(), QColor(0, 0, 0, 150)); QRect rect; switch (this->hoveredElement) { diff --git a/src/widgets/scrollbar.cpp b/src/widgets/scrollbar.cpp index 01df63211..039d9a209 100644 --- a/src/widgets/scrollbar.cpp +++ b/src/widgets/scrollbar.cpp @@ -109,14 +109,14 @@ void Scrollbar::setDesiredValue(qreal value, bool animated) // } this->currentValueAnimation.setEndValue(value); this->smoothScrollingOffset = 0; - this->atBottom = ((this->getMaximum() - this->getLargeChange()) - value) <= 0.01; + this->atBottom = ((this->getMaximum() - this->getLargeChange()) - value) <= 0.0001; this->currentValueAnimation.start(); } else { if (this->currentValueAnimation.state() != QPropertyAnimation::Running) { this->smoothScrollingOffset = 0; this->desiredValue = value; this->currentValueAnimation.stop(); - this->atBottom = ((this->getMaximum() - this->getLargeChange()) - value) <= 0.01; + this->atBottom = ((this->getMaximum() - this->getLargeChange()) - value) <= 0.0001; setCurrentValue(value); } }