#include "qballoontip.h" #include "iDescriptor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include void QBalloonTip::toggleBaloon(const QPoint &pos, int timeout, bool forceVisible) { if (m_visible && !forceVisible) { hideBalloon(); return; } if (timeout < 0) timeout = 10000; // 10 s default balloon(pos, timeout); } void QBalloonTip::hideBalloon() { m_visible = false; hide(); } void QBalloonTip::updateBalloonPosition(const QPoint &pos) { hideBalloon(); balloon(pos, 0); } bool QBalloonTip::isBalloonVisible() { return m_visible; } QBalloonTip::QBalloonTip(QWidget *widget) : QWidget(widget ? widget->window() : QApplication::activeWindow(), Qt::ToolTip), widget(widget) { // setAttribute(Qt::WA_DeleteOnClose); // setAttribute(Qt::WA_TranslucentBackground); if (widget) { connect(widget, &QWidget::destroyed, this, &QBalloonTip::close); } else if (QApplication::activeWindow()) { connect(QApplication::activeWindow(), &QWidget::destroyed, this, &QBalloonTip::close); } // Add drop shadow effect // QGraphicsDropShadowEffect *shadowEffect = // new QGraphicsDropShadowEffect(this); // shadowEffect->setBlurRadius(200); // shadowEffect->setColor(QColor(0, 0, 0, 80)); // shadowEffect->setOffset(0, 5); // setGraphicsEffect(shadowEffect); // QLabel *titleLabel = new QLabel; // titleLabel->installEventFilter(this); // titleLabel->setText(title); // QFont f = titleLabel->font(); // f.setBold(true); // titleLabel->setFont(f); // titleLabel->setTextFormat(Qt::PlainText); // to maintain compat with // windows // const int iconSize = 18; // const int closeButtonSize = 15; // QPushButton *closeButton = new QPushButton; // closeButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton)); // closeButton->setIconSize(QSize(closeButtonSize, closeButtonSize)); // closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // closeButton->setFixedSize(closeButtonSize, closeButtonSize); // QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); // QLabel *msgLabel = new QLabel; // msgLabel->installEventFilter(this); // msgLabel->setText(message); // msgLabel->setTextFormat(Qt::PlainText); // msgLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft); // QGridLayout *layout = new QGridLayout; // if (!icon.isNull()) { // QLabel *iconLabel = new QLabel; // iconLabel->setPixmap( // icon.pixmap(QSize(iconSize, iconSize), devicePixelRatio())); // iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // iconLabel->setMargin(2); // layout->addWidget(iconLabel, 0, 0); // layout->addWidget(titleLabel, 0, 1); // } else { // layout->addWidget(titleLabel, 0, 0, 1, 2); // } // layout->addWidget(closeButton, 0, 2); // layout->addWidget(msgLabel, 1, 0, 1, 3); // layout->setSizeConstraint(QLayout::SetFixedSize); // layout->setContentsMargins(3, 3, 3, 3); // setLayout(layout); } QBalloonTip::~QBalloonTip() {} void QBalloonTip::paintEvent(QPaintEvent *ev) { // QPainter painter(this); // painter.drawPixmap(rect(), pixmap); QWidget::paintEvent(ev); } void QBalloonTip::resizeEvent(QResizeEvent *ev) { QWidget::resizeEvent(ev); } void QBalloonTip::balloon(const QPoint &pos, int msecs) { m_visible = true; qApp->installEventFilter(this); QScreen *screen = QGuiApplication::screenAt(pos); if (!screen) { screen = QGuiApplication::primaryScreen(); } QRect screenRect = screen->availableGeometry(); // Ensure layout is up to date so we get the correct size ensurePolished(); adjustSize(); QSize balloonSize = size(); if (!balloonSize.isValid() || balloonSize.isEmpty()) { balloonSize = sizeHint(); } // Arrow dimensions const int arrowGap = 40; // gap between balloon and anchor const int margin = 5; // margin from screen edges // Calculate horizontal position - center on the anchor point int balloonX = pos.x() - balloonSize.width() / 2; // Clamp to screen bounds with margin balloonX = qBound(screenRect.left() + margin, balloonX, screenRect.right() - balloonSize.width() - margin); // Calculate vertical position - prefer above the anchor point int balloonY; int spaceAbove = pos.y() - screenRect.top(); if (spaceAbove >= balloonSize.height() + arrowGap + margin) { // Show above the anchor point (preferred) balloonY = pos.y() - balloonSize.height() - arrowGap; } else { // Not enough space above, show below balloonY = pos.y() + arrowGap; } balloonY = qBound(screenRect.top() + margin, balloonY, screenRect.bottom() - balloonSize.height() - margin); setGeometry(balloonX, balloonY, balloonSize.width(), balloonSize.height()); show(); raise(); activateWindow(); } void QBalloonTip::mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) { emit messageClicked(); } } void QBalloonTip::timerEvent(QTimerEvent *e) { if (e->timerId() == timer.timerId()) { timer.stop(); if (!underMouse()) close(); return; } QWidget::timerEvent(e); } bool QBalloonTip::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast(event); if (m_button) { if (QWidget *clickedWidget = qobject_cast(obj)) { if (clickedWidget == m_button || m_button->isAncestorOf(clickedWidget)) { return false; } } } if (m_visible && !geometry().contains(mouseEvent->globalPos())) { m_visible = false; close(); return true; } } else if (event->type() == QEvent::WindowDeactivate) { // Close when window loses focus if (obj == this) { m_visible = false; close(); return false; } } return QWidget::eventFilter(obj, event); } void QBalloonTip::hideEvent(QHideEvent *event) { // Remove event filter when hiding qApp->removeEventFilter(this); QWidget::hideEvent(event); }