summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel/qtooltip.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/kernel/qtooltip.cpp')
-rw-r--r--src/widgets/kernel/qtooltip.cpp298
1 files changed, 109 insertions, 189 deletions
diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp
index cf0f3f153b..35eaa8042a 100644
--- a/src/widgets/kernel/qtooltip.cpp
+++ b/src/widgets/kernel/qtooltip.cpp
@@ -1,51 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#if 0 // Used to be included in Qt4 for Q_WS_MAC
-# include <private/qcore_mac_p.h>
-#endif
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtWidgets/private/qtwidgetsglobal_p.h>
-#include <QtWidgets/private/qlabel_p.h>
#include <qapplication.h>
-#include <qdesktopwidget.h>
-#include <private/qdesktopwidget_p.h>
#include <qevent.h>
#include <qpointer.h>
#include <qstyle.h>
@@ -57,19 +15,19 @@
#endif
#include <qtextdocument.h>
#include <qdebug.h>
+#include <qpa/qplatformscreen.h>
+#include <qpa/qplatformcursor.h>
#include <private/qstylesheetstyle_p.h>
-#ifndef QT_NO_TOOLTIP
#include <qlabel.h>
+#include <QtWidgets/private/qlabel_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <qtooltip.h>
-#if 0 // Used to be included in Qt4 for Q_WS_MAC
-# include <private/qcore_mac_p.h>
-#include <private/qt_cocoa_helpers_mac_p.h>
-#endif
-
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
/*!
\class QToolTip
@@ -87,15 +45,24 @@ QT_BEGIN_NAMESPACE
Rich text displayed in a tool tip is implicitly word-wrapped unless
specified differently with \c{<p style='white-space:pre'>}.
- The simplest and most common way to set a widget's tool tip is by
- calling its QWidget::setToolTip() function.
+ UI elements that are created via \l{QAction} use the tooltip property
+ of the QAction, so for most interactive UI elements, setting that
+ property is the easiest way to provide tool tips.
+
+ \snippet tooltips/main.cpp action_tooltip
+
+ For any other widgets, the simplest and most common way to set
+ a widget's tool tip is by calling its QWidget::setToolTip() function.
+
+ \snippet tooltips/main.cpp static_tooltip
It is also possible to show different tool tips for different
regions of a widget, by using a QHelpEvent of type
QEvent::ToolTip. Intercept the help event in your widget's \l
{QWidget::}{event()} function and call QToolTip::showText() with
- the text you want to display. The \l{widgets/tooltips}{Tooltips}
- example illustrates this technique.
+ the text you want to display.
+
+ \snippet tooltips/main.cpp dynamic_tooltip
If you are calling QToolTip::hideText(), or QToolTip::showText()
with an empty string, as a result of a \l{QEvent::}{ToolTip}-event you
@@ -117,7 +84,7 @@ QT_BEGIN_NAMESPACE
\note Tool tips use the inactive color group of QPalette, because tool
tips are not active windows.
- \sa QWidget::toolTip, QAction::toolTip, {Tool Tips Example}
+ \sa QWidget::toolTip, QAction::toolTip
*/
class QTipLabel : public QLabel
@@ -145,7 +112,7 @@ public:
bool tipChanged(const QPoint &pos, const QString &text, QObject *o);
void placeTip(const QPoint &pos, QWidget *w);
- static int getTipScreen(const QPoint &pos, QWidget *w);
+ static QScreen *getTipScreen(const QPoint &pos, QWidget *w);
protected:
void timerEvent(QTimerEvent *e) override;
void paintEvent(QPaintEvent *e) override;
@@ -155,11 +122,11 @@ protected:
#ifndef QT_NO_STYLE_STYLESHEET
public slots:
/** \internal
- Cleanup the _q_stylesheet_parent propery.
+ Cleanup the _q_stylesheet_parent property.
*/
void styleSheetParentDestroyed() {
setProperty("_q_stylesheet_parent", QVariant());
- styleSheetParent = 0;
+ styleSheetParent = nullptr;
}
private:
@@ -171,14 +138,14 @@ private:
QRect rect;
};
-QTipLabel *QTipLabel::instance = 0;
+QTipLabel *QTipLabel::instance = nullptr;
QTipLabel::QTipLabel(const QString &text, const QPoint &pos, QWidget *w, int msecDisplayTime)
+ : QLabel(w, Qt::ToolTip | Qt::BypassGraphicsProxyWidget)
#ifndef QT_NO_STYLE_STYLESHEET
- : QLabel(w, Qt::ToolTip | Qt::BypassGraphicsProxyWidget), styleSheetParent(0), widget(0)
-#else
- : QLabel(w, Qt::ToolTip | Qt::BypassGraphicsProxyWidget), widget(0)
+ , styleSheetParent(nullptr)
#endif
+ , widget(nullptr)
{
delete instance;
instance = this;
@@ -186,12 +153,12 @@ QTipLabel::QTipLabel(const QString &text, const QPoint &pos, QWidget *w, int mse
setBackgroundRole(QPalette::ToolTipBase);
setPalette(QToolTip::palette());
ensurePolished();
- setMargin(1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0, this));
+ setMargin(1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, nullptr, this));
setFrameStyle(QFrame::NoFrame);
setAlignment(Qt::AlignLeft);
setIndent(1);
qApp->installEventFilter(this);
- setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0);
+ setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, nullptr, this) / 255.0);
setMouseTracking(true);
fadingOut = false;
reuseTip(text, msecDisplayTime, pos);
@@ -199,7 +166,9 @@ QTipLabel::QTipLabel(const QString &text, const QPoint &pos, QWidget *w, int mse
void QTipLabel::restartExpireTimer(int msecDisplayTime)
{
- int time = 10000 + 40 * qMax(0, text().length()-100);
+ Q_D(const QLabel);
+ const qsizetype textLength = d->needTextControl() ? d->control->toPlainText().size() : text().size();
+ qsizetype time = 10000 + 40 * qMax(0, textLength - 100);
if (msecDisplayTime > 0)
time = msecDisplayTime;
expireTimer.start(time, this);
@@ -210,9 +179,9 @@ void QTipLabel::reuseTip(const QString &text, int msecDisplayTime, const QPoint
{
#ifndef QT_NO_STYLE_STYLESHEET
if (styleSheetParent){
- disconnect(styleSheetParent, SIGNAL(destroyed()),
- QTipLabel::instance, SLOT(styleSheetParentDestroyed()));
- styleSheetParent = 0;
+ disconnect(styleSheetParent, &QWidget::destroyed,
+ this, &QTipLabel::styleSheetParentDestroyed);
+ styleSheetParent = nullptr;
}
#endif
@@ -223,11 +192,7 @@ void QTipLabel::reuseTip(const QString &text, int msecDisplayTime, const QPoint
void QTipLabel::updateSize(const QPoint &pos)
{
-#ifndef Q_OS_WINRT
- // ### The code below does not always work well on WinRT
- // (e.g COIN fails an auto test - tst_QToolTip::qtbug64550_stylesheet - QTBUG-72652)
d_func()->setScreenForPoint(pos);
-#endif
// Ensure that we get correct sizeHints by placing this window on the right screen.
QFontMetrics fm(font());
QSize extra(1, 0);
@@ -236,16 +201,10 @@ void QTipLabel::updateSize(const QPoint &pos)
++extra.rheight();
setWordWrap(Qt::mightBeRichText(text()));
QSize sh = sizeHint();
- // ### When the above WinRT code is fixed, windowhandle should be used to find the screen.
- QScreen *screen = QGuiApplication::screenAt(pos);
- if (!screen)
- screen = QGuiApplication::primaryScreen();
- if (screen) {
- const qreal screenWidth = screen->geometry().width();
- if (!wordWrap() && sh.width() > screenWidth) {
- setWordWrap(true);
- sh = sizeHint();
- }
+ const QScreen *screen = getTipScreen(pos, this);
+ if (!wordWrap() && sh.width() > screen->geometry().width()) {
+ setWordWrap(true);
+ sh = sizeHint();
}
resize(sh + extra);
}
@@ -254,7 +213,7 @@ void QTipLabel::paintEvent(QPaintEvent *ev)
{
QStylePainter p(this);
QStyleOptionFrame opt;
- opt.init(this);
+ opt.initFrom(this);
p.drawPrimitive(QStyle::PE_PanelTipLabel, opt);
p.end();
@@ -265,7 +224,7 @@ void QTipLabel::resizeEvent(QResizeEvent *e)
{
QStyleHintReturnMask frameMask;
QStyleOption option;
- option.init(this);
+ option.initFrom(this);
if (style()->styleHint(QStyle::SH_ToolTip_Mask, &option, this, &frameMask))
setMask(frameMask.region);
@@ -275,7 +234,7 @@ void QTipLabel::resizeEvent(QResizeEvent *e)
void QTipLabel::mouseMoveEvent(QMouseEvent *e)
{
if (!rect.isNull()) {
- QPoint pos = e->globalPos();
+ QPoint pos = e->globalPosition().toPoint();
if (widget)
pos = widget->mapFromGlobal(pos);
if (!rect.contains(pos))
@@ -286,7 +245,7 @@ void QTipLabel::mouseMoveEvent(QMouseEvent *e)
QTipLabel::~QTipLabel()
{
- instance = 0;
+ instance = nullptr;
}
void QTipLabel::hideTip()
@@ -317,20 +276,7 @@ void QTipLabel::timerEvent(QTimerEvent *e)
|| e->timerId() == expireTimer.timerId()){
hideTimer.stop();
expireTimer.stop();
-#if 0 /* Used to be included in Qt4 for Q_WS_MAC */ && QT_CONFIG(effects)
- if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip)){
- // Fade out tip on mac (makes it invisible).
- // The tip will not be deleted until a new tip is shown.
-
- // DRSWAT - Cocoa
- macWindowFade(qt_mac_window_for(this));
- QTipLabel::instance->fadingOut = true; // will never be false again.
- }
- else
- hideTipImmediately();
-#else
hideTipImmediately();
-#endif
}
}
@@ -352,7 +298,7 @@ bool QTipLabel::eventFilter(QObject *o, QEvent *e)
break;
-#if defined (Q_OS_QNX) // On QNX the window activate and focus events are delayed and will appear
+#if defined (Q_OS_QNX) || defined (Q_OS_WASM) // On QNX the window activate and focus events are delayed and will appear
// after the window is shown.
case QEvent::WindowActivate:
case QEvent::FocusIn:
@@ -373,7 +319,6 @@ bool QTipLabel::eventFilter(QObject *o, QEvent *e)
case QEvent::FocusIn:
case QEvent::FocusOut:
#endif
- case QEvent::Close: // For QTBUG-55523 (QQC) specifically: Hide tooltip when windows are closed
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
@@ -382,20 +327,20 @@ bool QTipLabel::eventFilter(QObject *o, QEvent *e)
break;
case QEvent::MouseMove:
- if (o == widget && !rect.isNull() && !rect.contains(static_cast<QMouseEvent*>(e)->pos()))
+ if (o == widget && !rect.isNull() && !rect.contains(static_cast<QMouseEvent*>(e)->position().toPoint()))
hideTip();
+ break;
default:
break;
}
return false;
}
-int QTipLabel::getTipScreen(const QPoint &pos, QWidget *w)
+QScreen *QTipLabel::getTipScreen(const QPoint &pos, QWidget *w)
{
- if (QDesktopWidgetPrivate::isVirtualDesktop())
- return QDesktopWidgetPrivate::screenNumber(pos);
- else
- return QDesktopWidgetPrivate::screenNumber(w);
+ QScreen *guess = w ? w->screen() : QGuiApplication::primaryScreen();
+ QScreen *exact = guess->virtualSiblingAt(pos);
+ return exact ? exact : guess;
}
void QTipLabel::placeTip(const QPoint &pos, QWidget *w)
@@ -405,56 +350,52 @@ void QTipLabel::placeTip(const QPoint &pos, QWidget *w)
//the stylesheet need to know the real parent
QTipLabel::instance->setProperty("_q_stylesheet_parent", QVariant::fromValue(w));
//we force the style to be the QStyleSheetStyle, and force to clear the cache as well.
- QTipLabel::instance->setStyleSheet(QLatin1String("/* */"));
+ QTipLabel::instance->setStyleSheet("/* */"_L1);
// Set up for cleaning up this later...
QTipLabel::instance->styleSheetParent = w;
if (w) {
- connect(w, SIGNAL(destroyed()),
- QTipLabel::instance, SLOT(styleSheetParentDestroyed()));
- // QTBUG-64550: A font inherited by the style sheet might change the size,
- // particular on Windows, where the tip is not parented on a window.
- QTipLabel::instance->updateSize(pos);
+ connect(w, &QWidget::destroyed,
+ QTipLabel::instance, &QTipLabel::styleSheetParentDestroyed);
}
+ // QTBUG-64550: A font inherited by the style sheet might change the size,
+ // particular on Windows, where the tip is not parented on a window.
+ // The updatesSize() also makes sure that the content size be updated with
+ // correct content margin.
+ QTipLabel::instance->updateSize(pos);
}
#endif //QT_NO_STYLE_STYLESHEET
-
-#if 0 // Used to be included in Qt4 for Q_WS_MAC
- // When in full screen mode, there is no Dock nor Menu so we can use
- // the whole screen for displaying the tooltip. However when not in
- // full screen mode we need to save space for the dock, so we use
- // availableGeometry instead.
- extern bool qt_mac_app_fullscreen; //qapplication_mac.mm
- QRect screen;
- if(qt_mac_app_fullscreen)
- screen = QDesktopWidgetPrivate::screenGeometry(getTipScreen(pos, w));
- else
- screen = QDesktopWidgetPrivate::availableGeometry(getTipScreen(pos, w));
-#else
- QRect screen = QDesktopWidgetPrivate::screenGeometry(getTipScreen(pos, w));
-#endif
-
QPoint p = pos;
- p += QPoint(2,
-#if 0 // Used to be included in Qt4 for Q_WS_WIN
- 21
-#else
- 16
-#endif
- );
- if (p.x() + this->width() > screen.x() + screen.width())
+ const QScreen *screen = getTipScreen(pos, w);
+ // a QScreen's handle *should* never be null, so this is a bit paranoid
+ if (const QPlatformScreen *platformScreen = screen ? screen->handle() : nullptr) {
+ QPlatformCursor *cursor = platformScreen->cursor();
+ // default implementation of QPlatformCursor::size() returns QSize(16, 16)
+ const QSize nativeSize = cursor ? cursor->size() : QSize(16, 16);
+ const QSize cursorSize = QHighDpi::fromNativePixels(nativeSize,
+ platformScreen);
+ QPoint offset(2, cursorSize.height());
+ // assuming an arrow shape, we can just move to the side for very large cursors
+ if (cursorSize.height() > 2 * this->height())
+ offset = QPoint(cursorSize.width() / 2, 0);
+
+ p += offset;
+
+ QRect screenRect = screen->geometry();
+ if (p.x() + this->width() > screenRect.x() + screenRect.width())
p.rx() -= 4 + this->width();
- if (p.y() + this->height() > screen.y() + screen.height())
+ if (p.y() + this->height() > screenRect.y() + screenRect.height())
p.ry() -= 24 + this->height();
- if (p.y() < screen.y())
- p.setY(screen.y());
- if (p.x() + this->width() > screen.x() + screen.width())
- p.setX(screen.x() + screen.width() - this->width());
- if (p.x() < screen.x())
- p.setX(screen.x());
- if (p.y() + this->height() > screen.y() + screen.height())
- p.setY(screen.y() + screen.height() - this->height());
+ if (p.y() < screenRect.y())
+ p.setY(screenRect.y());
+ if (p.x() + this->width() > screenRect.x() + screenRect.width())
+ p.setX(screenRect.x() + screenRect.width() - this->width());
+ if (p.x() < screenRect.x())
+ p.setX(screenRect.x());
+ if (p.y() + this->height() > screenRect.y() + screenRect.height())
+ p.setY(screenRect.y() + screenRect.height() - this->height());
+ }
this->move(p);
}
@@ -482,8 +423,12 @@ bool QTipLabel::tipChanged(const QPoint &pos, const QString &text, QObject *o)
The \a rect is in the coordinates of the widget you specify with
\a w. If the \a rect is not empty you must specify a widget.
- Otherwise this argument can be 0 but it is used to determine the
- appropriate screen on multi-head systems.
+ Otherwise this argument can be \nullptr but it is used to
+ determine the appropriate screen on multi-head systems.
+
+ The \a msecDisplayTime parameter specifies for how long the tool tip
+ will be displayed, in milliseconds. With the default value of -1, the
+ time is based on the length of the text.
If \a text is empty the tool tip is hidden. If the text is the
same as the currently shown tooltip, the tip will \e not move.
@@ -491,26 +436,13 @@ bool QTipLabel::tipChanged(const QPoint &pos, const QString &text, QObject *o)
and then showing the new tip at the new position.
*/
-void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect)
-{
- showText(pos, text, w, rect, -1);
-}
-
-/*!
- \since 5.2
- \overload
- This is similar to QToolTip::showText(\a pos, \a text, \a w, \a rect) but with an extra parameter \a msecDisplayTime
- that specifies how long the tool tip will be displayed, in milliseconds.
-*/
-
void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect, int msecDisplayTime)
{
- if (QTipLabel::instance && QTipLabel::instance->isVisible()){ // a tip does already exist
+ if (QTipLabel::instance && QTipLabel::instance->isVisible()) { // a tip does already exist
if (text.isEmpty()){ // empty text means hide current tip
QTipLabel::instance->hideTip();
return;
- }
- else if (!QTipLabel::instance->fadingOut){
+ } else if (!QTipLabel::instance->fadingOut) {
// If the tip has changed, reuse the one
// that is showing (removes flickering)
QPoint localPos = pos;
@@ -525,23 +457,24 @@ void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, cons
}
}
- if (!text.isEmpty()){ // no tip can be reused, create new tip:
+ if (!text.isEmpty()) { // no tip can be reused, create new tip:
+ QWidget *tipLabelParent = [w]() -> QWidget* {
#ifdef Q_OS_WIN32
- // On windows, we can't use the widget as parent otherwise the window will be
- // raised when the tooltip will be shown
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- new QTipLabel(text, pos, QApplication::desktop()->screen(QTipLabel::getTipScreen(pos, w)), msecDisplayTime);
-QT_WARNING_POP
+ // On windows, we can't use the widget as parent otherwise the window will be
+ // raised when the tooltip will be shown
+ Q_UNUSED(w);
+ return nullptr;
#else
- new QTipLabel(text, pos, w, msecDisplayTime); // sets QTipLabel::instance to itself
+ return w;
#endif
+ }();
+ new QTipLabel(text, pos, tipLabelParent, msecDisplayTime); // sets QTipLabel::instance to itself
+ QWidgetPrivate::get(QTipLabel::instance)->setScreen(QTipLabel::getTipScreen(pos, w));
QTipLabel::instance->setTipRect(w, rect);
QTipLabel::instance->placeTip(pos, w);
- QTipLabel::instance->setObjectName(QLatin1String("qtooltip_label"));
-
+ QTipLabel::instance->setObjectName("qtooltip_label"_L1);
-#if QT_CONFIG(effects) && !0 /* Used to be included in Qt4 for Q_WS_MAC */
+#if QT_CONFIG(effects)
if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip))
qFadeEffect(QTipLabel::instance);
else if (QApplication::isEffectEnabled(Qt::UI_AnimateTooltip))
@@ -555,18 +488,6 @@ QT_WARNING_POP
}
/*!
- \overload
-
- This is analogous to calling QToolTip::showText(\a pos, \a text, \a w, QRect())
-*/
-
-void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w)
-{
- QToolTip::showText(pos, text, w, QRect());
-}
-
-
-/*!
\fn void QToolTip::hideText()
\since 4.2
@@ -580,13 +501,13 @@ void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w)
/*!
\since 4.4
- Returns \c true if this tooltip is currently shown.
+ Returns \c true if a tooltip is currently shown.
\sa showText()
*/
bool QToolTip::isVisible()
{
- return (QTipLabel::instance != 0 && QTipLabel::instance->isVisible());
+ return (QTipLabel::instance != nullptr && QTipLabel::instance->isVisible());
}
/*!
@@ -654,4 +575,3 @@ void QToolTip::setFont(const QFont &font)
QT_END_NAMESPACE
#include "qtooltip.moc"
-#endif // QT_NO_TOOLTIP