95QTipLabel::QTipLabel(
const QString &text, QPoint pos, QWidget *w,
96 std::chrono::milliseconds displayTime)
97 : QLabel(w, Qt::ToolTip | Qt::BypassGraphicsProxyWidget)
98#if QT_CONFIG(style_stylesheet)
99 , styleSheetParent(
nullptr)
106 setForegroundRole(QPalette::ToolTipText);
107 setBackgroundRole(QPalette::ToolTipBase);
108 setPalette(QToolTip::palette());
110 setMargin(1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth,
nullptr,
this));
111 setFrameStyle(QFrame::NoFrame);
112 setAlignment(Qt::AlignLeft);
114 qApp->installEventFilter(
this);
115 setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity,
nullptr,
this) / 255.0);
116 setMouseTracking(
true);
117 reuseTip(text, displayTime, pos);
120void QTipLabel::restartExpireTimer(std::chrono::milliseconds displayTime)
123 std::chrono::milliseconds time;
124 if (displayTime > 0ms) {
127 const qsizetype textLength =
128 d->needTextControl() ? d->control->toPlainText().size() : text().size();
129 time = std::chrono::milliseconds(10000 + 40 * qMax(0, textLength - 100));
131 expireTimer.start(time,
this);
135void QTipLabel::reuseTip(
const QString &text, std::chrono::milliseconds displayTime, QPoint pos)
137#if QT_CONFIG(style_stylesheet)
138 if (styleSheetParent){
139 disconnect(styleSheetParent, &QWidget::destroyed,
140 this, &QTipLabel::styleSheetParentDestroyed);
141 styleSheetParent =
nullptr;
145 setWordWrap(Qt::mightBeRichText(text));
148 restartExpireTimer(displayTime);
151void QTipLabel::updateSize(
const QPoint &pos)
153 d_func()->setScreenForPoint(pos);
155 QFontMetrics fm(font());
158 if (fm.descent() == 2 && fm.ascent() >= 11)
160 QSize sh = sizeHint();
161 const QScreen *screen = getTipScreen(pos,
this);
162 if (!wordWrap() && sh.width() > screen->geometry().width()) {
180void QTipLabel::resizeEvent(QResizeEvent *e)
182 QStyleHintReturnMask frameMask;
184 option.initFrom(
this);
185 if (style()->styleHint(QStyle::SH_ToolTip_Mask, &option,
this, &frameMask))
186 setMask(frameMask.region);
188 QLabel::resizeEvent(e);
191void QTipLabel::mouseMoveEvent(QMouseEvent *e)
193 if (!rect.isNull()) {
194 QPointF pos = e->globalPosition();
196 pos = widget->mapFromGlobal(pos);
197 if (!rect.contains(pos.toPoint()))
200 QLabel::mouseMoveEvent(e);
240bool QTipLabel::eventFilter(QObject *o, QEvent *e)
244 case QEvent::KeyPress:
245 case QEvent::KeyRelease: {
246 const int key =
static_cast<QKeyEvent *>(e)->key();
248 if (key < Qt::Key_Shift || key > Qt::Key_ScrollLock)
249 hideTipImmediately();
258#if defined (Q_OS_QNX) || defined (Q_OS_WASM)
260 case QEvent::WindowActivate:
261 case QEvent::FocusIn:
263 case QEvent::WindowDeactivate:
266 hideTipImmediately();
268 case QEvent::FocusOut:
269 if (
reinterpret_cast<QWindow*>(o) != windowHandle())
271 hideTipImmediately();
274 case QEvent::WindowActivate:
275 case QEvent::WindowDeactivate:
276 case QEvent::FocusIn:
277 case QEvent::FocusOut:
279 case QEvent::MouseButtonPress:
280 case QEvent::MouseButtonRelease:
281 case QEvent::MouseButtonDblClick:
283 hideTipImmediately();
286 case QEvent::MouseMove:
287 if (o == widget && !rect.isNull() && !rect.contains(
static_cast<QMouseEvent*>(e)->position().toPoint()))
303void QTipLabel::placeTip(
const QPoint &pos, QWidget *w)
305#if QT_CONFIG(style_stylesheet)
306 if (testAttribute(Qt::WA_StyleSheet) || (w && qt_styleSheet(w->style()))) {
308 QTipLabel::instance->setProperty(
"_q_stylesheet_parent", QVariant::fromValue(w));
310 QTipLabel::instance->setStyleSheet(
"/* */"_L1);
313 QTipLabel::instance->styleSheetParent = w;
315 connect(w, &QWidget::destroyed,
316 QTipLabel::instance, &QTipLabel::styleSheetParentDestroyed);
322 QTipLabel::instance->updateSize(pos);
327 const QScreen *screen = getTipScreen(pos, w);
329 if (
const QPlatformScreen *platformScreen = screen ? screen->handle() :
nullptr) {
330 QPlatformCursor *cursor = platformScreen->cursor();
332 const QSize nativeSize = cursor ? cursor->size() : QSize(16, 16);
333 const QSize cursorSize = QHighDpi::fromNativePixels(nativeSize,
335 QPoint offset(2, cursorSize.height());
337 if (cursorSize.height() > 2 *
this->height())
338 offset = QPoint(cursorSize.width() / 2, 0);
342#if QT_CONFIG(wayland)
345 if (
auto waylandWindow =
dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(windowHandle()->handle())) {
346 QWidget *parentWindow = w->window();
347 parentWindow->createWinId();
348 windowHandle()->setTransientParent(parentWindow->windowHandle());
352 const QRect controlGeometry = QRect(p.x() - 4, p.y() - 24, 4, 24)
353 .translated(-parentWindow->mapToGlobal(QPoint(0, 0)));
354 waylandWindow->setParentControlGeometry(controlGeometry);
355 waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ToolTip);
360 QRect screenRect = screen->availableGeometry();
361 if (p.x() +
this->width() > screenRect.x() + screenRect.width())
362 p.rx() -= 4 +
this->width();
363 if (p.y() +
this->height() > screenRect.y() + screenRect.height())
364 p.ry() -= 24 +
this->height();
365 if (p.y() < screenRect.y())
366 p.setY(screenRect.y());
367 if (p.x() +
this->width() > screenRect.x() + screenRect.width())
368 p.setX(screenRect.x() + screenRect.width() -
this->width());
369 if (p.x() < screenRect.x())
370 p.setX(screenRect.x());
371 if (p.y() +
this->height() > screenRect.y() + screenRect.height())
372 p.setY(screenRect.y() + screenRect.height() -
this->height());
425void QToolTip::showText(
const QPoint &pos,
const QString &text, QWidget *w,
const QRect &rect,
int msecDisplayTime)
427 showText(pos, text, w, rect, std::chrono::milliseconds(msecDisplayTime));
455void QToolTip::showText(QPoint pos,
const QString &text, QWidget *w,
const QRect &rect,
456 std::chrono::milliseconds displayTime)
458 if (QTipLabel::instance && QTipLabel::instance->isVisible()) {
460 QTipLabel::instance->hideTip();
462 }
else if (!QTipLabel::instance->fadingOut) {
465 QPoint localPos = pos;
467 localPos = w->mapFromGlobal(pos);
468 if (QTipLabel::instance->tipChanged(localPos, text, w)){
469 QTipLabel::instance->reuseTip(text, displayTime, pos);
470 QTipLabel::instance->setTipRect(w, rect);
471 QTipLabel::instance->placeTip(pos, w);
477 if (!text.isEmpty()) {
478 QWidget *tipLabelParent = [w]() -> QWidget* {
488 new QTipLabel(text, pos, tipLabelParent, displayTime);
489 QWidgetPrivate::get(QTipLabel::instance)->setScreen(QTipLabel::getTipScreen(pos, w));
490 QTipLabel::instance->setTipRect(w, rect);
491 QTipLabel::instance->placeTip(pos, w);
492 QTipLabel::instance->setObjectName(
"qtooltip_label"_L1);
494#if QT_CONFIG(effects)
495 if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip))
496 qFadeEffect(QTipLabel::instance);
497 else if (QApplication::isEffectEnabled(Qt::UI_AnimateTooltip))
498 qScrollEffect(QTipLabel::instance);
500 QTipLabel::instance->showNormal();
502 QTipLabel::instance->showNormal();