2017-06-11 09:31:45 +02:00
|
|
|
#include "widgets/scrollbar.hpp"
|
|
|
|
#include "colorscheme.hpp"
|
2017-06-26 16:41:20 +02:00
|
|
|
#include "widgets/chatwidgetview.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>
|
|
|
|
|
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
|
|
|
|
2017-06-26 16:41:20 +02:00
|
|
|
ScrollBar::ScrollBar(ChatWidgetView *parent)
|
|
|
|
: BaseWidget(parent)
|
2017-06-29 14:13:00 +02:00
|
|
|
, _currentValueAnimation(this, "_currentValue")
|
2017-05-27 16:16:39 +02:00
|
|
|
, _highlights(nullptr)
|
2017-04-12 17:46:44 +02:00
|
|
|
{
|
|
|
|
resize(16, 100);
|
|
|
|
_currentValueAnimation.setDuration(250);
|
|
|
|
_currentValueAnimation.setEasingCurve(QEasingCurve(QEasingCurve::OutCubic));
|
|
|
|
|
|
|
|
setMouseTracking(true);
|
2017-01-03 21:19:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ScrollBar::~ScrollBar()
|
|
|
|
{
|
2017-04-12 17:46:44 +02:00
|
|
|
auto highlight = _highlights;
|
2017-01-03 21:19:33 +01:00
|
|
|
|
2017-06-11 09:37:30 +02: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-04-12 17:46:44 +02:00
|
|
|
_mutex.lock();
|
2017-01-03 21:19:33 +01:00
|
|
|
|
2017-06-11 09:37:30 +02:00
|
|
|
ScrollBarHighlight *last = nullptr;
|
2017-04-12 17:46:44 +02:00
|
|
|
ScrollBarHighlight *current = _highlights;
|
2017-01-03 21:19:33 +01:00
|
|
|
|
2017-06-11 09:37:30 +02:00
|
|
|
while (current != nullptr) {
|
2017-01-11 18:52:09 +01:00
|
|
|
if (func(*current)) {
|
2017-06-11 09:37:30 +02:00
|
|
|
if (last == nullptr) {
|
2017-04-12 17:46:44 +02:00
|
|
|
_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-04-12 17:46:44 +02:00
|
|
|
_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-04-12 17:46:44 +02:00
|
|
|
_mutex.lock();
|
2017-01-03 21:19:33 +01:00
|
|
|
|
2017-06-11 09:37:30 +02:00
|
|
|
if (_highlights == nullptr) {
|
2017-04-12 17:46:44 +02:00
|
|
|
_highlights = highlight;
|
2017-01-11 18:52:09 +01:00
|
|
|
} else {
|
2017-04-12 17:46:44 +02:00
|
|
|
highlight->next = _highlights->next;
|
|
|
|
_highlights->next = highlight;
|
|
|
|
}
|
|
|
|
|
|
|
|
_mutex.unlock();
|
|
|
|
}
|
|
|
|
|
2017-06-06 17:18:23 +02:00
|
|
|
void ScrollBar::scrollToBottom()
|
|
|
|
{
|
|
|
|
this->setDesiredValue(this->_maximum - this->getLargeChange());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScrollBar::isAtBottom() const
|
|
|
|
{
|
2017-08-05 22:46:40 +02:00
|
|
|
return ((this->getMaximum() - this->getLargeChange()) - this->getCurrentValue()) <= 0.00001;
|
2017-06-06 17:18:23 +02:00
|
|
|
}
|
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
void ScrollBar::setMaximum(qreal value)
|
|
|
|
{
|
|
|
|
_maximum = value;
|
|
|
|
|
|
|
|
updateScroll();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScrollBar::setMinimum(qreal value)
|
|
|
|
{
|
|
|
|
_minimum = value;
|
|
|
|
|
|
|
|
updateScroll();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScrollBar::setLargeChange(qreal value)
|
|
|
|
{
|
|
|
|
_largeChange = value;
|
|
|
|
|
|
|
|
updateScroll();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScrollBar::setSmallChange(qreal value)
|
|
|
|
{
|
|
|
|
_smallChange = value;
|
|
|
|
|
|
|
|
updateScroll();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScrollBar::setDesiredValue(qreal value, bool animated)
|
|
|
|
{
|
|
|
|
value = std::max(_minimum, std::min(_maximum - _largeChange, value));
|
|
|
|
|
|
|
|
if (_desiredValue != value) {
|
|
|
|
if (animated) {
|
|
|
|
_currentValueAnimation.stop();
|
|
|
|
_currentValueAnimation.setStartValue(_currentValue);
|
|
|
|
|
|
|
|
_currentValueAnimation.setEndValue(value);
|
|
|
|
_currentValueAnimation.start();
|
|
|
|
} else {
|
|
|
|
if (_currentValueAnimation.state() != QPropertyAnimation::Running) {
|
|
|
|
// currentValueAnimation.stop();
|
|
|
|
|
|
|
|
setCurrentValue(value);
|
|
|
|
}
|
|
|
|
}
|
2017-01-03 21:19:33 +01:00
|
|
|
}
|
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
_desiredValue = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal ScrollBar::getMaximum() const
|
|
|
|
{
|
|
|
|
return _maximum;
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal ScrollBar::getMinimum() const
|
|
|
|
{
|
|
|
|
return _minimum;
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal ScrollBar::getLargeChange() const
|
|
|
|
{
|
|
|
|
return _largeChange;
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal ScrollBar::getSmallChange() const
|
|
|
|
{
|
|
|
|
return _smallChange;
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal ScrollBar::getDesiredValue() const
|
|
|
|
{
|
|
|
|
return _desiredValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal ScrollBar::getCurrentValue() const
|
|
|
|
{
|
|
|
|
return _currentValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::signals2::signal<void()> &ScrollBar::getCurrentValueChanged()
|
|
|
|
{
|
|
|
|
return _currentValueChanged;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScrollBar::setCurrentValue(qreal value)
|
|
|
|
{
|
|
|
|
value = std::max(_minimum, std::min(_maximum - _largeChange, value));
|
|
|
|
|
|
|
|
if (_currentValue != value) {
|
|
|
|
_currentValue = value;
|
|
|
|
|
|
|
|
updateScroll();
|
|
|
|
_currentValueChanged();
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
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
|
|
|
{
|
|
|
|
QPainter painter(this);
|
2017-06-26 16:41:20 +02:00
|
|
|
painter.fillRect(rect(), this->colorScheme.ScrollbarBG);
|
2017-01-03 21:19:33 +01:00
|
|
|
|
2017-08-05 18:15:23 +02:00
|
|
|
painter.fillRect(QRect(0, 0, width(), _buttonHeight), this->colorScheme.ScrollbarArrow);
|
|
|
|
painter.fillRect(QRect(0, height() - _buttonHeight, width(), _buttonHeight), this->colorScheme.ScrollbarArrow);
|
|
|
|
|
|
|
|
// mouse over thumb
|
|
|
|
if (this->_mouseDownIndex == 2) {
|
|
|
|
painter.fillRect(_thumbRect, this->colorScheme.ScrollbarThumbSelected);
|
|
|
|
}
|
|
|
|
// mouse not over thumb
|
|
|
|
else {
|
|
|
|
painter.fillRect(_thumbRect, this->colorScheme.ScrollbarThumb);
|
|
|
|
}
|
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-04-12 17:46:44 +02:00
|
|
|
_mutex.lock();
|
2017-01-18 04:33:30 +01:00
|
|
|
|
|
|
|
// do {
|
|
|
|
// painter.fillRect();
|
2017-06-11 09:37:30 +02:00
|
|
|
// } while ((highlight = highlight->next()) != nullptr);
|
2017-01-03 21:19:33 +01:00
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
_mutex.unlock();
|
2017-01-18 04:33:30 +01:00
|
|
|
}
|
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
void ScrollBar::mouseMoveEvent(QMouseEvent *event)
|
2017-01-26 04:26:40 +01:00
|
|
|
{
|
2017-04-12 17:46:44 +02:00
|
|
|
if (_mouseDownIndex == -1) {
|
2017-01-26 04:26:40 +01:00
|
|
|
int y = event->pos().y();
|
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
auto oldIndex = _mouseOverIndex;
|
2017-01-26 04:26:40 +01:00
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
if (y < _buttonHeight) {
|
|
|
|
_mouseOverIndex = 0;
|
|
|
|
} else if (y < _thumbRect.y()) {
|
|
|
|
_mouseOverIndex = 1;
|
|
|
|
} else if (_thumbRect.contains(2, y)) {
|
|
|
|
_mouseOverIndex = 2;
|
|
|
|
} else if (y < height() - _buttonHeight) {
|
|
|
|
_mouseOverIndex = 3;
|
2017-01-26 04:26:40 +01:00
|
|
|
} else {
|
2017-04-12 17:46:44 +02:00
|
|
|
_mouseOverIndex = 4;
|
2017-01-26 04:26:40 +01:00
|
|
|
}
|
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
if (oldIndex != _mouseOverIndex) {
|
|
|
|
update();
|
2017-01-26 04:26:40 +01:00
|
|
|
}
|
2017-04-12 17:46:44 +02:00
|
|
|
} else if (_mouseDownIndex == 2) {
|
|
|
|
int delta = event->pos().y() - _lastMousePosition.y();
|
2017-01-26 04:26:40 +01:00
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
setDesiredValue(_desiredValue + (qreal)delta / _trackHeight * _maximum);
|
2017-01-26 04:26:40 +01:00
|
|
|
}
|
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
_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-04-12 17:46:44 +02:00
|
|
|
if (y < _buttonHeight) {
|
|
|
|
_mouseDownIndex = 0;
|
|
|
|
} else if (y < _thumbRect.y()) {
|
|
|
|
_mouseDownIndex = 1;
|
|
|
|
} else if (_thumbRect.contains(2, y)) {
|
|
|
|
_mouseDownIndex = 2;
|
|
|
|
} else if (y < height() - _buttonHeight) {
|
|
|
|
_mouseDownIndex = 3;
|
2017-01-26 04:26:40 +01:00
|
|
|
} else {
|
2017-04-12 17:46:44 +02:00
|
|
|
_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-04-12 17:46:44 +02:00
|
|
|
if (y < _buttonHeight) {
|
|
|
|
if (_mouseDownIndex == 0) {
|
|
|
|
setDesiredValue(_desiredValue - _smallChange, true);
|
2017-01-26 04:26:40 +01:00
|
|
|
}
|
2017-04-12 17:46:44 +02:00
|
|
|
} else if (y < _thumbRect.y()) {
|
|
|
|
if (_mouseDownIndex == 1) {
|
|
|
|
setDesiredValue(_desiredValue - _smallChange, true);
|
2017-01-26 04:26:40 +01:00
|
|
|
}
|
2017-04-12 17:46:44 +02:00
|
|
|
} else if (_thumbRect.contains(2, y)) {
|
2017-01-26 04:26:40 +01:00
|
|
|
// do nothing
|
2017-04-12 17:46:44 +02:00
|
|
|
} else if (y < height() - _buttonHeight) {
|
|
|
|
if (_mouseDownIndex == 3) {
|
|
|
|
setDesiredValue(_desiredValue + _smallChange, true);
|
2017-01-26 04:26:40 +01:00
|
|
|
}
|
|
|
|
} else {
|
2017-04-12 17:46:44 +02:00
|
|
|
if (_mouseDownIndex == 4) {
|
|
|
|
setDesiredValue(_desiredValue + _smallChange, true);
|
2017-01-26 04:26:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
_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-04-12 17:46:44 +02:00
|
|
|
_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-04-12 17:46:44 +02:00
|
|
|
_trackHeight = height() - _buttonHeight - _buttonHeight - MIN_THUMB_HEIGHT - 1;
|
2017-01-18 04:33:30 +01:00
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
_thumbRect = QRect(0, (int)(_currentValue / _maximum * _trackHeight) + 1 + _buttonHeight,
|
|
|
|
width(), (int)(_largeChange / _maximum * _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
|