mirror-chatterino2/src/widgets/scrollbar.cpp

368 lines
9.5 KiB
C++
Raw Normal View History

2017-06-11 09:31:45 +02:00
#include "widgets/scrollbar.hpp"
2017-12-31 00:50:07 +01:00
#include "singletons/thememanager.hpp"
2017-11-12 17:21:50 +01:00
#include "widgets/helper/channelview.hpp"
2017-01-03 21:19:33 +01:00
2017-06-06 17:18:23 +02:00
#include <QDebug>
2017-01-26 04:26:40 +01:00
#include <QMouseEvent>
2017-01-18 04:52:47 +01:00
#include <QPainter>
#include <QTimer>
#include <cmath>
2017-01-18 04:52:47 +01:00
2017-01-18 04:33:30 +01:00
#define MIN_THUMB_HEIGHT 10
2017-04-14 17:52:22 +02:00
namespace chatterino {
namespace widgets {
2017-01-18 21:30:23 +01:00
ScrollBar::ScrollBar(ChannelView *parent)
: BaseWidget(parent)
2017-12-19 01:11:35 +01:00
, currentValueAnimation(this, "currentValue")
, highlights(nullptr)
2017-12-31 22:58:35 +01:00
, smoothScrollingSetting(singletons::SettingManager::getInstance().enableSmoothScrolling)
2017-04-12 17:46:44 +02:00
{
resize((int)(16 * this->getDpiMultiplier()), 100);
2018-01-05 23:32:06 +01:00
this->currentValueAnimation.setDuration(150);
2017-12-19 01:11:35 +01:00
this->currentValueAnimation.setEasingCurve(QEasingCurve(QEasingCurve::OutCubic));
2017-04-12 17:46:44 +02:00
setMouseTracking(true);
// don't do this at home kids
QTimer *timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=]() {
resize((int)(16 * this->getDpiMultiplier()), 100);
timer->deleteLater();
});
timer->start(10);
2017-01-03 21:19:33 +01:00
}
ScrollBar::~ScrollBar()
{
2017-12-19 01:11:35 +01:00
auto highlight = this->highlights;
2017-01-03 21:19:33 +01:00
while (highlight != nullptr) {
2017-01-03 21:19:33 +01:00
auto tmp = highlight->next;
delete highlight;
highlight = tmp;
}
}
2017-04-12 17:46:44 +02:00
void ScrollBar::removeHighlightsWhere(std::function<bool(ScrollBarHighlight &)> func)
2017-01-03 21:19:33 +01:00
{
2017-12-19 01:11:35 +01:00
this->mutex.lock();
2017-01-03 21:19:33 +01:00
ScrollBarHighlight *last = nullptr;
2017-12-19 01:11:35 +01:00
ScrollBarHighlight *current = this->highlights;
2017-01-03 21:19:33 +01:00
while (current != nullptr) {
2017-01-11 18:52:09 +01:00
if (func(*current)) {
if (last == nullptr) {
2017-12-19 01:11:35 +01:00
this->highlights = current->next;
2017-01-11 18:52:09 +01:00
} else {
2017-01-03 21:19:33 +01:00
last->next = current->next;
}
auto oldCurrent = current;
current = current->next;
last = current;
delete oldCurrent;
}
}
2017-12-19 01:11:35 +01:00
this->mutex.unlock();
2017-01-03 21:19:33 +01:00
}
2017-04-12 17:46:44 +02:00
void ScrollBar::addHighlight(ScrollBarHighlight *highlight)
2017-01-03 21:19:33 +01:00
{
2017-12-19 01:11:35 +01:00
this->mutex.lock();
2017-01-03 21:19:33 +01:00
2017-12-19 01:11:35 +01:00
if (this->highlights == nullptr) {
this->highlights = highlight;
2017-01-11 18:52:09 +01:00
} else {
2017-12-19 01:11:35 +01:00
highlight->next = this->highlights->next;
this->highlights->next = highlight;
2017-04-12 17:46:44 +02:00
}
2017-12-19 01:11:35 +01:00
this->mutex.unlock();
2017-04-12 17:46:44 +02:00
}
2018-01-05 03:14:46 +01:00
void ScrollBar::scrollToBottom(bool animate)
2017-06-06 17:18:23 +02:00
{
2018-01-05 03:14:46 +01:00
this->setDesiredValue(this->maximum - this->getLargeChange(), animate);
2017-06-06 17:18:23 +02:00
}
bool ScrollBar::isAtBottom() const
{
2017-12-18 22:13:46 +01:00
return this->atBottom;
2017-06-06 17:18:23 +02:00
}
2017-04-12 17:46:44 +02:00
void ScrollBar::setMaximum(qreal value)
{
2017-12-19 01:11:35 +01:00
this->maximum = value;
2017-04-12 17:46:44 +02:00
updateScroll();
}
void ScrollBar::setMinimum(qreal value)
{
2017-12-19 01:11:35 +01:00
this->minimum = value;
2017-04-12 17:46:44 +02:00
updateScroll();
}
void ScrollBar::setLargeChange(qreal value)
{
2017-12-19 01:11:35 +01:00
this->largeChange = value;
2017-04-12 17:46:44 +02:00
updateScroll();
}
void ScrollBar::setSmallChange(qreal value)
{
2017-12-19 01:11:35 +01:00
this->smallChange = value;
2017-04-12 17:46:44 +02:00
updateScroll();
}
void ScrollBar::setDesiredValue(qreal value, bool animated)
{
animated &= this->smoothScrollingSetting.getValue();
2017-12-19 01:11:35 +01:00
value = std::max(this->minimum, std::min(this->maximum - this->largeChange, value));
2017-04-12 17:46:44 +02:00
2017-12-19 01:11:35 +01:00
if (this->desiredValue + this->smoothScrollingOffset != value) {
2017-04-12 17:46:44 +02:00
if (animated) {
2017-12-19 01:11:35 +01:00
this->currentValueAnimation.stop();
this->currentValueAnimation.setStartValue(this->currentValue +
this->smoothScrollingOffset);
2017-04-12 17:46:44 +02:00
2017-12-18 22:13:46 +01:00
// if (((this->getMaximum() - this->getLargeChange()) - value) <= 0.01) {
// value += 1;
// }
2017-12-19 01:11:35 +01:00
this->currentValueAnimation.setEndValue(value);
this->smoothScrollingOffset = 0;
this->atBottom = ((this->getMaximum() - this->getLargeChange()) - value) <= 0.01;
2017-12-19 01:11:35 +01:00
this->currentValueAnimation.start();
2017-04-12 17:46:44 +02:00
} else {
2017-12-19 01:11:35 +01:00
if (this->currentValueAnimation.state() != QPropertyAnimation::Running) {
this->smoothScrollingOffset = 0;
this->desiredValue = value;
this->currentValueAnimation.stop();
this->atBottom = ((this->getMaximum() - this->getLargeChange()) - value) <= 0.01;
2017-04-12 17:46:44 +02:00
setCurrentValue(value);
}
}
2017-01-03 21:19:33 +01:00
}
2017-12-19 01:11:35 +01:00
this->smoothScrollingOffset = 0;
this->desiredValue = value;
2017-04-12 17:46:44 +02:00
}
qreal ScrollBar::getMaximum() const
{
2017-12-19 01:11:35 +01:00
return this->maximum;
2017-04-12 17:46:44 +02:00
}
qreal ScrollBar::getMinimum() const
{
2017-12-19 01:11:35 +01:00
return this->minimum;
2017-04-12 17:46:44 +02:00
}
qreal ScrollBar::getLargeChange() const
{
2017-12-19 01:11:35 +01:00
return this->largeChange;
2017-04-12 17:46:44 +02:00
}
qreal ScrollBar::getSmallChange() const
{
2017-12-19 01:11:35 +01:00
return this->smallChange;
2017-04-12 17:46:44 +02:00
}
qreal ScrollBar::getDesiredValue() const
{
2017-12-19 01:11:35 +01:00
return this->desiredValue + this->smoothScrollingOffset;
2017-04-12 17:46:44 +02:00
}
qreal ScrollBar::getCurrentValue() const
{
2017-12-19 01:11:35 +01:00
return this->currentValue;
2017-04-12 17:46:44 +02:00
}
void ScrollBar::offset(qreal value)
{
2017-12-19 01:11:35 +01:00
if (this->currentValueAnimation.state() == QPropertyAnimation::Running) {
this->smoothScrollingOffset += value;
} else {
this->setDesiredValue(this->getDesiredValue() + value);
}
}
2017-04-12 17:46:44 +02:00
boost::signals2::signal<void()> &ScrollBar::getCurrentValueChanged()
{
2017-12-19 01:11:35 +01:00
return this->currentValueChanged;
2017-04-12 17:46:44 +02:00
}
void ScrollBar::setCurrentValue(qreal value)
{
2017-12-19 01:11:35 +01:00
value = std::max(this->minimum, std::min(this->maximum - this->largeChange,
value + this->smoothScrollingOffset));
2017-04-12 17:46:44 +02:00
if (std::abs(this->currentValue - value) > 0.000001) {
2017-12-19 01:11:35 +01:00
this->currentValue = value;
2017-04-12 17:46:44 +02:00
this->updateScroll();
2017-12-19 01:11:35 +01:00
this->currentValueChanged();
2017-04-12 17:46:44 +02:00
this->update();
2017-04-12 17:46:44 +02:00
}
2017-01-03 21:19:33 +01:00
}
2017-06-06 17:18:23 +02:00
void ScrollBar::printCurrentState(const QString &prefix) const
{
qDebug() << prefix //
<< "Current value: " << this->getCurrentValue() //
<< ". Maximum: " << this->getMaximum() //
<< ". Minimum: " << this->getMinimum() //
<< ". Large change: " << this->getLargeChange(); //
}
2017-04-12 17:46:44 +02:00
void ScrollBar::paintEvent(QPaintEvent *)
2017-01-03 21:19:33 +01:00
{
bool mouseOver = this->mouseOverIndex != -1;
int xOffset = mouseOver ? 0 : width() - (int)(4 * this->getDpiMultiplier());
2017-01-03 21:19:33 +01:00
QPainter painter(this);
2017-12-31 00:50:07 +01:00
// painter.fillRect(rect(), this->themeManager.ScrollbarBG);
2017-01-03 21:19:33 +01:00
2018-01-02 02:15:11 +01:00
// painter.fillRect(QRect(xOffset, 0, width(), this->buttonHeight),
// this->themeManager.ScrollbarArrow);
// painter.fillRect(QRect(xOffset, height() - this->buttonHeight, width(),
// this->buttonHeight),
// this->themeManager.ScrollbarArrow);
2017-08-12 12:09:26 +02:00
this->thumbRect.setX(xOffset);
2017-08-12 12:09:26 +02:00
// mouse over thumb
2017-12-19 01:11:35 +01:00
if (this->mouseDownIndex == 2) {
2018-01-02 02:15:11 +01:00
painter.fillRect(this->thumbRect, this->themeManager.scrollbars.thumbSelected);
2017-08-12 12:09:26 +02:00
}
// mouse not over thumb
else {
2018-01-02 02:15:11 +01:00
painter.fillRect(this->thumbRect, this->themeManager.scrollbars.thumb);
2017-08-12 12:09:26 +02:00
}
2017-01-26 04:26:40 +01:00
2017-04-12 17:46:44 +02:00
// ScrollBarHighlight *highlight = highlights;
2017-01-18 04:33:30 +01:00
2017-12-19 01:11:35 +01:00
this->mutex.lock();
2017-01-18 04:33:30 +01:00
// do {
// painter.fillRect();
// } while ((highlight = highlight->next()) != nullptr);
2017-01-03 21:19:33 +01:00
2017-12-19 01:11:35 +01:00
this->mutex.unlock();
2017-01-18 04:33:30 +01:00
}
2017-12-26 16:54:39 +01:00
void ScrollBar::resizeEvent(QResizeEvent *)
{
this->resize((int)(16 * this->getDpiMultiplier()), this->height());
}
2017-04-12 17:46:44 +02:00
void ScrollBar::mouseMoveEvent(QMouseEvent *event)
2017-01-26 04:26:40 +01:00
{
2017-12-19 01:11:35 +01:00
if (this->mouseDownIndex == -1) {
2017-01-26 04:26:40 +01:00
int y = event->pos().y();
2017-12-19 01:11:35 +01:00
auto oldIndex = this->mouseOverIndex;
2017-01-26 04:26:40 +01:00
2017-12-19 01:11:35 +01:00
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;
2017-01-26 04:26:40 +01:00
} else {
2017-12-19 01:11:35 +01:00
this->mouseOverIndex = 4;
2017-01-26 04:26:40 +01:00
}
2017-12-19 01:11:35 +01:00
if (oldIndex != this->mouseOverIndex) {
2017-04-12 17:46:44 +02:00
update();
2017-01-26 04:26:40 +01:00
}
2017-12-19 01:11:35 +01:00
} else if (this->mouseDownIndex == 2) {
int delta = event->pos().y() - this->lastMousePosition.y();
2017-01-26 04:26:40 +01:00
2017-12-19 01:11:35 +01:00
setDesiredValue(this->desiredValue + (qreal)delta / this->trackHeight * this->maximum);
2017-01-26 04:26:40 +01:00
}
2017-12-19 01:11:35 +01:00
this->lastMousePosition = event->pos();
2017-01-26 04:26:40 +01:00
}
2017-04-12 17:46:44 +02:00
void ScrollBar::mousePressEvent(QMouseEvent *event)
2017-01-26 04:26:40 +01:00
{
int y = event->pos().y();
2017-12-19 01:11:35 +01:00
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;
2017-01-26 04:26:40 +01:00
} else {
2017-12-19 01:11:35 +01:00
this->mouseDownIndex = 4;
2017-01-26 04:26:40 +01:00
}
}
2017-04-12 17:46:44 +02:00
void ScrollBar::mouseReleaseEvent(QMouseEvent *event)
2017-01-26 04:26:40 +01:00
{
int y = event->pos().y();
2017-12-19 01:11:35 +01:00
if (y < this->buttonHeight) {
if (this->mouseDownIndex == 0) {
setDesiredValue(this->desiredValue - this->smallChange, true);
2017-01-26 04:26:40 +01:00
}
2017-12-19 01:11:35 +01:00
} else if (y < this->thumbRect.y()) {
if (this->mouseDownIndex == 1) {
setDesiredValue(this->desiredValue - this->smallChange, true);
2017-01-26 04:26:40 +01:00
}
2017-12-19 01:11:35 +01:00
} else if (this->thumbRect.contains(2, y)) {
2017-01-26 04:26:40 +01:00
// do nothing
2017-12-19 01:11:35 +01:00
} else if (y < height() - this->buttonHeight) {
if (this->mouseDownIndex == 3) {
setDesiredValue(this->desiredValue + this->smallChange, true);
2017-01-26 04:26:40 +01:00
}
} else {
2017-12-19 01:11:35 +01:00
if (this->mouseDownIndex == 4) {
setDesiredValue(this->desiredValue + this->smallChange, true);
2017-01-26 04:26:40 +01:00
}
}
2017-12-19 01:11:35 +01:00
this->mouseDownIndex = -1;
2017-01-26 07:10:46 +01:00
update();
2017-01-26 04:26:40 +01:00
}
2017-04-12 17:46:44 +02:00
void ScrollBar::leaveEvent(QEvent *)
2017-01-26 04:26:40 +01:00
{
2017-12-19 01:11:35 +01:00
this->mouseOverIndex = -1;
2017-01-26 04:26:40 +01:00
2017-01-26 07:10:46 +01:00
update();
2017-01-26 04:26:40 +01:00
}
2017-04-12 17:46:44 +02:00
void ScrollBar::updateScroll()
2017-01-18 04:33:30 +01:00
{
2017-12-19 01:11:35 +01:00
this->trackHeight = height() - this->buttonHeight - this->buttonHeight - MIN_THUMB_HEIGHT - 1;
2017-01-18 04:33:30 +01:00
2017-12-19 01:11:35 +01:00
this->thumbRect = QRect(
0, (int)(this->currentValue / this->maximum * this->trackHeight) + 1 + this->buttonHeight,
width(), (int)(this->largeChange / this->maximum * this->trackHeight) + MIN_THUMB_HEIGHT);
2017-01-18 04:33:30 +01:00
2017-01-26 07:10:46 +01:00
update();
2017-01-03 21:19:33 +01:00
}
2017-06-06 17:18:23 +02:00
} // namespace widgets
} // namespace chatterino