added highlights to the scrollbar

This commit is contained in:
fourtf 2018-01-06 03:48:56 +01:00
parent 99f2d0dd27
commit 20eab57db5
10 changed files with 159 additions and 134 deletions

View file

@ -132,7 +132,7 @@ public:
return acceptedItems; return acceptedItems;
} }
// replaces a single item, return true if successful // replace an single item, return index if successful, -1 if unsuccessful
int replaceItem(const T &item, const T &replacement) int replaceItem(const T &item, const T &replacement)
{ {
std::lock_guard<std::mutex> lock(this->mutex); std::lock_guard<std::mutex> lock(this->mutex);
@ -166,6 +166,38 @@ public:
return -1; return -1;
} }
// replace an item at index, return true if worked
bool replaceItem(size_t index, const T &replacement)
{
std::lock_guard<std::mutex> lock(this->mutex);
int x = 0;
for (size_t i = 0; i < this->chunks->size(); i++) {
Chunk &chunk = this->chunks->at(i);
size_t start = i == 0 ? this->firstChunkOffset : 0;
size_t end = i == chunk->size() - 1 ? this->lastChunkEnd : chunk->size();
for (size_t j = start; j < end; j++) {
if (x == index) {
Chunk newChunk = std::make_shared<std::vector<T>>();
newChunk->resize(chunk->size());
for (size_t k = 0; k < chunk->size(); k++) {
newChunk->at(k) = chunk->at(k);
}
newChunk->at(j) = replacement;
this->chunks->at(i) = newChunk;
return x;
}
x++;
}
}
}
// void insertAfter(const std::vector<T> &items, const T &index) // void insertAfter(const std::vector<T> &items, const T &index)
messages::LimitedQueueSnapshot<T> getSnapshot() messages::LimitedQueueSnapshot<T> getSnapshot()

View file

@ -13,6 +13,8 @@
#include <list> #include <list>
#include <tuple> #include <tuple>
typedef chatterino::widgets::ScrollbarHighlight SBHighlight;
namespace chatterino { namespace chatterino {
namespace messages { namespace messages {
@ -128,6 +130,14 @@ void Message::updateContent() const
this->content = _content; this->content = _content;
} }
SBHighlight Message::getScrollBarHighlight() const
{
if (this->getFlags() & Message::Highlighted) {
return SBHighlight(SBHighlight::Highlight);
}
return SBHighlight();
}
namespace { namespace {
void AddCurrentTimestamp(Message *message) void AddCurrentTimestamp(Message *message)

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "messages/word.hpp" #include "messages/word.hpp"
#include "widgets/helper/scrollbarhighlight.hpp"
#include <chrono> #include <chrono>
#include <memory> #include <memory>
@ -23,6 +24,7 @@ public:
None = 0, None = 0,
System = (1 << 1), System = (1 << 1),
Timeout = (1 << 2), Timeout = (1 << 2),
Highlighted = (1 << 3),
}; };
bool containsHighlightedPhrase() const; bool containsHighlightedPhrase() const;
@ -44,6 +46,7 @@ public:
bool getDisableCompactEmotes() const; bool getDisableCompactEmotes() const;
void setDisableCompactEmotes(bool value); void setDisableCompactEmotes(bool value);
void updateContent() const; void updateContent() const;
widgets::ScrollbarHighlight getScrollBarHighlight() const;
QString loginName; QString loginName;
QString displayName; QString displayName;

View file

@ -460,6 +460,10 @@ void TwitchMessageBuilder::parseHighlights()
QApplication::alert(singletons::WindowManager::getInstance().getMainWindow().window(), QApplication::alert(singletons::WindowManager::getInstance().getMainWindow().window(),
2500); 2500);
} }
if (doHighlight) {
this->message->addFlags(Message::Highlighted);
}
} }
} }

View file

