mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
fixed selections moving when new messages come in while selecting
This commit is contained in:
parent
8ee0f85a2b
commit
d24e1f8314
7 changed files with 112 additions and 32 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue