238 lines
12 KiB
C++
238 lines
12 KiB
C++
#include "ElaPopularCardFloater.h"
|
|
|
|
#include <QEvent>
|
|
#include <QGraphicsOpacityEffect>
|
|
#include <QPainter>
|
|
#include <QPainterPath>
|
|
#include <QPropertyAnimation>
|
|
|
|
#include "ElaPopularCard.h"
|
|
#include "ElaPopularCardPrivate.h"
|
|
#include "ElaPushButton.h"
|
|
#include "ElaTheme.h"
|
|
ElaPopularCardFloater::ElaPopularCardFloater(ElaPopularCard *card, ElaPopularCardPrivate *cardPrivate, QWidget *parent) : QWidget{parent} {
|
|
_card = card;
|
|
_cardPrivate = cardPrivate;
|
|
_pHoverOpacity = 0;
|
|
_pHoverYOffset = 0;
|
|
setObjectName("ElaPopularCardFloater");
|
|
setStyleSheet("#ElaPopularCardFloater{background-color:transparent}");
|
|
setMouseTracking(true);
|
|
|
|
_overButton = new ElaPushButton("获取", this);
|
|
_opacityEffect = new QGraphicsOpacityEffect(_overButton);
|
|
_opacityEffect->setOpacity(1);
|
|
_overButton->setGraphicsEffect(_opacityEffect);
|
|
_overButton->move(0, 0);
|
|
_overButton->setLightDefaultColor(ElaThemeColor(ElaThemeType::Light, PrimaryNormal));
|
|
_overButton->setLightHoverColor(ElaThemeColor(ElaThemeType::Light, PrimaryHover));
|
|
_overButton->setLightPressColor(ElaThemeColor(ElaThemeType::Light, PrimaryPress));
|
|
_overButton->setLightTextColor(Qt::white);
|
|
_overButton->setDarkDefaultColor(ElaThemeColor(ElaThemeType::Dark, PrimaryNormal));
|
|
_overButton->setDarkHoverColor(ElaThemeColor(ElaThemeType::Dark, PrimaryHover));
|
|
_overButton->setDarkPressColor(ElaThemeColor(ElaThemeType::Dark, PrimaryPress));
|
|
_overButton->setDarkTextColor(Qt::white);
|
|
_overButton->setMinimumSize(0, 0);
|
|
_overButton->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
|
|
connect(_overButton, &ElaPushButton::clicked, _card, &ElaPopularCard::popularCardButtonClicked);
|
|
|
|
_themeMode = eTheme->getThemeMode();
|
|
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
|
|
setVisible(false);
|
|
}
|
|
|
|
ElaPopularCardFloater::~ElaPopularCardFloater() {}
|
|
|
|
void ElaPopularCardFloater::showFloater() {
|
|
_isHideAnimationFinished = true;
|
|
_pHoverYOffset = 6;
|
|
_pHoverOpacity = 1;
|
|
_opacityEffect->setOpacity(1);
|
|
|
|
QPropertyAnimation *geometryAnimation = new QPropertyAnimation(this, "geometry");
|
|
connect(geometryAnimation, &QPropertyAnimation::valueChanged, this, [=]() { update(); });
|
|
geometryAnimation->setEasingCurve(QEasingCurve::OutQuad);
|
|
geometryAnimation->setDuration(300);
|
|
QRect cardGeometry = QRect(_card->mapTo(_cardPrivate->_pCardFloatArea, QPoint(0, 0)), _card->size());
|
|
QRect endGeometry = _calculateTargetGeometry(cardGeometry);
|
|
QRect startGeometry = QRect(endGeometry.x() + _floatGeometryOffset, endGeometry.y() + _floatGeometryOffset, _card->width(), _card->height());
|
|
geometryAnimation->setStartValue(startGeometry);
|
|
geometryAnimation->setEndValue(endGeometry);
|
|
geometryAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
|
|
// Button动画
|
|
QPropertyAnimation *buttonAnimation = new QPropertyAnimation(_overButton, "geometry");
|
|
buttonAnimation->setEasingCurve(QEasingCurve::OutQuad);
|
|
buttonAnimation->setDuration(300);
|
|
buttonAnimation->setStartValue(_cardPrivate->_interactiveTipsBaseRect);
|
|
buttonAnimation->setEndValue(_cardPrivate->_buttonTargetRect);
|
|
buttonAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
setVisible(true);
|
|
}
|
|
|
|
void ElaPopularCardFloater::hideFloater() {
|
|
if (!_isHideAnimationFinished) {
|
|
return;
|
|
}
|
|
_isHideAnimationFinished = false;
|
|
QPropertyAnimation *geometryAnimation = new QPropertyAnimation(this, "geometry");
|
|
connect(geometryAnimation, &QPropertyAnimation::valueChanged, this, [=]() {
|
|
QRect endGeometry = QRect(_card->mapTo(_cardPrivate->_pCardFloatArea, QPoint(0, 0)), _card->size());
|
|
geometryAnimation->setEndValue(endGeometry);
|
|
});
|
|
connect(geometryAnimation, &QPropertyAnimation::finished, this, [=]() {
|
|
_cardPrivate->_isFloating = false;
|
|
setVisible(false);
|
|
_card->update();
|
|
});
|
|
geometryAnimation->setEasingCurve(QEasingCurve::InOutSine);
|
|
geometryAnimation->setDuration(300);
|
|
QRect endGeometry = QRect(_card->mapTo(_cardPrivate->_pCardFloatArea, QPoint(0, 0)), _card->size());
|
|
geometryAnimation->setStartValue(geometry());
|
|
geometryAnimation->setEndValue(endGeometry);
|
|
geometryAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
|
|
QPropertyAnimation *opacityAnimation = new QPropertyAnimation(this, "pHoverOpacity");
|
|
opacityAnimation->setDuration(300);
|
|
opacityAnimation->setStartValue(_pHoverOpacity);
|
|
opacityAnimation->setEndValue(0);
|
|
opacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
|
|
// 内容调整动画
|
|
QPropertyAnimation *hoverAnimation = new QPropertyAnimation(this, "pHoverYOffset");
|
|
connect(hoverAnimation, &QPropertyAnimation::valueChanged, this, [=]() { update(); });
|
|
hoverAnimation->setDuration(300);
|
|
hoverAnimation->setStartValue(_pHoverYOffset);
|
|
hoverAnimation->setEndValue(0);
|
|
hoverAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
|
|
// Button动画
|
|
QPropertyAnimation *buttonAnimation = new QPropertyAnimation(_overButton, "geometry");
|
|
buttonAnimation->setEasingCurve(QEasingCurve::InOutSine);
|
|
buttonAnimation->setDuration(300);
|
|
buttonAnimation->setStartValue(_overButton->geometry());
|
|
QRectF endRect = _cardPrivate->_interactiveTipsBaseRect;
|
|
endRect.adjust(0, 6, 0, 6);
|
|
buttonAnimation->setEndValue(endRect);
|
|
buttonAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
|
|
QPropertyAnimation *buttonOpacityAnimation = new QPropertyAnimation(_overButton->graphicsEffect(), "opacity");
|
|
buttonOpacityAnimation->setEasingCurve(QEasingCurve::InOutSine);
|
|
buttonOpacityAnimation->setDuration(350);
|
|
buttonOpacityAnimation->setStartValue(1);
|
|
buttonOpacityAnimation->setEndValue(0);
|
|
buttonOpacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
}
|
|
|
|
bool ElaPopularCardFloater::event(QEvent *event) {
|
|
switch (event->type()) {
|
|
case QEvent::Leave: {
|
|
hideFloater();
|
|
break;
|
|
}
|
|
case QEvent::MouseButtonRelease: {
|
|
Q_EMIT _card->popularCardClicked();
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
return QWidget::event(event);
|
|
}
|
|
|
|
void ElaPopularCardFloater::paintEvent(QPaintEvent *event) {
|
|
QPainter painter(this);
|
|
painter.save();
|
|
painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing | QPainter::TextAntialiasing);
|
|
// 阴影绘制
|
|
painter.setOpacity(_pHoverOpacity);
|
|
QRect shadowRect = rect();
|
|
shadowRect.adjust(0, 0, 0, -_pHoverYOffset);
|
|
eTheme->drawEffectShadow(&painter, shadowRect, _cardPrivate->_shadowBorderWidth, _cardPrivate->_pBorderRadius);
|
|
QRectF foregroundRect(_cardPrivate->_shadowBorderWidth, _cardPrivate->_shadowBorderWidth - _pHoverYOffset + 1,
|
|
width() - 2 * _cardPrivate->_shadowBorderWidth, height() - 2 * _cardPrivate->_shadowBorderWidth);
|
|
QRectF cardForegroundRect(_cardPrivate->_shadowBorderWidth, _cardPrivate->_shadowBorderWidth - _cardPrivate->_pHoverYOffset + 1,
|
|
_card->width() - 2 * _cardPrivate->_shadowBorderWidth, _card->height() - 2 * _cardPrivate->_shadowBorderWidth);
|
|
|
|
// 背景绘制
|
|
painter.setOpacity(1);
|
|
painter.setPen(ElaThemeColor(_themeMode, PopupBorderHover));
|
|
painter.setBrush(ElaThemeColor(_themeMode, DialogBase));
|
|
painter.drawRoundedRect(foregroundRect, _cardPrivate->_pBorderRadius, _cardPrivate->_pBorderRadius);
|
|
painter.setClipRect(foregroundRect);
|
|
// 图片绘制
|
|
painter.save();
|
|
QRectF pixRect(foregroundRect.x() + cardForegroundRect.height() * 0.15, foregroundRect.y() + cardForegroundRect.height() * 0.15,
|
|
cardForegroundRect.height() * 0.7, cardForegroundRect.height() * 0.7);
|
|
|
|
QPainterPath pixPath;
|
|
pixPath.addRoundedRect(pixRect, 4, 4);
|
|
painter.setClipPath(pixPath);
|
|
painter.drawPixmap(pixRect, _cardPrivate->_pCardPixmap, _cardPrivate->_pCardPixmap.rect());
|
|
painter.restore();
|
|
|
|
// 文字绘制
|
|
// Title
|
|
painter.setPen(ElaThemeColor(_themeMode, BasicText));
|
|
QFont font = painter.font();
|
|
font.setWeight(QFont::Bold);
|
|
font.setPixelSize(15);
|
|
painter.setFont(font);
|
|
int titleHeight = painter.fontMetrics().height();
|
|
QRectF titleRect(pixRect.right() + _cardPrivate->_textHSpacing, pixRect.y(),
|
|
_floatGeometryOffset * 2 + cardForegroundRect.width() - pixRect.width() - _cardPrivate->_textHSpacing * 2 -
|
|
cardForegroundRect.height() * 0.15 - _cardPrivate->_buttonTargetRect.width(),
|
|
titleHeight);
|
|
QString titleText = painter.fontMetrics().elidedText(_cardPrivate->_pTitle, Qt::ElideRight, titleRect.width());
|
|
painter.drawText(titleRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, titleText);
|
|
|
|
// SubTitle
|
|
font.setWeight(QFont::DemiBold);
|
|
font.setPixelSize(13);
|
|
painter.setFont(font);
|
|
int subTitleHeight = painter.fontMetrics().height();
|
|
QRectF subTitleRect(pixRect.right() + _cardPrivate->_textHSpacing, titleRect.bottom() + _cardPrivate->_textVSpacing,
|
|
_floatGeometryOffset * 2 + cardForegroundRect.width() - pixRect.width() - _cardPrivate->_textHSpacing * 2 -
|
|
cardForegroundRect.height() * 0.15 - _cardPrivate->_buttonTargetRect.width(),
|
|
subTitleHeight);
|
|
QString subTitleText = painter.fontMetrics().elidedText(_cardPrivate->_pSubTitle, Qt::ElideRight, subTitleRect.width());
|
|
painter.drawText(subTitleRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, subTitleText);
|
|
|
|
// DetailedText
|
|
painter.setPen(ElaThemeColor(_themeMode, BasicDetailsText));
|
|
int detailedTextHeight = painter.fontMetrics().height() * 2 + 2;
|
|
QRectF detailedTextRect(pixRect.x(), pixRect.bottom() + cardForegroundRect.height() * 0.15,
|
|
cardForegroundRect.width() + 2 * _floatGeometryOffset - _cardPrivate->_textHSpacing - cardForegroundRect.height() * 0.15,
|
|
detailedTextHeight);
|
|
QString detailedText = painter.fontMetrics().elidedText(_cardPrivate->_pDetailedText, Qt::ElideRight, detailedTextRect.width() * 1.9);
|
|
painter.drawText(detailedTextRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, detailedText);
|
|
|
|
// 分割线绘制
|
|
painter.setPen(ElaThemeColor(_themeMode, BasicBaseLine));
|
|
painter.drawLine(foregroundRect.x(), detailedTextRect.bottom() + 5, foregroundRect.right(), detailedTextRect.bottom() + 5);
|
|
|
|
// CardFloatPixmap
|
|
painter.drawPixmap(
|
|
QRect(pixRect.x(), detailedTextRect.bottom() + 15,
|
|
cardForegroundRect.bottom() + _floatGeometryOffset + 90 - detailedTextRect.bottom() - 15 - _cardPrivate->_shadowBorderWidth - 10,
|
|
cardForegroundRect.bottom() + _floatGeometryOffset + 90 - detailedTextRect.bottom() - 15 - _cardPrivate->_shadowBorderWidth - 10),
|
|
_cardPrivate->_pCardFloatPixmap);
|
|
painter.restore();
|
|
}
|
|
|
|
QRect ElaPopularCardFloater::_calculateTargetGeometry(QRect cardGeometry) {
|
|
QRect targetGeometry = cardGeometry;
|
|
targetGeometry.adjust(-_floatGeometryOffset, -_floatGeometryOffset, _floatGeometryOffset, 90);
|
|
QRect windowRect = _cardPrivate->_pCardFloatArea->rect();
|
|
if (targetGeometry.bottom() > windowRect.bottom()) {
|
|
int offset = targetGeometry.bottom() - windowRect.bottom();
|
|
targetGeometry.adjust(0, -offset, 0, -offset);
|
|
}
|
|
if (targetGeometry.top() < windowRect.top()) {
|
|
int offset = targetGeometry.top() - windowRect.top();
|
|
targetGeometry.adjust(0, -offset, 0, -offset);
|
|
}
|
|
return targetGeometry;
|
|
}
|