From 700c756f5acd93eec4f3f6224a9c5ed63fb7f7df Mon Sep 17 00:00:00 2001 From: fourtf Date: Thu, 26 Jan 2017 04:26:40 +0100 Subject: [PATCH] added scrollbar and smooth scrolling --- channel.cpp | 4 ++ channel.h | 6 ++ channel.h.zT7500 | 129 +++++++++++++++++++++++++++++++++++++ colorscheme.cpp | 2 + settings.cpp | 1 + settings.h | 1 + widgets/chatwidget.cpp | 3 + widgets/chatwidgetview.cpp | 33 ++++++++-- widgets/chatwidgetview.h | 7 ++ widgets/scrollbar.cpp | 103 +++++++++++++++++++++++++++++ widgets/scrollbar.h | 44 ++++++++++++- windows.cpp | 10 ++- 12 files changed, 333 insertions(+), 10 deletions(-) create mode 100644 channel.h.zT7500 diff --git a/channel.cpp b/channel.cpp index cc0dec183..c80687129 100644 --- a/channel.cpp +++ b/channel.cpp @@ -18,6 +18,10 @@ Channel::Channel(const QString &channel) , channelLink("https://twitch.tv/" + name) , popoutPlayerLink("https://player.twitch.tv/?channel=" + name) { + for (int i = 0; i < 40; i++) { + addMessage(std::shared_ptr( + new messages::Message("test xD test"))); + } } QVector> diff --git a/channel.h b/channel.h index 832d55f17..1f59031ed 100644 --- a/channel.h +++ b/channel.h @@ -93,6 +93,12 @@ public: QVector> getMessagesClone(); + QVector> & + getMessages() + { + return messages; + } + private: QVector> messages; diff --git a/channel.h.zT7500 b/channel.h.zT7500 new file mode 100644 index 000000000..8760581af --- /dev/null +++ b/channel.h.zT7500 @@ -0,0 +1,129 @@ +#ifndef CHANNEL_H +#define CHANNEL_H + +#include "concurrentmap.h" +#include "messages/lazyloadedimage.h" + +#include +#include +#include +#include +#include + +namespace chatterino { +namespace messages { +class Message; +} + +class Channel +{ +public: + Channel(const QString &channel); + + // properties + const ConcurrentMap & + getBttvChannelEmotes() const + { + return bttvChannelEmotes; + } + + const ConcurrentMap & + getFfzChannelEmotes() const + { + return ffzChannelEmotes; + } + + const QMutex & + getMessageMutex() const + { + return messageMutex; + } + + const QString & + getName() const + { + return name; + } + + int + getRoomID() const + { + return roomID; + } + + const QString & + getSubLink() const + { + return subLink; + } + const QString & + getChannelLink() const + { + return channelLink; + } + const QString & + getPopoutPlayerLink() const + { + return popoutPlayerLink; + } + + bool + getIsLive() const + { + return isLive; + } + int + getStreamViewerCount() const + { + return streamViewerCount; + } + const QString & + getStreamStatus() const + { + return streamStatus; + } + const QString & + getStreamGame() const + { + return streamGame; + } + + // methods + void addMessage(std::shared_ptr message); + + QVector> getMessagesClone(); + + QVector> & + getMessages() const + { + return messages; + } + + QMutex & + getMessageMutes() const + { + return messageMutex; + } + +private: + QVector> messages; + + QString name; + int roomID; + + ConcurrentMap bttvChannelEmotes; + ConcurrentMap ffzChannelEmotes; + QMutex messageMutex; + + QString subLink; + QString channelLink; + QString popoutPlayerLink; + + bool isLive; + int streamViewerCount; + QString streamStatus; + QString streamGame; +}; +} + +#endif // CHANNEL_H diff --git a/colorscheme.cpp b/colorscheme.cpp index a3b4d3449..c7ca32d09 100644 --- a/colorscheme.cpp +++ b/colorscheme.cpp @@ -46,6 +46,8 @@ ColorScheme::setColors(float hue, float multiplyer) ChatInputBackground = getColor(0, 0.1, 0.95); ChatInputBorder = getColor(0, 0.1, 0.9); + ScrollbarBG = ChatBackground; + // generate color lookuptable fillLookupTableValues(this->middleLookupTable, 0.000, 0.166, 0.66, 0.5); fillLookupTableValues(this->middleLookupTable, 0.166, 0.333, 0.5, 0.55); diff --git a/settings.cpp b/settings.cpp index b8fcc5daf..2c9541ca5 100644 --- a/settings.cpp +++ b/settings.cpp @@ -18,6 +18,7 @@ Settings::Settings() , theme(this->settingsItems, "theme", "dark") , selectedUser(this->settingsItems, "selectedUser", "") , emoteScale(this->settingsItems, "emoteScale", 1.0) + , mouseScrollMultiplier(this->settingsItems, "mouseScrollMultiplier", 1.0) , scaleEmotesByLineHeight(this->settingsItems, "scaleEmotesByLineHeight", false) , showTimestamps(this->settingsItems, "showTimestamps", true) diff --git a/settings.h b/settings.h index 18d08f772..9085046dc 100644 --- a/settings.h +++ b/settings.h @@ -82,6 +82,7 @@ public: Setting theme; Setting selectedUser; Setting emoteScale; + Setting mouseScrollMultiplier; Setting scaleEmotesByLineHeight; Setting showTimestamps; Setting showTimestampSeconds; diff --git a/widgets/chatwidget.cpp b/widgets/chatwidget.cpp index 89adcb9d6..81b077830 100644 --- a/widgets/chatwidget.cpp +++ b/widgets/chatwidget.cpp @@ -59,6 +59,9 @@ ChatWidget::setChannelName(const QString &name) } else { this->channel = Channels::addChannel(channel); } + + this->view.layoutMessages(); + this->view.repaint(); } void diff --git a/widgets/chatwidgetview.cpp b/widgets/chatwidgetview.cpp index 7d074964c..8cf3dd2f5 100644 --- a/widgets/chatwidgetview.cpp +++ b/widgets/chatwidgetview.cpp @@ -8,7 +8,6 @@ #include #include -#include #include namespace chatterino { @@ -19,12 +18,12 @@ ChatWidgetView::ChatWidgetView(ChatWidget *parent) , chatWidget(parent) , scrollbar(this) { - auto scroll = QScroller::scroller(this); - - scroll->scrollTo(QPointF(0, 100)); + this->scrollbar.setSmallChange(2); QObject::connect(&Settings::getInstance(), &Settings::wordTypeMaskChanged, this, &ChatWidgetView::wordTypeMaskChanged); + + this->scrollbar.getValueChanged().connect([this] { repaint(); }); } ChatWidgetView::~ChatWidgetView() @@ -50,9 +49,25 @@ ChatWidgetView::layoutMessages() redraw |= message.get()->layout(this->width(), true); } + updateScrollbar(); + return redraw; } +void +ChatWidgetView::updateScrollbar() +{ + auto c = this->chatWidget->getChannel(); + + if (c == NULL) { + return; + } + + // this->scrollbar.setValue(0); + this->scrollbar.setLargeChange(10); + this->scrollbar.setMaximum(c->getMessages().size()); +} + void ChatWidgetView::resizeEvent(QResizeEvent *) { @@ -163,5 +178,15 @@ ChatWidgetView::paintEvent(QPaintEvent *) } } } + +void +ChatWidgetView::wheelEvent(QWheelEvent *event) +{ + this->scrollbar.setValue( + this->scrollbar.getValue() - + event->delta() / 10.0 * + Settings::getInstance().mouseScrollMultiplier.get(), + true); +} } } diff --git a/widgets/chatwidgetview.h b/widgets/chatwidgetview.h index 1585436cf..e4a744590 100644 --- a/widgets/chatwidgetview.h +++ b/widgets/chatwidgetview.h @@ -6,6 +6,8 @@ #include "widgets/scrollbar.h" #include +#include +#include #include namespace chatterino { @@ -22,10 +24,15 @@ public: bool layoutMessages(); + void updateScrollbar(); + protected: void resizeEvent(QResizeEvent *); void paintEvent(QPaintEvent *); + void wheelEvent(QWheelEvent *event); + + void scroll(int dx, int dy); private: ChatWidget *chatWidget; diff --git a/widgets/scrollbar.cpp b/widgets/scrollbar.cpp index da4b78a82..da749f65b 100644 --- a/widgets/scrollbar.cpp +++ b/widgets/scrollbar.cpp @@ -1,6 +1,7 @@ #include "widgets/scrollbar.h" #include "colorscheme.h" +#include #include #define MIN_THUMB_HEIGHT 10 @@ -11,15 +12,27 @@ namespace widgets { ScrollBar::ScrollBar(QWidget *widget) : QWidget(widget) , mutex() + , valueAnimation(this, "value") , highlights(NULL) + , mouseOverIndex(-1) + , mouseDownIndex(-1) + , lastMousePosition() + , buttonHeight(16) + , trackHeight(100) , thumbRect() , maximum() , minimum() , largeChange() , smallChange() , value() + , valueChanged() { resize(16, 100); + + valueAnimation.setDuration(300); + valueAnimation.setEasingCurve(QEasingCurve(QEasingCurve::OutCubic)); + + this->setMouseTracking(true); } ScrollBar::~ScrollBar() @@ -88,6 +101,8 @@ ScrollBar::paintEvent(QPaintEvent *) QRect(0, height() - this->buttonHeight, width(), this->buttonHeight), QColor(255, 0, 0)); + painter.fillRect(this->thumbRect, QColor(0, 255, 255)); + ScrollBarHighlight *highlight = this->highlights; this->mutex.lock(); @@ -99,6 +114,94 @@ ScrollBar::paintEvent(QPaintEvent *) this->mutex.unlock(); } +void +ScrollBar::mouseMoveEvent(QMouseEvent *event) +{ + if (this->mouseDownIndex == -1) { + int y = event->pos().y(); + + auto oldIndex = this->mouseOverIndex; + + if (y < this->buttonHeight) { + this->mouseOverIndex = 0; + } else if (y < this->thumbRect.y()) { + this->mouseOverIndex = 1; + } else if (this->thumbRect.contains(2, y)) { + this->mouseOverIndex = 2; + } else if (y < height() - this->buttonHeight) { + this->mouseOverIndex = 3; + } else { + this->mouseOverIndex = 4; + } + + if (oldIndex != this->mouseOverIndex) { + this->repaint(); + } + } else if (this->mouseDownIndex == 2) { + int delta = event->pos().y() - lastMousePosition.y(); + + this->setValue(this->value + + (qreal)delta / this->trackHeight * maximum); + } + + this->lastMousePosition = event->pos(); +} + +void +ScrollBar::mousePressEvent(QMouseEvent *event) +{ + int y = event->pos().y(); + + if (y < this->buttonHeight) { + this->mouseDownIndex = 0; + } else if (y < this->thumbRect.y()) { + this->mouseDownIndex = 1; + } else if (this->thumbRect.contains(2, y)) { + this->mouseDownIndex = 2; + } else if (y < height() - this->buttonHeight) { + this->mouseDownIndex = 3; + } else { + this->mouseDownIndex = 4; + } +} + +void +ScrollBar::mouseReleaseEvent(QMouseEvent *event) +{ + int y = event->pos().y(); + + if (y < this->buttonHeight) { + if (this->mouseDownIndex == 0) { + this->setValue(this->value - this->smallChange); + } + } else if (y < this->thumbRect.y()) { + if (this->mouseDownIndex == 0) { + this->setValue(this->value - this->smallChange); + } + } else if (this->thumbRect.contains(2, y)) { + // do nothing + } else if (y < height() - this->buttonHeight) { + if (this->mouseDownIndex == 0) { + this->setValue(this->value + this->smallChange); + } + } else { + if (this->mouseDownIndex == 0) { + this->setValue(this->value + this->smallChange); + } + } + + this->mouseDownIndex = -1; + repaint(); +} + +void +ScrollBar::leaveEvent(QEvent *) +{ + this->mouseOverIndex = -1; + + repaint(); +} + void ScrollBar::updateScroll() { diff --git a/widgets/scrollbar.h b/widgets/scrollbar.h index 93f025c04..3e23df8c9 100644 --- a/widgets/scrollbar.h +++ b/widgets/scrollbar.h @@ -4,7 +4,9 @@ #include "widgets/scrollbarhighlight.h" #include +#include #include +#include #include namespace chatterino { @@ -21,6 +23,8 @@ public: void removeHighlightsWhere(std::function func); void addHighlight(ScrollBarHighlight *highlight); + Q_PROPERTY(qreal value READ getValue WRITE setValue) + void setMaximum(qreal value) { @@ -54,11 +58,26 @@ public: } void - setValue(qreal value) + setValue(qreal value, bool animated = false) { - this->value = value; + value = std::max(this->minimum, + std::min(this->maximum - this->largeChange, value)); - this->updateScroll(); + if (this->value != value) { + if (animated) { + this->valueAnimation.stop(); + this->valueAnimation.setStartValue(this->value); + this->valueAnimation.setEndValue(value); + this->valueAnimation.start(); + } else { + this->value = value; + } + + this->updateScroll(); + this->valueChanged(); + + this->repaint(); + } } qreal @@ -91,10 +110,27 @@ public: return this->value; } + boost::signals2::signal & + getValueChanged() + { + return valueChanged; + } + private: QMutex mutex; ScrollBarHighlight *highlights; + + QPropertyAnimation valueAnimation; + void paintEvent(QPaintEvent *); + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void leaveEvent(QEvent *); + + int mouseOverIndex; + int mouseDownIndex; + QPoint lastMousePosition; int buttonHeight; int trackHeight; @@ -107,6 +143,8 @@ private: qreal smallChange; qreal value; + boost::signals2::signal valueChanged; + void updateScroll(); }; } diff --git a/windows.cpp b/windows.cpp index 063d9ca76..d81fd0a5c 100644 --- a/windows.cpp +++ b/windows.cpp @@ -4,17 +4,21 @@ namespace chatterino { QMutex Windows::windowMutex; -widgets::MainWindow *Windows::mainWindow(NULL); +widgets::MainWindow *Windows::mainWindow(nullptr); void Windows::layoutVisibleChatWidgets(Channel *channel) { - Windows::mainWindow->layoutVisibleChatWidgets(channel); + if (Windows::mainWindow != nullptr) { + Windows::mainWindow->layoutVisibleChatWidgets(channel); + } } void Windows::repaintVisibleChatWidgets(Channel *channel) { - Windows::mainWindow->repaintVisibleChatWidgets(channel); + if (Windows::mainWindow != nullptr) { + Windows::mainWindow->repaintVisibleChatWidgets(channel); + } } }