@ -233,7 +233,7 @@ void ChannelView::updateGifEmotes()
} }
} }
ScrollBar &ChannelView::getScrollBar() Scrollbar &ChannelView::getScrollBar()
{ {
return this->scrollBar; return this->scrollBar;
} }
@ -395,6 +395,8 @@ void ChannelView::setChannel(std::shared_ptr<Channel> newChannel)
this->highlightedMessageReceived.invoke(); this->highlightedMessageReceived.invoke();
} }
this->scrollBar.addHighlight(message->getScrollBarHighlight());
this->messageWasAdded = true; this->messageWasAdded = true;
this->layoutMessages(); this->layoutMessages();
}); });
@ -416,6 +418,14 @@ void ChannelView::setChannel(std::shared_ptr<Channel> newChannel)
} }
} }
std::vector<ScrollbarHighlight> highlights;
highlights.reserve(messages.size());
for (int i = 0; i < messages.size(); i++) {
highlights.push_back(messages.at(i)->getScrollBarHighlight());
}
this->scrollBar.addHighlightsAtStart(highlights);
this->messageWasAdded = true; this->messageWasAdded = true;
this->layoutMessages(); this->layoutMessages();
}); });
@ -436,6 +446,8 @@ void ChannelView::setChannel(std::shared_ptr<Channel> newChannel)
newChannel->messageReplaced.connect([this](size_t index, SharedMessage replacement) { newChannel->messageReplaced.connect([this](size_t index, SharedMessage replacement) {
SharedMessageRef newItem(new MessageRef(replacement)); SharedMessageRef newItem(new MessageRef(replacement));
this->scrollBar.replaceHighlight(index, replacement->getScrollBarHighlight());
this->messages.replaceItem(this->messages.getSnapshot()[index], newItem); this->messages.replaceItem(this->messages.getSnapshot()[index], newItem);
this->layoutMessages(); this->layoutMessages();
}); });

View file

@ -33,7 +33,7 @@ public:
void updateGifEmotes(); void updateGifEmotes();
void queueUpdate(); void queueUpdate();
ScrollBar &getScrollBar(); Scrollbar &getScrollBar();
QString getSelectedText(); QString getSelectedText();
bool hasSelection(); bool hasSelection();
void clearSelection(); void clearSelection();
@ -94,7 +94,7 @@ private:
std::vector<GifEmoteData> gifEmotes; std::vector<GifEmoteData> gifEmotes;
ScrollBar scrollBar; Scrollbar scrollBar;
RippleEffectLabel *goToBottom; RippleEffectLabel *goToBottom;
// This variable can be used to decide whether or not we should render the "Show latest // This variable can be used to decide whether or not we should render the "Show latest

View file

