#include "message.h"
#include <QPainter>
#include <QStyleOption>
#include <QGraphicsOpacityEffect>
#include <QSequentialAnimationGroup>
#include <algorithm>
static int nMessageItemMargin = 20;
static Message *s_instance_ = 0;
Message *Message::instance()
{
return s_instance_;
}
Message::Message(QObject *parent) : QObject(parent)
{
if (parent == nullptr)
throw std::runtime_error("message structure error!");
auto widget = qobject_cast<QWidget *>(parent);
if (widget == nullptr) {
throw std::runtime_error("message structure error!");
}
width_ = widget->width();
duration_ = 3000;
messages_.reserve(50);
s_instance_ = this;
}
Message::Message(int duration, QObject *parent) : duration_(duration)
{
if (parent == nullptr)
throw std::runtime_error("message structure error!");
auto widget = qobject_cast<QWidget *>(parent);
if (widget == nullptr) {
throw std::runtime_error("message structure error!");
}
width_ = widget->width();
if (duration_ < 0)
duration_ = 0;
messages_.reserve(50);
}
Message::~Message()
{
}
void Message::Push(MessageType type, QString content)
{
std::unique_lock<std::mutex> lck(mtx_);
int height = 0;
for_each(messages_.begin(), messages_.end(),
[&height](MessageItem *pTp) mutable {
height += (nMessageItemMargin + pTp->height());
});
MessageItem *pItem =
new MessageItem(qobject_cast<QWidget *>(parent()), type, content);
connect(pItem, &MessageItem::itemReadyRemoved, this,
&Message::adjustItemPos);
connect(pItem, &MessageItem::itemRemoved, this, &Message::removeItem);
pItem->SetDuration(duration_);
height += nMessageItemMargin;
pItem->move(QPoint((width_ - pItem->width()) / 2, height));
messages_.emplace_back(pItem);
pItem->Show();
}
void Message::setDuration(int nDuration)
{
if (nDuration < 0)
nDuration = 0;
duration_ = nDuration;
}
void Message::adjustItemPos(MessageItem *pItem)
{
pItem->Close();
}
void Message::removeItem(MessageItem *pItem)
{
std::unique_lock<std::mutex> lck(mtx_);
for (auto itr = messages_.begin(); itr != messages_.end();) {
if (*itr == pItem) {
messages_.erase(itr);
break;
} else
++itr;
}
int height = nMessageItemMargin;
for_each(messages_.begin(), messages_.end(), [&](MessageItem *item) {
QPropertyAnimation *pAnimation1 =
new QPropertyAnimation(item, "geometry", this);
pAnimation1->setDuration(300);
pAnimation1->setStartValue(QRect(item->pos().x(), item->pos().y(),
item->width(), item->height()));
pAnimation1->setEndValue(
QRect(item->pos().x(), height, item->width(), item->height()));
pAnimation1->start(
QAbstractAnimation::DeletionPolicy::DeleteWhenStopped);
height += (nMessageItemMargin + item->height());
});
}
MessageItem::MessageItem(QWidget *parent, MessageType type,
const QString content, const int duration,
const int iconMargin, const int leftMargin,
const int topMargin, const int minWidth,
const int minHeight)
: QWidget(parent), duration_(duration)
{
setObjectName(QStringLiteral("message_item"));
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
pLabelIcon_ = new QLabel(this);
if (type == MessageType::MESSAGE_TYPE_SUCCESS) {
setStyleSheet(QStringLiteral(
"QWidget#message_item{border:1px solid "
"#E1F3D8;background-color:rgb(240,249,235);border-radius:4px;}"
"QLabel{border:none;background-color:rgb(240,249,235);font-family:"
"Microsoft "
"Yahei;font-size:16px;font-weight:400;color:rgb(103,194,58);}"));
pLabelIcon_->setPixmap(
QPixmap(":/image/resource/image/message/type_success.png"));
} else if (type == MessageType::MESSAGE_TYPE_ERROR) {
setStyleSheet(QStringLiteral(
"QWidget#message_item{border:1px solid "
"#FDE2E2;background-color:#FEF0F0;border-radius:4px;}"
"QLabel{border:none;background-color:#FEF0F0;font-family:Microsoft "
"Yahei;font-size:16px;font-weight:400;color:rgb(245,108,108);}"));
pLabelIcon_->setPixmap(
QPixmap(":/image/resource/image/message/type_error.png"));
} else if (type == MessageType::MESSAGE_TYPE_WARNING) {
setStyleSheet(QStringLiteral(
"QWidget#message_item{border:1px solid "
"#FAECD8;background-color:#FDF6EC;border-radius:4px;}"
"QLabel{border:none;background-color:#FDF6EC;font-family:Microsoft "
"Yahei;font-size:16px;font-weight:400;color:rgb(230,162,60);}"));
pLabelIcon_->setPixmap(
QPixmap(":/image/resource/image/message/type_warning.png"));
} else {
setStyleSheet(QStringLiteral(
"QWidget#message_item{border:1px solid "
"#EBEEF5;background-color:#EDF2FC;border-radius:4px;}"
"QLabel{border:none;background-color:#EDF2FC;font-family:Microsoft "
"Yahei;font-size:16px;font-weight:400;color:rgb(144,147,153);}"));
pLabelIcon_->setPixmap(
QPixmap(":/image/resource/image/message/type_infomation.png"));
}
pLabelContent_ = new QLabel(this);
pLabelContent_->setText(content);
pLabelContent_->adjustSize();
width_ = pLabelContent_->width() + leftMargin * 2;
height_ = pLabelContent_->height() + topMargin * 2;
if (width_ < minWidth)
width_ = minWidth;
if (height_ < minHeight)
height_ = minHeight;
resize(width_, height_);
pLabelContent_->move(leftMargin, (height_ - pLabelContent_->height()) / 2);
pLabelIcon_->move(iconMargin, (height_ - pLabelIcon_->height()) / 2);
connect(&lifeTimer_, &QTimer::timeout, this, [&]() {
lifeTimer_.stop();
emit itemReadyRemoved(this);
});
hide();
}
MessageItem::~MessageItem()
{
delete pLabelIcon_;
delete pLabelContent_;
}
void MessageItem::Show()
{
show();
if (duration_ > 0)
lifeTimer_.start(duration_);
AppearAnimation();
}
void MessageItem::Close()
{
DisappearAnimation();
}
void MessageItem::SetDuration(int nDuration)
{
duration_ = nDuration;
}
void MessageItem::paintEvent(QPaintEvent *event)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QWidget::paintEvent(event);
}
void MessageItem::AppearAnimation()
{
QPropertyAnimation *animation = new QPropertyAnimation(this, "geometry");
animation->setDuration(20);
animation->setStartValue(
QRect(pos().x(), pos().y() - nMessageItemMargin, width_, height_));
animation->setEndValue(QRect(pos().x(), pos().y(), width_, height_));
animation->start(QAbstractAnimation::DeletionPolicy::DeleteWhenStopped);
}
void MessageItem::DisappearAnimation()
{
QGraphicsOpacityEffect *pOpacity = new QGraphicsOpacityEffect(this);
pOpacity->setOpacity(1);
setGraphicsEffect(pOpacity);
QPropertyAnimation *pOpacityAnimation2 =
new QPropertyAnimation(pOpacity, "opacity");
pOpacityAnimation2->setDuration(500);
pOpacityAnimation2->setStartValue(1);
pOpacityAnimation2->setEndValue(0);
pOpacityAnimation2->start(
QAbstractAnimation::DeletionPolicy::DeleteWhenStopped);
connect(pOpacityAnimation2, &QPropertyAnimation::finished, this, [&]() {
emit itemRemoved(this);
deleteLater();
});
}