fixed selections moving when new messages come in while selecting

This commit is contained in:
fourtf 2018-05-17 12:16:13 +02:00
parent 8ee0f85a2b
commit d24e1f8314
7 changed files with 112 additions and 32 deletions

View file

@ -42,6 +42,11 @@ struct SelectionItem {
{ {
return this->messageIndex == b.messageIndex && this->charIndex == b.charIndex; return this->messageIndex == b.messageIndex && this->charIndex == b.charIndex;
} }
bool operator!=(const SelectionItem &b) const
{
return this->operator==(b);
}
}; };
struct Selection { struct Selection {

View file

@ -45,7 +45,8 @@ TwitchChannel::TwitchChannel(const QString &channelName, Communi::IrcConnection
this->refreshLiveStatus(); // this->refreshLiveStatus(); //
}); });
this->managedConnect(app->accounts->Twitch.currentUserChanged, [this]() { this->setMod(false); }); this->managedConnect(app->accounts->Twitch.currentUserChanged,
[this]() { this->setMod(false); });
auto refreshPubSubState = [=]() { auto refreshPubSubState = [=]() {
if (!this->hasModRights()) { if (!this->hasModRights()) {
@ -102,6 +103,10 @@ TwitchChannel::TwitchChannel(const QString &channelName, Communi::IrcConnection
this->chattersListTimer = new QTimer; this->chattersListTimer = new QTimer;
QObject::connect(this->chattersListTimer, &QTimer::timeout, doRefreshChatters); QObject::connect(this->chattersListTimer, &QTimer::timeout, doRefreshChatters);
this->chattersListTimer->start(5 * 60 * 1000); this->chattersListTimer->start(5 * 60 * 1000);
for (int i = 0; i < 1000; i++) {
this->addMessage(messages::Message::createSystemMessage("asdf"));
}
} }
TwitchChannel::~TwitchChannel() TwitchChannel::~TwitchChannel()

View file

@ -28,6 +28,8 @@
#include <memory> #include <memory>
#define LAYOUT_WIDTH (this->width() - (this->scrollBar.isVisible() ? 16 : 4) * this->getScale()) #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::messages;
using namespace chatterino::providers::twitch; using namespace chatterino::providers::twitch;
@ -42,9 +44,6 @@ ChannelView::ChannelView(BaseWidget *parent)
{ {
auto app = getApp(); auto app = getApp();
#ifndef Q_OS_MAC
// this->setAttribute(Qt::WA_OpaquePaintEvent);
#endif
this->setMouseTracking(true); this->setMouseTracking(true);
this->managedConnections.emplace_back(app->settings->wordFlagsChanged.connect([=] { 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 // Whenever the scrollbar value has been changed, re-render the ChatWidgetView
this->actuallyLayoutMessages(true); this->actuallyLayoutMessages(true);
this->goToBottom->setVisible(this->enableScrollingToBottom && this->scrollBar.isVisible() && this->goToBottom->setVisible(this->enableScrollingToBottom && this->scrollBar.isVisible() &&
!this->scrollBar.isAtBottom()); !this->scrollBar.isAtBottom() &&
!this->scrollToBottomAfterTemporaryPause);
this->queueUpdate(); this->queueUpdate();
}); });
@ -97,12 +97,21 @@ ChannelView::ChannelView(BaseWidget *parent)
// }); // });
this->pauseTimeout.setSingleShot(true); 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()); // auto e = new QResizeEvent(this->size(), this->size());
// this->resizeEvent(e); // this->resizeEvent(e);
// delete 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( app->settings->showLastMessageIndicator.connect(
[this](auto, auto) { [this](auto, auto) {
@ -120,6 +129,11 @@ ChannelView::ChannelView(BaseWidget *parent)
this->layoutQueued = false; this->layoutQueued = false;
} }
}); });
QTimer::singleShot(1, this, [this] {
this->scrollBar.setGeometry(this->width() - this->scrollBar.width(), 0,
this->scrollBar.width(), this->height());
});
} }
ChannelView::~ChannelView() ChannelView::~ChannelView()
@ -336,10 +350,11 @@ const boost::optional<messages::MessageElement::Flags> &ChannelView::getOverride
messages::LimitedQueueSnapshot<MessageLayoutPtr> ChannelView::getMessagesSnapshot() messages::LimitedQueueSnapshot<MessageLayoutPtr> ChannelView::getMessagesSnapshot()
{ {
if (!this->paused) { // if (!this->isPaused()) {
this->snapshot = this->messages.getSnapshot(); this->snapshot = this->messages.getSnapshot();
} // }
// return this->snapshot;
return this->snapshot; return this->snapshot;
} }
@ -363,14 +378,18 @@ void ChannelView::setChannel(ChannelPtr newChannel)
} }
this->lastMessageHasAlternateBackground = !this->lastMessageHasAlternateBackground; this->lastMessageHasAlternateBackground = !this->lastMessageHasAlternateBackground;
if (this->isPaused()) {
this->messagesAddedSinceSelectionPause++;
}
if (this->messages.pushBack(MessageLayoutPtr(messageRef), deleted)) { if (this->messages.pushBack(MessageLayoutPtr(messageRef), deleted)) {
if (!this->paused) { // if (!this->isPaused()) {
if (this->scrollBar.isAtBottom()) { if (this->scrollBar.isAtBottom()) {
this->scrollBar.scrollToBottom(); this->scrollBar.scrollToBottom();
} else { } else {
this->scrollBar.offset(-1); this->scrollBar.offset(-1);
}
} }
// }
} }
if (!(message->flags & Message::DoNotTriggerNotification)) { if (!(message->flags & Message::DoNotTriggerNotification)) {
@ -395,7 +414,7 @@ void ChannelView::setChannel(ChannelPtr newChannel)
messageRefs.at(i) = MessageLayoutPtr(new MessageLayout(messages.at(i))); messageRefs.at(i) = MessageLayoutPtr(new MessageLayout(messages.at(i)));
} }
if (!this->paused) { if (!this->isPaused()) {
if (this->messages.pushFront(messageRefs).size() > 0) { if (this->messages.pushFront(messageRefs).size() > 0) {
if (this->scrollBar.isAtBottom()) { if (this->scrollBar.isAtBottom()) {
this->scrollBar.scrollToBottom(); this->scrollBar.scrollToBottom();
@ -474,7 +493,15 @@ void ChannelView::detachChannel()
void ChannelView::pause(int msecTimeout) 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); this->pauseTimeout.start(msecTimeout);
} }
@ -492,8 +519,8 @@ void ChannelView::updateLastReadMessage()
void ChannelView::resizeEvent(QResizeEvent *) void ChannelView::resizeEvent(QResizeEvent *)
{ {
this->scrollBar.resize(this->scrollBar.width(), this->height()); this->scrollBar.setGeometry(this->width() - this->scrollBar.width(), 0, this->scrollBar.width(),
this->scrollBar.move(this->width() - this->scrollBar.width(), 0); this->height());
this->goToBottom->setGeometry(0, this->height() - 32, this->width(), 32); 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) void ChannelView::setSelection(const SelectionItem &start, const SelectionItem &end)
{ {
// selections // 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->selection = Selection(start, end);
this->selectionChanged.invoke(); this->selectionChanged.invoke();
@ -536,6 +572,23 @@ messages::MessageElement::Flags ChannelView::getFlags() const
return flags; 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*/) void ChannelView::paintEvent(QPaintEvent * /*event*/)
{ {
// BENCH(timer); // BENCH(timer);
@ -691,7 +744,7 @@ void ChannelView::enterEvent(QEvent *)
void ChannelView::leaveEvent(QEvent *) void ChannelView::leaveEvent(QEvent *)
{ {
this->paused = false; this->pausedTemporarily = false;
} }
void ChannelView::mouseMoveEvent(QMouseEvent *event) void ChannelView::mouseMoveEvent(QMouseEvent *event)
@ -706,7 +759,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
auto app = getApp(); auto app = getApp();
if (app->settings->pauseChatHover.getValue()) { if (app->settings->pauseChatHover.getValue()) {
this->pause(300); this->pause(CHAT_HOVER_PAUSE_DURATION);
} }
auto tooltipWidget = TooltipWidget::getInstance(); auto tooltipWidget = TooltipWidget::getInstance();
@ -722,8 +775,8 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
} }
// is selecting // is selecting
if (this->selecting) { if (this->isMouseDown) {
this->pause(500); this->pause(300);
int index = layout->getSelectionIndex(relativePos); int index = layout->getSelectionIndex(relativePos);
this->setSelection(this->selection.start, SelectionItem(messageIndex, index)); this->setSelection(this->selection.start, SelectionItem(messageIndex, index));
@ -804,7 +857,6 @@ void ChannelView::mousePressEvent(QMouseEvent *event)
SelectionItem selectionItem(lastMessageIndex, lastCharacterIndex); SelectionItem selectionItem(lastMessageIndex, lastCharacterIndex);
this->setSelection(selectionItem, selectionItem); this->setSelection(selectionItem, selectionItem);
this->selecting = true;
return; return;
} }
@ -818,7 +870,6 @@ void ChannelView::mousePressEvent(QMouseEvent *event)
auto selectionItem = SelectionItem(messageIndex, index); auto selectionItem = SelectionItem(messageIndex, index);
this->setSelection(selectionItem, selectionItem); this->setSelection(selectionItem, selectionItem);
this->selecting = true;
this->repaint(); this->repaint();
} }
@ -841,11 +892,23 @@ void ChannelView::mouseReleaseEvent(QMouseEvent *event)
auto app = getApp(); auto app = getApp();
if (this->selecting) { 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->isMouseDown = false;
this->selecting = false;
float distance = util::distanceBetweenPoints(this->lastPressPosition, event->screenPos()); float distance = util::distanceBetweenPoints(this->lastPressPosition, event->screenPos());

View file

@ -86,7 +86,10 @@ private:
bool updateQueued = false; bool updateQueued = false;
bool messageWasAdded = false; bool messageWasAdded = false;
bool lastMessageHasAlternateBackground = false; bool lastMessageHasAlternateBackground = false;
bool paused = false; bool pausedTemporarily = false;
bool pausedBySelection = false;
bool scrollToBottomAfterTemporaryPause = false;
int messagesAddedSinceSelectionPause = 0;
QTimer pauseTimeout; QTimer pauseTimeout;
boost::optional<messages::MessageElement::Flags> overrideFlags; boost::optional<messages::MessageElement::Flags> overrideFlags;
messages::MessageLayoutPtr lastReadMessage; messages::MessageLayoutPtr lastReadMessage;
@ -99,6 +102,10 @@ private:
void drawMessages(QPainter &painter); void drawMessages(QPainter &painter);
void setSelection(const messages::SelectionItem &start, const messages::SelectionItem &end); void setSelection(const messages::SelectionItem &start, const messages::SelectionItem &end);
messages::MessageElement::Flags getFlags() const; messages::MessageElement::Flags getFlags() const;
bool isPaused();
void beginPause();
void endPause();
ChannelPtr channel; ChannelPtr channel;

View file

@ -253,7 +253,7 @@ void SplitHeader::mouseReleaseEvent(QMouseEvent *event)
TooltipWidget *widget = new TooltipWidget(); TooltipWidget *widget = new TooltipWidget();
widget->setText("Double click or press <ctrl+r> to change the channel.\nClick and " widget->setText("Double click or press <Ctrl+R> to change the channel.\nClick and "
"drag to move the split."); "drag to move the split.");
widget->setAttribute(Qt::WA_DeleteOnClose); widget->setAttribute(Qt::WA_DeleteOnClose);
widget->move(pos); widget->move(pos);

View file

@ -86,7 +86,7 @@ SplitOverlay::SplitOverlay(Split *parent)
void SplitOverlay::paintEvent(QPaintEvent *event) void SplitOverlay::paintEvent(QPaintEvent *event)
{ {
QPainter painter(this); QPainter painter(this);
painter.fillRect(this->rect(), QColor(0, 0, 0, 90)); painter.fillRect(this->rect(), QColor(0, 0, 0, 150));
QRect rect; QRect rect;
switch (this->hoveredElement) { switch (this->hoveredElement) {

View file

@ -109,14 +109,14 @@ void Scrollbar::setDesiredValue(qreal value, bool animated)
// } // }
this->currentValueAnimation.setEndValue(value); this->currentValueAnimation.setEndValue(value);
this->smoothScrollingOffset = 0; this->smoothScrollingOffset = 0;
this->atBottom = ((this->getMaximum() - this->getLargeChange()) - value) <= 0.01; this->atBottom = ((this->getMaximum() - this->getLargeChange()) - value) <= 0.0001;
this->currentValueAnimation.start(); this->currentValueAnimation.start();
} else { } else {
if (this->currentValueAnimation.state() != QPropertyAnimation::Running) { if (this->currentValueAnimation.state() != QPropertyAnimation::Running) {
this->smoothScrollingOffset = 0; this->smoothScrollingOffset = 0;
this->desiredValue = value; this->desiredValue = value;
this->currentValueAnimation.stop(); this->currentValueAnimation.stop();
this->atBottom = ((this->getMaximum() - this->getLargeChange()) - value) <= 0.01; this->atBottom = ((this->getMaximum() - this->getLargeChange()) - value) <= 0.0001;
setCurrentValue(value); setCurrentValue(value);
} }
} }