@ -5,16 +5,32 @@
namespace chatterino { namespace chatterino {
namespace widgets { namespace widgets {
ScrollBarHighlight::ScrollBarHighlight(double _position, int _colorIndex, ScrollBar *parent, ScrollbarHighlight::ScrollbarHighlight()
Style _style, QString _tag) : color(Color::Highlight)
: themeManager(parent->themeManager) , style(Style::None)
, position(_position)
// , colorIndex(std::max(0, std::min(this->themeManager.HighlightColorCount, _colorIndex)))
, colorIndex(0)
, style(_style)
, tag(_tag)
{ {
} }
ScrollbarHighlight::ScrollbarHighlight(Color _color, Style _style)
: color(_color)
, style(_style)
{
}
ScrollbarHighlight::Color ScrollbarHighlight::getColor() const
{
return this->color;
}
ScrollbarHighlight::Style ScrollbarHighlight::getStyle() const
{
return this->style;
}
bool ScrollbarHighlight::isNull() const
{
return this->style == None;
}
} // namespace widgets } // namespace widgets
} // namespace chatterino } // namespace chatterino

View file

@ -3,51 +3,23 @@
#include "QString" #include "QString"
namespace chatterino { namespace chatterino {
namespace singletons {
class ThemeManager;
}
namespace widgets { namespace widgets {
class ScrollbarHighlight
class ScrollBar;
class ScrollBarHighlight
{ {
public: public:
enum Style { Default, Left, Right, SingleLine }; enum Style : char { None, Default, Line };
enum Color : char { Highlight };
ScrollBarHighlight(double _position, int _colorIndex, ScrollBar *parent, Style _style = Default, ScrollbarHighlight();
QString _tag = ""); ScrollbarHighlight(Color _color, Style _style = Default);
singletons::ThemeManager &themeManager; Color getColor() const;
Style getStyle() const;
double getPosition() bool isNull() const;
{
return this->position;
}
int getColorIndex()
{
return this->colorIndex;
}
Style getStyle()
{
return this->style;
}
QString getTag()
{
return this->tag;
}
ScrollBarHighlight *next = nullptr;
private: private:
double position; Color color;
int colorIndex;
Style style; Style style;
QString tag;
}; };
} // namespace widgets } // namespace widgets

View file

@ -13,10 +13,9 @@
namespace chatterino { namespace chatterino {
namespace widgets { namespace widgets {
ScrollBar::ScrollBar(ChannelView *parent) Scrollbar::Scrollbar(ChannelView *parent)
: BaseWidget(parent) : BaseWidget(parent)
, currentValueAnimation(this, "currentValue") , currentValueAnimation(this, "currentValue")
, highlights(nullptr)
, smoothScrollingSetting(singletons::SettingManager::getInstance().enableSmoothScrolling) , smoothScrollingSetting(singletons::SettingManager::getInstance().enableSmoothScrolling)
{ {
resize((int)(16 * this->getDpiMultiplier()), 100); resize((int)(16 * this->getDpiMultiplier()), 100);
@ -37,97 +36,61 @@ ScrollBar::ScrollBar(ChannelView *parent)
timer->start(10); timer->start(10);
} }
ScrollBar::~ScrollBar() void Scrollbar::addHighlight(ScrollbarHighlight highlight)
{ {
auto highlight = this->highlights; ScrollbarHighlight deleted;
this->highlights.pushBack(highlight, deleted);
while (highlight != nullptr) {
auto tmp = highlight->next;
delete highlight;
highlight = tmp;
}
} }
void ScrollBar::removeHighlightsWhere(std::function<bool(ScrollBarHighlight &)> func) void Scrollbar::addHighlightsAtStart(const std::vector<ScrollbarHighlight> &_highlights)
{ {
this->mutex.lock(); this->highlights.pushFront(_highlights);
ScrollBarHighlight *last = nullptr;
ScrollBarHighlight *current = this->highlights;
while (current != nullptr) {
if (func(*current)) {
if (last == nullptr) {
this->highlights = current->next;
} else {
last->next = current->next;
}
auto oldCurrent = current;
current = current->next;
last = current;
delete oldCurrent;
}
}
this->mutex.unlock();
} }
void ScrollBar::addHighlight(ScrollBarHighlight *highlight) void Scrollbar::replaceHighlight(size_t index, ScrollbarHighlight replacement)
{ {
this->mutex.lock(); this->highlights.replaceItem(index, replacement);
if (this->highlights == nullptr) {
this->highlights = highlight;
} else {
highlight->next = this->highlights->next;
this->highlights->next = highlight;
}
this->mutex.unlock();
} }
void ScrollBar::scrollToBottom(bool animate) void Scrollbar::scrollToBottom(bool animate)
{ {
this->setDesiredValue(this->maximum - this->getLargeChange(), animate); this->setDesiredValue(this->maximum - this->getLargeChange(), animate);
} }
bool ScrollBar::isAtBottom() const bool Scrollbar::isAtBottom() const
{ {
return this->atBottom; return this->atBottom;
} }
void ScrollBar::setMaximum(qreal value) void Scrollbar::setMaximum(qreal value)
{ {
this->maximum = value; this->maximum = value;
updateScroll(); updateScroll();
} }
void ScrollBar::setMinimum(qreal value) void Scrollbar::setMinimum(qreal value)
{ {
this->minimum = value; this->minimum = value;
updateScroll(); updateScroll();
} }
void ScrollBar::setLargeChange(qreal value) void Scrollbar::setLargeChange(qreal value)
{ {
this->largeChange = value; this->largeChange = value;
updateScroll(); updateScroll();
} }
void ScrollBar::setSmallChange(qreal value) void Scrollbar::setSmallChange(qreal value)
{ {
this->smallChange = value; this->smallChange = value;
updateScroll(); updateScroll();
} }
void ScrollBar::setDesiredValue(qreal value, bool animated) void Scrollbar::setDesiredValue(qreal value, bool animated)
{ {
animated &= this->smoothScrollingSetting.getValue(); animated &= this->smoothScrollingSetting.getValue();
value = std::max(this->minimum, std::min(this->maximum - this->largeChange, value)); value = std::max(this->minimum, std::min(this->maximum - this->largeChange, value));
@ -160,37 +123,37 @@ void ScrollBar::setDesiredValue(qreal value, bool animated)
this->desiredValue = value; this->desiredValue = value;
} }
qreal ScrollBar::getMaximum() const qreal Scrollbar::getMaximum() const
{ {
return this->maximum; return this->maximum;
} }
qreal ScrollBar::getMinimum() const qreal Scrollbar::getMinimum() const
{ {
return this->minimum; return this->minimum;
} }
qreal ScrollBar::getLargeChange() const qreal Scrollbar::getLargeChange() const
{ {
return this->largeChange; return this->largeChange;
} }
qreal ScrollBar::getSmallChange() const qreal Scrollbar::getSmallChange() const
{ {
return this->smallChange; return this->smallChange;
} }
qreal ScrollBar::getDesiredValue() const qreal Scrollbar::getDesiredValue() const
{ {
return this->desiredValue + this->smoothScrollingOffset; return this->desiredValue + this->smoothScrollingOffset;
} }
qreal ScrollBar::getCurrentValue() const qreal Scrollbar::getCurrentValue() const
{ {
return this->currentValue; return this->currentValue;
} }
void ScrollBar::offset(qreal value) void Scrollbar::offset(qreal value)
{ {
if (this->currentValueAnimation.state() == QPropertyAnimation::Running) { if (this->currentValueAnimation.state() == QPropertyAnimation::Running) {
this->smoothScrollingOffset += value; this->smoothScrollingOffset += value;
@ -199,12 +162,12 @@ void ScrollBar::offset(qreal value)
} }
} }
boost::signals2::signal<void()> &ScrollBar::getCurrentValueChanged() boost::signals2::signal<void()> &Scrollbar::getCurrentValueChanged()
{ {
return this->currentValueChanged; return this->currentValueChanged;
} }
void ScrollBar::setCurrentValue(qreal value) void Scrollbar::setCurrentValue(qreal value)
{ {
value = std::max(this->minimum, std::min(this->maximum - this->largeChange, value = std::max(this->minimum, std::min(this->maximum - this->largeChange,
value + this->smoothScrollingOffset)); value + this->smoothScrollingOffset));
@ -219,7 +182,7 @@ void ScrollBar::setCurrentValue(qreal value)
} }
} }
void ScrollBar::printCurrentState(const QString &prefix) const void Scrollbar::printCurrentState(const QString &prefix) const
{ {
qDebug() << prefix // qDebug() << prefix //
<< "Current value: " << this->getCurrentValue() // << "Current value: " << this->getCurrentValue() //
@ -228,7 +191,7 @@ void ScrollBar::printCurrentState(const QString &prefix) const
<< ". Large change: " << this->getLargeChange(); // << ". Large change: " << this->getLargeChange(); //
} }
void ScrollBar::paintEvent(QPaintEvent *) void Scrollbar::paintEvent(QPaintEvent *)
{ {
bool mouseOver = this->mouseOverIndex != -1; bool mouseOver = this->mouseOverIndex != -1;
int xOffset = mouseOver ? 0 : width() - (int)(4 * this->getDpiMultiplier()); int xOffset = mouseOver ? 0 : width() - (int)(4 * this->getDpiMultiplier());
@ -253,23 +216,37 @@ void ScrollBar::paintEvent(QPaintEvent *)
painter.fillRect(this->thumbRect, this->themeManager.scrollbars.thumb); painter.fillRect(this->thumbRect, this->themeManager.scrollbars.thumb);
} }
// ScrollBarHighlight *highlight = highlights; // draw highlights
auto snapshot = this->highlights.getSnapshot();
int snapshotLength = snapshot.getLength();
int w = this->width();
float y = 0;
float dY = (this->height() - MIN_THUMB_HEIGHT) / snapshotLength;
int highlightHeight = std::ceilf(dY);
this->mutex.lock(); for (int i = 0; i < snapshotLength; i++) {
ScrollbarHighlight const &highlight = snapshot[i];
// do { if (!highlight.isNull()) {
// painter.fillRect(); if (highlight.getStyle() == ScrollbarHighlight::Default) {
// } while ((highlight = highlight->next()) != nullptr); painter.fillRect(w / 8 * 3, (int)y, w / 4, highlightHeight,
this->themeManager.tabs.selected.backgrounds.regular.color());
} else {
painter.fillRect(0, (int)y, w, 1,
this->themeManager.tabs.selected.backgrounds.regular.color());
}
}
this->mutex.unlock(); y += dY;
}
} }
void ScrollBar::resizeEvent(QResizeEvent *) void Scrollbar::resizeEvent(QResizeEvent *)
{ {
this->resize((int)(16 * this->getDpiMultiplier()), this->height()); this->resize((int)(16 * this->getDpiMultiplier()), this->height());
} }
void ScrollBar::mouseMoveEvent(QMouseEvent *event) void Scrollbar::mouseMoveEvent(QMouseEvent *event)
{ {
if (this->mouseDownIndex == -1) { if (this->mouseDownIndex == -1) {
int y = event->pos().y(); int y = event->pos().y();
@ -300,7 +277,7 @@ void ScrollBar::mouseMoveEvent(QMouseEvent *event)
this->lastMousePosition = event->pos(); this->lastMousePosition = event->pos();
} }
void ScrollBar::mousePressEvent(QMouseEvent *event) void Scrollbar::mousePressEvent(QMouseEvent *event)
{ {
int y = event->pos().y(); int y = event->pos().y();
@ -317,7 +294,7 @@ void ScrollBar::mousePressEvent(QMouseEvent *event)
} }
} }
void ScrollBar::mouseReleaseEvent(QMouseEvent *event) void Scrollbar::mouseReleaseEvent(QMouseEvent *event)
{ {
int y = event->pos().y(); int y = event->pos().y();
@ -345,14 +322,14 @@ void ScrollBar::mouseReleaseEvent(QMouseEvent *event)
update(); update();
} }
void ScrollBar::leaveEvent(QEvent *) void Scrollbar::leaveEvent(QEvent *)
{ {
this->mouseOverIndex = -1; this->mouseOverIndex = -1;
update(); update();
} }
void ScrollBar::updateScroll() void Scrollbar::updateScroll()
{ {
this->trackHeight = height() - this->buttonHeight - this->buttonHeight - MIN_THUMB_HEIGHT - 1; this->trackHeight = height() - this->buttonHeight - this->buttonHeight - MIN_THUMB_HEIGHT - 1;

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "messages/limitedqueue.hpp"
#include "singletons/settingsmanager.hpp" #include "singletons/settingsmanager.hpp"
#include "widgets/basewidget.hpp" #include "widgets/basewidget.hpp"
#include "widgets/helper/scrollbarhighlight.hpp" #include "widgets/helper/scrollbarhighlight.hpp"
@ -15,21 +16,18 @@ namespace widgets {
class ChannelView; class ChannelView;
class ScrollBar : public BaseWidget class Scrollbar : public BaseWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
ScrollBar(ChannelView *parent = 0); Scrollbar(ChannelView *parent = 0);
~ScrollBar();
void removeHighlightsWhere(std::function<bool(ScrollBarHighlight &)> func); void addHighlight(ScrollbarHighlight highlight);
void addHighlight(ScrollBarHighlight *highlight); void addHighlightsAtStart(const std::vector<ScrollbarHighlight> &highlights);
void replaceHighlight(size_t index, ScrollbarHighlight replacement);
Q_PROPERTY(qreal desiredValue READ getDesiredValue WRITE setDesiredValue)
void scrollToBottom(bool animate = false); void scrollToBottom(bool animate = false);
bool isAtBottom() const; bool isAtBottom() const;
void setMaximum(qreal value); void setMaximum(qreal value);
@ -50,6 +48,8 @@ public:
void printCurrentState(const QString &prefix = QString()) const; void printCurrentState(const QString &prefix = QString()) const;
Q_PROPERTY(qreal desiredValue READ getDesiredValue WRITE setDesiredValue)
protected: protected:
void paintEvent(QPaintEvent *) override; void paintEvent(QPaintEvent *) override;
void resizeEvent(QResizeEvent *) override; void resizeEvent(QResizeEvent *) override;
@ -65,7 +65,7 @@ private:
QPropertyAnimation currentValueAnimation; QPropertyAnimation currentValueAnimation;
ScrollBarHighlight *highlights; messages::LimitedQueue<ScrollbarHighlight> highlights;
bool atBottom = false; bool atBottom = false;
@ -73,7 +73,6 @@ private:
int mouseDownIndex = -1; int mouseDownIndex = -1;
QPoint lastMousePosition; QPoint lastMousePosition;
// int buttonHeight = 16;
int buttonHeight = 0; int buttonHeight = 0;
int trackHeight = 100; int trackHeight = 100;