mirror of
https://github.com/Linloir/SceneEditor.git
synced 2025-12-16 23:18:12 +08:00
423 lines
14 KiB
C++
423 lines
14 KiB
C++
#include "scrolllistwidget.h"
|
|
|
|
ScrollListWidget::ScrollListWidget(QWidget* parent) : QWidget(parent)
|
|
{
|
|
//initialize list container and timer
|
|
container = new ScrollListContainer(this);
|
|
container->move(0, 0);
|
|
container->resize(this->width(), 3);
|
|
getCord = new QTimer;
|
|
getCord->setSingleShot(true);
|
|
rfrshView = new QTimer;
|
|
getCord->setSingleShot(true);
|
|
|
|
indicator = new ScrollListIndicator(this);
|
|
indicator->resize(indicator->width(), (int)((double)this->height() * this->height() / (double)container->height()));
|
|
indicator->move(this->width() - indicator->width() - 3, 0);
|
|
|
|
this->setMouseTracking(true);
|
|
container->setMouseTracking(true);
|
|
indicator->setMouseTracking(true);
|
|
|
|
bounce = new QPropertyAnimation(container, "pos");
|
|
|
|
QObject::connect(getCord, SIGNAL(timeout()), this, SLOT(updateSpd()));
|
|
QObject::connect(rfrshView, SIGNAL(timeout()), this, SLOT(scrollContainer()));
|
|
QObject::connect(indicator, SIGNAL(scrollPage(int)), this, SLOT(scrollIndicator(int)));
|
|
}
|
|
|
|
void ScrollListWidget::paintEvent(QPaintEvent* event) {
|
|
container->resize(this->width(), container->height());
|
|
if (container->height() > this->height() && container->y() < this->height() - container->height() && curSpd == 0 && bounce->state() == QAbstractAnimation::Stopped)
|
|
container->move(container->x(), this->height() - container->height());
|
|
if (container->height() <= this->height()) {
|
|
container->move(container->x(), 0);
|
|
indicator->hide();
|
|
}
|
|
else {
|
|
indicator->show();
|
|
}
|
|
indicator->resize(indicator->width(), (int)((double)this->height() * this->height() / (double)container->height()));
|
|
indicator->move(this->width() - indicator->width() - 3, -container->y() * this->height() / container->height());
|
|
}
|
|
|
|
void ScrollListWidget::mousePressEvent(QMouseEvent* event) {
|
|
if (container->height() > this->height()) {
|
|
if (container->y() <= 0 && container->y() + container->height() >= this->height())
|
|
pressed = true;
|
|
lastY = event->pos().y();
|
|
}
|
|
getCord->stop();
|
|
rfrshView->stop();
|
|
curSpd = 0;
|
|
outOfEdge = false;
|
|
moveStored = 0;
|
|
nextMove = 1;
|
|
}
|
|
|
|
void ScrollListWidget::mouseMoveEvent(QMouseEvent* event) {
|
|
setCursor(Qt::ArrowCursor);
|
|
if (pressed) {
|
|
//start scroll
|
|
if (!getCord->isActive() && event->pos().y() - lastY != 0) {
|
|
//start 30ms timer
|
|
getCord->start(30);
|
|
strtY = event->pos().y();
|
|
}
|
|
if (container->y() <= 0 && container->y() + container->height() >= this->height())
|
|
container->move(container->x(), container->y() + event->pos().y() - lastY);
|
|
else {
|
|
if (!outOfEdge) {
|
|
bfEdgeY = event->pos().y();
|
|
container->move(container->x(), container->y() + event->pos().y() - lastY);
|
|
outOfEdge = true;
|
|
}
|
|
else {
|
|
int pos = container->y() >= 0 ? 1 : -1;
|
|
int dp = event->pos().y() - bfEdgeY;
|
|
if (dp == 0) {
|
|
outOfEdge = false;
|
|
nextMove = 1;
|
|
moveStored = 0;
|
|
if (container->y() >= 0)
|
|
container->move(container->x(), 0);
|
|
else
|
|
container->move(container->x(), this->height() - container->height());
|
|
}
|
|
else if (dp / abs(dp) != pos) {
|
|
outOfEdge = false;
|
|
container->move(container->x(), this->y() + event->pos().y() - bfEdgeY);
|
|
nextMove = 1;
|
|
moveStored = 0;
|
|
}
|
|
else {
|
|
while (abs(moveStored) + nextMove <= abs(event->pos().y() - bfEdgeY)) {
|
|
moveStored += nextMove * pos;
|
|
container->move(container->x(), container->y() + pos);
|
|
nextMove++;
|
|
}
|
|
while (nextMove > 1 && abs(moveStored) > abs(event->pos().y() - bfEdgeY)) {
|
|
nextMove--;
|
|
moveStored -= nextMove * pos;
|
|
container->move(container->x(), container->y() - pos);
|
|
}
|
|
if (moveStored == 0) {
|
|
outOfEdge = false;
|
|
if (container->y() >= 0)
|
|
container->move(container->x(), 0);
|
|
else
|
|
container->move(container->x(), this->height() - container->height());
|
|
nextMove = 1;
|
|
moveStored = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
lastY = event->pos().y();
|
|
}
|
|
}
|
|
|
|
void ScrollListWidget::mouseReleaseEvent(QMouseEvent* event) {
|
|
//start scrolling
|
|
if (container->y() > 0 || container->y() + container->height() < this->height())
|
|
bounceBack();
|
|
else
|
|
rfrshView->start(30);
|
|
pressed = false;
|
|
}
|
|
|
|
void ScrollListWidget::bounceBack() {
|
|
rfrshView->stop();
|
|
getCord->stop();
|
|
bounce->setDuration(500);
|
|
bounce->setStartValue(container->pos());
|
|
if (container->y() > 0)
|
|
bounce->setEndValue(QPoint(container->x(), 0));
|
|
else
|
|
bounce->setEndValue(QPoint(container->x(), this->height() - container->height()));
|
|
bounce->setEasingCurve(QEasingCurve::OutQuad);
|
|
bounce->start();
|
|
}
|
|
|
|
void ScrollListWidget::scrollContainer() {
|
|
//scroll
|
|
if (curSpd > 0) {
|
|
if (curSpd > MAXSPEED && !ignoreMaxSpeed)
|
|
curSpd = MAXSPEED;
|
|
else if (curSpd <= MAXSPEED) ignoreMaxSpeed = false;
|
|
int dp = scrollDown ? curSpd : -curSpd;
|
|
container->move(container->x(), container->y() + dp);
|
|
}
|
|
else
|
|
return;
|
|
if (container->y() <= 0 && container->y() + container->height() >= this->height()) {
|
|
curSpd -= damp;
|
|
curSpd = curSpd < 0 ? 0 : curSpd;
|
|
}
|
|
else
|
|
curSpd /= 2;
|
|
if (curSpd == 0 && (container->y() > 0 || container->y() + container->height() < this->height()))
|
|
bounceBack();
|
|
else
|
|
rfrshView->start(30);
|
|
}
|
|
|
|
void ScrollListWidget::updateSpd() {
|
|
int spd = lastY - strtY;
|
|
scrollDown = spd >= 0;
|
|
strtY = lastY;
|
|
curSpd = abs(spd);
|
|
}
|
|
|
|
void ScrollListWidget::addWidget(QWidget* newWidget, bool setAnimation) {
|
|
newWidget->setParent(container);
|
|
container->AddWidget(newWidget, setAnimation);
|
|
}
|
|
|
|
void ScrollListWidget::removeWidget(QWidget* w) {
|
|
container->RemoveWidget(w);
|
|
}
|
|
|
|
void ScrollListWidget::scrollToTop() {
|
|
curSpd = sqrt(8 * (-container->pos().y()) + 2) / 2;
|
|
scrollDown = true;
|
|
getCord->stop();
|
|
rfrshView->stop();
|
|
outOfEdge = false;
|
|
moveStored = 0;
|
|
nextMove = 1;
|
|
ignoreMaxSpeed = true;
|
|
rfrshView->start(30);
|
|
}
|
|
|
|
void ScrollListWidget::updateHeight() {
|
|
container->updateHeight();
|
|
}
|
|
|
|
void ScrollListWidget::clear() {
|
|
container->clear();
|
|
}
|
|
|
|
void ScrollListWidget::scrollIndicator(int dp) {
|
|
int newY = container->y() - dp * container->height() / this->height();
|
|
if (newY > 0)
|
|
newY = 0;
|
|
else if (newY < this->height() - container->height())
|
|
newY = this->height() - container->height();
|
|
container->move(container->x(), newY);
|
|
update();
|
|
}
|
|
|
|
void ScrollListWidget::wheelEvent(QWheelEvent* event) {
|
|
if (container->y() > 0 || container->y() + container->height() < this->height())
|
|
return;
|
|
curSpd += 5;
|
|
bool newDirection = event->angleDelta().y() > 0;
|
|
if (newDirection != scrollDown)
|
|
curSpd = 5;
|
|
if (curSpd > MAXSPEED)
|
|
curSpd = MAXSPEED;
|
|
scrollDown = newDirection;
|
|
if (!rfrshView->isActive())
|
|
rfrshView->start(30);
|
|
update();
|
|
}
|
|
|
|
ScrollListContainer::ScrollListContainer(QWidget* parent) : QWidget(parent) {}
|
|
|
|
void ScrollListContainer::paintEvent(QPaintEvent* event) {
|
|
for (int i = 0; i < widgets.size(); i++) {
|
|
widgets[i]->resize(this->width(), widgets[i]->height());
|
|
}
|
|
}
|
|
|
|
void ScrollListContainer::AddWidget(QWidget* widget, bool setAnimation) {
|
|
//Add animation for all widgets current
|
|
this->resize(this->width(), this->height() + widget->height() + spacing);
|
|
widgets.push_back(widget);
|
|
size++;
|
|
ys.push_back(0);
|
|
widget->resize(this->width(), widget->height());
|
|
widget->show();
|
|
|
|
if (setAnimation) {
|
|
QGraphicsOpacityEffect* widgetOpac = new QGraphicsOpacityEffect(widget);
|
|
widgetOpac->setOpacity(0);
|
|
widget->setGraphicsEffect(widgetOpac);
|
|
QParallelAnimationGroup* dpGroup = new QParallelAnimationGroup;
|
|
QSequentialAnimationGroup* newWidgetFadeIn = new QSequentialAnimationGroup;
|
|
for (int i = 0; i < size - 1; i++) {
|
|
ys[i] += widget->height() + spacing;
|
|
QPropertyAnimation* move = new QPropertyAnimation(widgets[i], "pos");
|
|
move->setDuration(750);
|
|
move->setStartValue(widgets[i]->pos());
|
|
move->setEndValue(QPoint(widgets[i]->x(), ys[i]));
|
|
move->setEasingCurve(QEasingCurve::InOutQuart);
|
|
dpGroup->addAnimation(move);
|
|
}
|
|
newWidgetFadeIn->addPause(300);
|
|
QPropertyAnimation* fade = new QPropertyAnimation(widgetOpac, "opacity", widget);
|
|
fade->setDuration(300);
|
|
fade->setStartValue(0);
|
|
fade->setEndValue(0.99);
|
|
newWidgetFadeIn->addAnimation(fade);
|
|
dpGroup->addAnimation(newWidgetFadeIn);
|
|
dpGroup->start();
|
|
connect(dpGroup, &QPropertyAnimation::stateChanged, [=]() {
|
|
if (dpGroup->state() == QAbstractAnimation::Stopped) {
|
|
if (widgetOpac->opacity() != 0.99) {
|
|
fade->start(QAbstractAnimation::DeleteWhenStopped);
|
|
connect(fade, &QPropertyAnimation::finished, [=]() {widgetOpac->deleteLater(); });
|
|
}
|
|
else {
|
|
dpGroup->deleteLater();
|
|
widgetOpac->deleteLater();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
for (int i = 0; i < size - 1; i++) {
|
|
ys[i] += widget->height() + spacing;
|
|
widgets[i]->move(QPoint(widgets[i]->pos().x(), ys[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScrollListContainer::RemoveWidget(QWidget* widget) {
|
|
int index;
|
|
if (widget == nullptr) {
|
|
index = size - 1;
|
|
if (index != -1)
|
|
widget = widgets[index];
|
|
}
|
|
else
|
|
index = widgets.indexOf(widget);
|
|
if (index == -1 || widget == nullptr) {
|
|
return;
|
|
}
|
|
this->resize(this->width(), this->height() - widget->height() - spacing);
|
|
this->parentWidget()->update();
|
|
widget->hide();
|
|
widget->setParent(nullptr);
|
|
QParallelAnimationGroup* dpGroup = new QParallelAnimationGroup;
|
|
for (int i = index - 1; i >= 0; i--) {
|
|
ys[i] -= (widget->height() + spacing);
|
|
QPropertyAnimation* move = new QPropertyAnimation(widgets[i], "pos");
|
|
move->setDuration(750);
|
|
move->setStartValue(widgets[i]->pos());
|
|
move->setEndValue(QPoint(widgets[i]->x(), ys[i]));
|
|
move->setEasingCurve(QEasingCurve::InOutQuart);
|
|
dpGroup->addAnimation(move);
|
|
}
|
|
dpGroup->start(QAbstractAnimation::DeleteWhenStopped);
|
|
widgets.remove(index);
|
|
size--;
|
|
ys.remove(index);
|
|
}
|
|
|
|
void ScrollListContainer::updateHeight() {
|
|
for (int i = size - 2; i >= 0; i--) {
|
|
ys[i] = ys[i + 1] + widgets[i + 1]->height() + spacing;
|
|
widgets[i]->move(widgets[i]->pos().x(), ys[i]);
|
|
}
|
|
this->resize(this->width(), ys[0] + widgets[0]->height() + 3);
|
|
}
|
|
|
|
void ScrollListContainer::clear() {
|
|
int n = size;
|
|
for (int i = 0; i < n; i++)
|
|
RemoveWidget();
|
|
}
|
|
|
|
ScrollListIndicator::ScrollListIndicator(QWidget* parent) : QWidget(parent)
|
|
{
|
|
this->resize(defaultWidth, 0);
|
|
hovTimer = new QTimer(this);
|
|
hovTimer->setSingleShot(true);
|
|
aniPause = new QTimer(this);
|
|
aniPause->setSingleShot(true);
|
|
QObject::connect(hovTimer, SIGNAL(timeout()), this, SLOT(setHoverActive()));
|
|
this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
|
this->curColor = defaultColor;
|
|
|
|
this->setMouseTracking(true);
|
|
}
|
|
|
|
void ScrollListIndicator::paintEvent(QPaintEvent* event) {
|
|
QPainter painter(this);
|
|
painter.setPen(Qt::NoPen);
|
|
painter.setBrush(curColor);
|
|
painter.drawRect(this->rect());
|
|
}
|
|
|
|
void ScrollListIndicator::enterEvent(QEnterEvent* event) {
|
|
if (!pressed) {
|
|
hovTimer->start(100);
|
|
curColor = hoverColor;
|
|
update();
|
|
}
|
|
}
|
|
|
|
void ScrollListIndicator::leaveEvent(QEvent* event) {
|
|
hovTimer->stop();
|
|
curColor = defaultColor;
|
|
QPropertyAnimation* narrow = new QPropertyAnimation(this, "geometry");
|
|
narrow->setDuration(300);
|
|
narrow->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
|
|
narrow->setEndValue(QRect(this->parentWidget()->width() - margin - defaultWidth, this->y(), defaultWidth, this->height()));
|
|
narrow->setEasingCurve(QEasingCurve::InOutQuad);
|
|
narrow->start(QAbstractAnimation::DeleteWhenStopped);
|
|
aniPause->start(300);
|
|
update();
|
|
}
|
|
|
|
void ScrollListIndicator::mousePressEvent(QMouseEvent* event) {
|
|
curColor = pressColor;
|
|
pressed = true;
|
|
//>note: globalPos -> globalPosition here due to deprecation
|
|
//> may cause issues
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
|
lastY = event->globalPosition().y();
|
|
#else
|
|
lastY = event->globalPos().y();
|
|
#endif
|
|
update();
|
|
}
|
|
|
|
void ScrollListIndicator::mouseMoveEvent(QMouseEvent* event) {
|
|
if (pressed && !aniPause->isActive()) {
|
|
//>note: globalPos -> globalPosition here due to deprecation
|
|
//> may cause issues
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
|
int dp = event->globalPosition().y() - lastY;
|
|
#else
|
|
int dp = event->globalPos().y() - lastY;
|
|
#endif
|
|
emit scrollPage(dp);
|
|
//>note: globalPos -> globalPosition here due to deprecation
|
|
//> may cause issues
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
|
|
lastY = event->globalPosition().y();
|
|
#else
|
|
lastY = event->globalPos().y();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void ScrollListIndicator::mouseReleaseEvent(QMouseEvent* event) {
|
|
pressed = false;
|
|
curColor = hoverColor;
|
|
update();
|
|
}
|
|
|
|
void ScrollListIndicator::setHoverActive() {
|
|
QPropertyAnimation* widen = new QPropertyAnimation(this, "geometry");
|
|
widen->setDuration(300);
|
|
widen->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
|
|
widen->setEndValue(QRect(this->parentWidget()->width() - margin - defaultWidthAtFocus, this->y(), defaultWidthAtFocus, this->height()));
|
|
widen->setEasingCurve(QEasingCurve::InOutQuad);
|
|
widen->start(QAbstractAnimation::DeleteWhenStopped);
|
|
aniPause->start(300);
|
|
}
|