#include #include #include #include #include #include #include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) #include #endif // QT 5.15 #include "popup.h" class PopupLabel : public QLabel { public: PopupLabel(const QString &text, QWidget *parent = 0); ~PopupLabel(); bool eventFilter(QObject *o, QEvent *ev); void place(const QPoint &pos, QWidget *w); void deleteAfterTimer(); void stopTimer() {_timer.stop();} static PopupLabel *_instance; protected: void paintEvent(QPaintEvent *event); void timerEvent(QTimerEvent *event); void contextMenuEvent(QContextMenuEvent *) {} private: QBasicTimer _timer; }; PopupLabel *PopupLabel::_instance = 0; PopupLabel::PopupLabel(const QString &text, QWidget *parent) : QLabel(text, parent, Qt::ToolTip | Qt::BypassGraphicsProxyWidget | Qt::WindowDoesNotAcceptFocus) { delete _instance; _instance = this; setForegroundRole(QPalette::ToolTipText); setBackgroundRole(QPalette::ToolTipBase); setPalette(QToolTip::palette()); ensurePolished(); setMargin(1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0, this)); setFrameStyle(QFrame::NoFrame); setAlignment(Qt::AlignLeft); setIndent(1); setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0); setTextInteractionFlags(Qt::TextBrowserInteraction); setOpenExternalLinks(true); setWordWrap(true); setMouseTracking(true); qApp->installEventFilter(this); } PopupLabel::~PopupLabel() { _instance = 0; } void PopupLabel::paintEvent(QPaintEvent *event) { QStylePainter p(this); QStyleOptionFrame opt; opt.initFrom(this); p.drawPrimitive(QStyle::PE_PanelTipLabel, opt); p.end(); QLabel::paintEvent(event); } void PopupLabel::timerEvent(QTimerEvent *event) { if (event->timerId() == _timer.timerId()) { _timer.stop(); deleteLater(); } } bool PopupLabel::eventFilter(QObject *o, QEvent *ev) { Q_UNUSED(o); switch (ev->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: { const int key = static_cast(ev)->key(); if (key == Qt::Key_Escape) { deleteLater(); return true; } break; } case QEvent::FocusIn: case QEvent::FocusOut: case QEvent::WindowActivate: case QEvent::WindowDeactivate: case QEvent::Close: deleteLater(); break; case QEvent::MouseMove: { QRectF r(geometry().adjusted(-5, -20, 5, 20)); QPointF p(static_cast(ev)->globalPos()); if (!r.contains(p)) deleteAfterTimer(); break; } default: break; } return false; } void PopupLabel::place(const QPoint &pos, QWidget *w) { #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) QRect screen = QApplication::desktop()->screenGeometry(w); #else // QT 5.15 QRect screen = w->screen()->geometry(); #endif // QT 5.15 QPoint p(pos.x() + 2, pos.y() + 16); if (p.x() + width() > screen.x() + screen.width()) p.rx() -= 4 + width(); if (p.y() + height() > screen.y() + screen.height()) p.ry() -= 24 + height(); if (p.y() < screen.y()) p.setY(screen.y()); if (p.x() + width() > screen.x() + screen.width()) p.setX(screen.x() + screen.width() - width()); if (p.x() < screen.x()) p.setX(screen.x()); if (p.y() + height() > screen.y() + screen.height()) p.setY(screen.y() + screen.height() - height()); this->move(p); } void PopupLabel::deleteAfterTimer() { if (!_timer.isActive()) _timer.start(300, this); } void Popup::show(const QPoint &pos, const QString &text, QWidget *w) { if (PopupLabel::_instance) { PopupLabel::_instance->stopTimer(); PopupLabel::_instance->setText(text); } else PopupLabel::_instance = new PopupLabel(text); PopupLabel::_instance->resize(PopupLabel::_instance->sizeHint()); PopupLabel::_instance->place(pos, w); PopupLabel::_instance->showNormal(); } void Popup::clear() { if (PopupLabel::_instance) delete PopupLabel::_instance; }