250 lines
10 KiB
C++
250 lines
10 KiB
C++
#include "ElaCentralStackedWidget.h"
|
|
|
|
#include "ElaTheme.h"
|
|
#include <QApplication>
|
|
#include <QGraphicsBlurEffect>
|
|
#include <QPainter>
|
|
#include <QPainterPath>
|
|
#include <QPropertyAnimation>
|
|
#include <QTimer>
|
|
#include <cmath>
|
|
ElaCentralStackedWidget::ElaCentralStackedWidget(QWidget *parent) : QStackedWidget(parent) {
|
|
_pPopupAnimationYOffset = 0;
|
|
_pScaleAnimationRatio = 1;
|
|
_pScaleAnimationPixOpacity = 1;
|
|
_pFlipAnimationRatio = 1;
|
|
_pBlurAnimationRadius = 0;
|
|
|
|
_blurEffect = new QGraphicsBlurEffect(this);
|
|
_blurEffect->setBlurHints(QGraphicsBlurEffect::BlurHint::QualityHint);
|
|
_blurEffect->setBlurRadius(0);
|
|
_blurEffect->setEnabled(false);
|
|
setGraphicsEffect(_blurEffect);
|
|
|
|
setObjectName("ElaCentralStackedWidget");
|
|
setStyleSheet("#ElaCentralStackedWidget{background-color:transparent;}");
|
|
_themeMode = eTheme->getThemeMode();
|
|
connect(eTheme, &ElaTheme::themeModeChanged, this, &ElaCentralStackedWidget::onThemeModeChanged);
|
|
}
|
|
|
|
ElaCentralStackedWidget::~ElaCentralStackedWidget() {}
|
|
|
|
void ElaCentralStackedWidget::onThemeModeChanged(ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; }
|
|
|
|
void ElaCentralStackedWidget::setIsTransparent(bool isTransparent) {
|
|
this->_isTransparent = isTransparent;
|
|
update();
|
|
}
|
|
|
|
bool ElaCentralStackedWidget::getIsTransparent() const { return _isTransparent; }
|
|
|
|
void ElaCentralStackedWidget::setIsHasRadius(bool isHasRadius) {
|
|
this->_isHasRadius = isHasRadius;
|
|
update();
|
|
}
|
|
|
|
void ElaCentralStackedWidget::doWindowStackSwitch(ElaWindowType::StackSwitchMode stackSwitchMode, int nodeIndex, bool isRouteBack) {
|
|
_stackSwitchMode = stackSwitchMode;
|
|
switch (stackSwitchMode) {
|
|
case ElaWindowType::None: {
|
|
this->setCurrentIndex(nodeIndex);
|
|
break;
|
|
}
|
|
case ElaWindowType::Popup: {
|
|
QTimer::singleShot(180, this, [=]() {
|
|
QWidget *targetWidget = this->widget(nodeIndex);
|
|
this->setCurrentIndex(nodeIndex);
|
|
_getTargetStackPix();
|
|
targetWidget->setVisible(false);
|
|
QPropertyAnimation *popupAnimation = new QPropertyAnimation(this, "pPopupAnimationYOffset");
|
|
connect(popupAnimation, &QPropertyAnimation::valueChanged, this, [=]() { update(); });
|
|
connect(popupAnimation, &QPropertyAnimation::finished, this, [=]() {
|
|
_targetStackPix = QPixmap();
|
|
targetWidget->setVisible(true);
|
|
});
|
|
popupAnimation->setEasingCurve(QEasingCurve::OutCubic);
|
|
popupAnimation->setDuration(300);
|
|
int targetWidgetY = targetWidget->y();
|
|
popupAnimation->setEndValue(targetWidgetY);
|
|
targetWidgetY += 80;
|
|
popupAnimation->setStartValue(targetWidgetY);
|
|
popupAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
});
|
|
break;
|
|
}
|
|
case ElaWindowType::Scale: {
|
|
QWidget *targetWidget = this->widget(nodeIndex);
|
|
_getCurrentStackPix();
|
|
this->setCurrentIndex(nodeIndex);
|
|
_getTargetStackPix();
|
|
targetWidget->setVisible(false);
|
|
_isDrawNewPix = false;
|
|
QPropertyAnimation *currentPixZoomAnimation = new QPropertyAnimation(this, "pScaleAnimationRatio");
|
|
connect(currentPixZoomAnimation, &QPropertyAnimation::valueChanged, this, [=]() { update(); });
|
|
connect(currentPixZoomAnimation, &QPropertyAnimation::finished, this, [=]() {
|
|
_isDrawNewPix = true;
|
|
QPropertyAnimation *targetPixZoomAnimation = new QPropertyAnimation(this, "pScaleAnimationRatio");
|
|
connect(targetPixZoomAnimation, &QPropertyAnimation::valueChanged, this, [=]() { update(); });
|
|
connect(targetPixZoomAnimation, &QPropertyAnimation::finished, this, [=]() {
|
|
_targetStackPix = QPixmap();
|
|
_currentStackPix = QPixmap();
|
|
targetWidget->setVisible(true);
|
|
});
|
|
if (isRouteBack) {
|
|
targetPixZoomAnimation->setStartValue(1.5);
|
|
targetPixZoomAnimation->setEndValue(1);
|
|
} else {
|
|
// 放大
|
|
targetPixZoomAnimation->setStartValue(0.85);
|
|
targetPixZoomAnimation->setEndValue(1);
|
|
}
|
|
targetPixZoomAnimation->setDuration(300);
|
|
targetPixZoomAnimation->setEasingCurve(QEasingCurve::OutCubic);
|
|
targetPixZoomAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
});
|
|
if (isRouteBack) {
|
|
// 缩小
|
|
currentPixZoomAnimation->setStartValue(1);
|
|
currentPixZoomAnimation->setEndValue(0.85);
|
|
} else {
|
|
// 放大
|
|
currentPixZoomAnimation->setStartValue(1);
|
|
currentPixZoomAnimation->setEndValue(1.15);
|
|
}
|
|
currentPixZoomAnimation->setDuration(150);
|
|
currentPixZoomAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
|
|
QPropertyAnimation *currentPixOpacityAnimation = new QPropertyAnimation(this, "pScaleAnimationPixOpacity");
|
|
connect(currentPixZoomAnimation, &QPropertyAnimation::finished, this, [=]() {
|
|
QPropertyAnimation *targetPixOpacityAnimation = new QPropertyAnimation(this, "pScaleAnimationPixOpacity");
|
|
targetPixOpacityAnimation->setStartValue(0);
|
|
targetPixOpacityAnimation->setEndValue(1);
|
|
targetPixOpacityAnimation->setDuration(300);
|
|
targetPixOpacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
});
|
|
currentPixOpacityAnimation->setStartValue(1);
|
|
currentPixOpacityAnimation->setEndValue(0);
|
|
currentPixOpacityAnimation->setDuration(150);
|
|
currentPixOpacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
break;
|
|
}
|
|
case ElaWindowType::Flip: {
|
|
QWidget *targetWidget = this->widget(nodeIndex);
|
|
_getCurrentStackPix();
|
|
this->setCurrentIndex(nodeIndex);
|
|
_getTargetStackPix();
|
|
targetWidget->setVisible(false);
|
|
QPropertyAnimation *flipAnimation = new QPropertyAnimation(this, "pFlipAnimationRatio");
|
|
connect(flipAnimation, &QPropertyAnimation::valueChanged, this, [=]() { update(); });
|
|
connect(flipAnimation, &QPropertyAnimation::finished, this, [=]() {
|
|
_targetStackPix = QPixmap();
|
|
_currentStackPix = QPixmap();
|
|
targetWidget->setVisible(true);
|
|
});
|
|
flipAnimation->setEasingCurve(QEasingCurve::InOutSine);
|
|
flipAnimation->setDuration(650);
|
|
flipAnimation->setStartValue(0);
|
|
flipAnimation->setEndValue(isRouteBack ? -180 : 180);
|
|
flipAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
break;
|
|
}
|
|
case ElaWindowType::Blur: {
|
|
_targetStackPix = QPixmap();
|
|
_blurEffect->setEnabled(true);
|
|
QPropertyAnimation *blurAnimation = new QPropertyAnimation(this, "pBlurAnimationRadius");
|
|
connect(blurAnimation, &QPropertyAnimation::valueChanged, this, [=]() { _blurEffect->setBlurRadius(_pBlurAnimationRadius); });
|
|
connect(blurAnimation, &QPropertyAnimation::finished, this, [=]() { _blurEffect->setEnabled(false); });
|
|
blurAnimation->setEasingCurve(QEasingCurve::InOutSine);
|
|
blurAnimation->setDuration(350);
|
|
blurAnimation->setStartValue(40);
|
|
blurAnimation->setEndValue(2);
|
|
blurAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
QApplication::processEvents();
|
|
this->setCurrentIndex(nodeIndex);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ElaCentralStackedWidget::paintEvent(QPaintEvent *event) {
|
|
QRect targetRect = this->rect();
|
|
// ADDZY: 左上角向右下移动(1, 1),右下角向右下收缩(10, 10)
|
|
targetRect.adjust(1, 1, 10, 10);
|
|
QPainter painter(this);
|
|
painter.save();
|
|
painter.setRenderHints(QPainter::Antialiasing);
|
|
if (!_isTransparent) {
|
|
painter.setPen(QPen(ElaThemeColor(_themeMode, BasicBaseLine), 1.5));
|
|
painter.setBrush(ElaThemeColor(_themeMode, WindowCentralStackBase));
|
|
if (_isHasRadius) {
|
|
painter.drawRoundedRect(targetRect, 10, 10);
|
|
} else {
|
|
painter.drawRect(targetRect);
|
|
}
|
|
}
|
|
// 切换动画
|
|
if (!_targetStackPix.isNull()) {
|
|
QPainterPath clipPath;
|
|
clipPath.addRoundedRect(targetRect, 10, 10);
|
|
painter.setClipPath(clipPath);
|
|
switch (_stackSwitchMode) {
|
|
case ElaWindowType::None: {
|
|
break;
|
|
}
|
|
case ElaWindowType::Popup: {
|
|
painter.drawPixmap(QRect(0, _pPopupAnimationYOffset, width(), height()), _targetStackPix);
|
|
break;
|
|
}
|
|
case ElaWindowType::Scale: {
|
|
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
|
painter.setOpacity(_pScaleAnimationPixOpacity);
|
|
painter.translate(rect().center());
|
|
painter.scale(_pScaleAnimationRatio, _pScaleAnimationRatio);
|
|
painter.translate(-rect().center());
|
|
painter.drawPixmap(rect(), _isDrawNewPix ? _targetStackPix : _currentStackPix);
|
|
break;
|
|
}
|
|
case ElaWindowType::Flip: {
|
|
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
|
QTransform transform;
|
|
transform.translate(rect().center().x(), 0);
|
|
if (abs(_pFlipAnimationRatio) >= 90) {
|
|
transform.rotate(-180 + _pFlipAnimationRatio, Qt::YAxis);
|
|
} else {
|
|
transform.rotate(_pFlipAnimationRatio, Qt::YAxis);
|
|
}
|
|
transform.translate(-rect().center().x(), 0);
|
|
painter.setTransform(transform);
|
|
if (abs(_pFlipAnimationRatio) >= 90) {
|
|
painter.drawPixmap(rect(), _targetStackPix);
|
|
} else {
|
|
painter.drawPixmap(rect(), _currentStackPix);
|
|
}
|
|
break;
|
|
}
|
|
case ElaWindowType::Blur: {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
painter.restore();
|
|
}
|
|
|
|
void ElaCentralStackedWidget::_getCurrentStackPix() {
|
|
_targetStackPix = QPixmap();
|
|
bool isTransparent = _isTransparent;
|
|
_isTransparent = true;
|
|
currentWidget()->setVisible(true);
|
|
_currentStackPix = this->grab(rect());
|
|
currentWidget()->setVisible(false);
|
|
_isTransparent = isTransparent;
|
|
}
|
|
|
|
void ElaCentralStackedWidget::_getTargetStackPix() {
|
|
_targetStackPix = QPixmap();
|
|
bool isTransparent = _isTransparent;
|
|
_isTransparent = true;
|
|
_targetStackPix = this->grab(rect());
|
|
_isTransparent = isTransparent;
|
|
}
|