123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- #include "../PaintHelper/painthelper.h"
- #include "globalmsgmgr.h"
- #include <QPainter>
- #include <QTimer>
- #include <QDebug>
- GlobalMsgMgr::GlobalMsgMgrGarbo GlobalMsgMgr::garbo;
- GlobalMsgMgr* GlobalMsgMgr::sm_pInstance = new GlobalMsgMgr(nullptr); //初始化静态单例(饿汉):
- const int g_nSpacing = 20; //弹出消息的间距
- const int g_nFlyDistance = 60; //飞入飞出的距离
- //const QSize g_sizeWeakHint = QSize(380,48); //弱提示的尺寸(对应窗口的高度还要加上飞入飞出的距离)
- const int g_nWeakHintHeight = 48; //弱提示的高度(对应窗口的高度还要加上飞入飞出的距离)
- const int g_nSpeed = 3; //每update间隔时间里移动的像素
- const int g_nUpdateInterval = 10; //update间隔时间
- const int g_nPaddingTop = 20; //距离上方的高度
- const int g_nTextPaddingL = 60; //文本左间距
- const int g_nTextPaddingR = 24; //文本右间距
- GlobalMsgWidget::GlobalMsgWidget(const QString &msg, HintMode mode, QWidget *parent)
- : QWidget(parent)
- , m_mode(mode)
- , m_strMsg(msg)
- {
- setAttribute(Qt::WA_TransparentForMouseEvents);
- setAttribute(Qt::WA_TranslucentBackground);
- setWindowFlag(Qt::FramelessWindowHint);
- QFontMetrics fMetrics(FontEx(fontInfo().family(), 14));
- QSize textSize = fMetrics.size(Qt::TextSingleLine, msg);
- int width = qBound(380, g_nTextPaddingL + g_nTextPaddingR + textSize.width(), 800);
-
- m_strMsg = fMetrics.elidedText(msg, Qt::ElideRight, width - g_nTextPaddingL - g_nTextPaddingR);
-
- resize(QSize(width, g_nWeakHintHeight + g_nFlyDistance));
-
- m_animFlyInOut.setDuration(g_nFlyDistance/g_nSpeed*g_nUpdateInterval);
- m_animFlyInOut.setStartValue(0);
- m_animFlyInOut.setEndValue(g_nFlyDistance);
- connect(&m_animFlyInOut, &QVariantAnimation::valueChanged, [&](const QVariant &){update();});
- connect(&m_animFlyInOut, &QVariantAnimation::finished, [&](){
- if(m_animFlyInOut.direction() == QVariantAnimation::Backward) deleteLater();
- });
-
- m_animFlyInOut.start();
- m_dtStart = QDateTime::currentDateTime();
- connect(&m_timerCheckIfStay, &QTimer::timeout, this, &GlobalMsgWidget::CheckIfStay);
- m_timerCheckIfStay.start(10);
- }
- void GlobalMsgWidget::CheckIfStay()
- {
- QPoint cursorPos = mapFromGlobal(QCursor::pos());
- QRect rectContent(0,m_animFlyInOut.currentValue().toInt(),width(),40);
- if(rectContent.contains(cursorPos))
- {
- m_dtStart = QDateTime::currentDateTime();
- return;
- }
- if(m_dtStart.msecsTo(QDateTime::currentDateTime()) >= 3000)
- {
- m_animFlyInOut.setDirection(QVariantAnimation::Backward);
- m_animFlyInOut.start();
- m_timerCheckIfStay.stop();
- emit sig_Hide(this);
- }
- }
- QColor GlobalMsgWidget::GetBGColor(HintMode mode, int alpha)
- {
- if(mode == Success) return QColor(240,249,235,alpha);
- if(mode == Warn) return QColor(253,246,236,alpha);
- if(mode == Normal) return QColor(237,242,252,alpha);
- if(mode == Error) return QColor(254,240,240,alpha);
- return QColor(30,30,30,alpha);
- }
- QColor GlobalMsgWidget::GetTextColor(HintMode mode, int alpha)
- {
- if(mode == Success) return QColor(103,194,58,alpha);
- if(mode == Warn) return QColor(230,162,60,alpha);
- if(mode == Normal) return QColor(144,147,153,alpha);
- if(mode == Error) return QColor(245,108,108,alpha);
- return QColor(30,30,30,alpha);
- }
- QString GlobalMsgWidget::GetIconPath(HintMode mode)
- {
- if(mode == Success) return QString(":/GlobalMsg/success.png");
- if(mode == Warn) return QString(":/GlobalMsg/warn.png");
- if(mode == Normal) return QString(":/GlobalMsg/normal.png");
- if(mode == Error) return QString(":/GlobalMsg/error.png");
- return QString(":/GlobalMsg/normal.png");
- }
- void GlobalMsgWidget::paintEvent(QPaintEvent *)
- {
- PainterEx painter(this);
-
- QRect rectContent(0,m_animFlyInOut.currentValue().toInt(),width(),g_nWeakHintHeight);
-
- double startValue = m_animFlyInOut.startValue().toDouble();
- double endValue = m_animFlyInOut.endValue().toDouble();
- double curValue = m_animFlyInOut.currentValue().toDouble();
-
- int alpha = qRound((curValue - startValue)/(endValue - startValue) * 255);
- {//底色
- painter.DrawRoundedRect(rectContent, 4, GetBGColor(m_mode,alpha));
- }
- {//图标
- QRect iconRect(rectContent.topLeft()+QPoint(28,14), QSize(20,20));
- painter.DrawPixmap(iconRect, GetIconPath(m_mode), alpha);
- }
- {//文字
- QRect textRect(g_nTextPaddingL, rectContent.top(), width() - g_nTextPaddingL - g_nTextPaddingR, g_nWeakHintHeight);
- painter.setFont(FontEx(painter.fontInfo().family(), 14));
- painter.DrawText(textRect, m_strMsg, GetTextColor(m_mode,alpha), Qt::AlignLeft|Qt::AlignVCenter);
- }
- }
- GlobalMsgMgr::GlobalMsgMgr(QObject *parent)
- : QObject(parent)
- , m_pRootWidget(nullptr)
- {
- connect(&m_timerUpdate, &QTimer::timeout, this, &GlobalMsgMgr::OnUpdate);
- }
- void GlobalMsgMgr::SetRootWidget(QWidget *rootWidget)
- {
- m_pRootWidget = rootWidget;
- }
- void GlobalMsgMgr::Popup(const QString &msg, GlobalMsgWidget::HintMode mode)
- {
- //动画思路:单个消息窗, 飞入飞出+淡入淡出; 多个消息窗, 单个本身动画不变, 多个组成队列
- //某个消息窗开始飞出时, 它后面的所有消息窗同时上移
- //新消息窗飞入时, 从头部位置飞入; 头部位置随着[新消息飞入]和[所有窗口同时上移]而改变, [新消息飞入]则加一个单位, [所有窗口同时上移]则减一个单位
- //单个消息窗的[飞入飞出+淡入淡出]用paintevent实现; [所有窗口同时上移]在OnUpdate实现
-
- if(m_pRootWidget == nullptr) return;
- GlobalMsgWidget *weakWidget = new GlobalMsgWidget(msg, mode);
- connect(weakWidget, &GlobalMsgWidget::sig_Hide, this, &GlobalMsgMgr::OnWeakHintHide);
- weakWidget->setWindowFlag(Qt::ToolTip);
- weakWidget->setParent(m_pRootWidget);
- int x = (m_pRootWidget->width()-weakWidget->width())/2;
- int offset = m_listWeakHints.count()*(g_nSpacing + g_nWeakHintHeight);
- weakWidget->move(x, offset - g_nFlyDistance + g_nPaddingTop);
- weakWidget->show();
- m_listWeakHints.append(weakWidget);
- if(!m_timerUpdate.isActive()) m_timerUpdate.start(g_nUpdateInterval);
- }
- void GlobalMsgMgr::Popup(const QString &msg, QWidget *parentWidget, GlobalMsgWidget::HintMode mode)
- {
- //动画思路:单个消息窗, 飞入飞出+淡入淡出; 多个消息窗, 单个本身动画不变, 多个组成队列
- //某个消息窗开始飞出时, 它后面的所有消息窗同时上移
- //新消息窗飞入时, 从头部位置飞入; 头部位置随着[新消息飞入]和[所有窗口同时上移]而改变, [新消息飞入]则加一个单位, [所有窗口同时上移]则减一个单位
- //单个消息窗的[飞入飞出+淡入淡出]用paintevent实现; [所有窗口同时上移]在OnUpdate实现
- if(parentWidget == nullptr) return;
- GlobalMsgWidget *weakWidget = new GlobalMsgWidget(msg, mode);
- connect(weakWidget, &GlobalMsgWidget::sig_Hide, this, &GlobalMsgMgr::OnWeakHintHide);
- weakWidget->setWindowFlag(Qt::ToolTip);
- weakWidget->setParent(parentWidget);
- int x = (parentWidget->width()-weakWidget->width())/2;
- int offset = m_listWeakHints.count()*(g_nSpacing + g_nWeakHintHeight);
- weakWidget->move(x, offset - g_nFlyDistance + g_nPaddingTop);
- weakWidget->show();
- m_listWeakHints.append(weakWidget);
- if(!m_timerUpdate.isActive()) m_timerUpdate.start(g_nUpdateInterval);
- }
- void GlobalMsgMgr::Clear(QWidget *parentWidget)
- {
- for(auto weakHint=m_listWeakHints.begin();weakHint!=m_listWeakHints.end();){
- if((*weakHint)->parent() == parentWidget)
- weakHint = m_listWeakHints.erase(weakHint);
- else
- ++weakHint;
- }
- }
- void GlobalMsgMgr::OnUpdate()
- {
- for(GlobalMsgWidget* weakHint: m_listWeakHints)
- {
- int offset = m_listWeakHints.indexOf(weakHint)*(g_nSpacing + g_nWeakHintHeight);
- int targetPosY = offset - g_nFlyDistance + g_nPaddingTop;
- QPoint curPos = weakHint->pos();
- if(curPos.y() == targetPosY) continue;
- if(targetPosY > curPos.y())
- {
- int newPosY = qMin(curPos.y()+g_nSpeed, targetPosY);
- QPoint newPos = QPoint(curPos.x(), newPosY);
- weakHint->move(newPos);
- }
- if(targetPosY < curPos.y())
- {
- int newPosY = qMax(curPos.y()-g_nSpeed, targetPosY);
- QPoint newPos = QPoint(curPos.x(), newPosY);
- weakHint->move(newPos);
- }
- }
- }
- void GlobalMsgMgr::OnWeakHintHide(GlobalMsgWidget* pWeakHint)
- {
- if(m_listWeakHints.contains(pWeakHint)) m_listWeakHints.removeOne(pWeakHint);
- }
|