KWidgetsAddons

ktooltipwidget.cpp
1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2008 Fredrik Höglund <fredrik@kde.org>
4 SPDX-FileCopyrightText: 2008 Konstantin Heil <konst.heil@stud.uni-heidelberg.de>
5 SPDX-FileCopyrightText: 2009 Peter Penz <peter.penz@gmx.at>
6 SPDX-FileCopyrightText: 2017 Elvis Angelaccio <elvis.angelaccio@kde.org>
7
8 SPDX-License-Identifier: LGPL-2.1-or-later
9*/
10
11#include "ktooltipwidget.h"
12
13#include <QPaintEvent>
14#include <QScreen>
15#include <QStyleOptionFrame>
16#include <QStylePainter>
17#include <QTimer>
18#include <QVBoxLayout>
19#include <QWindow>
20
21class KToolTipWidgetPrivate
22{
23public:
24 KToolTipWidgetPrivate(KToolTipWidget *parent)
25 : q(parent)
26 {
27 }
28
29 void init();
30 void addWidget(QWidget *widget);
31 void removeWidget();
32 void show(const QPoint &pos, QWindow *transientParent);
33 void storeParent();
34 void restoreParent();
35 QPoint centerBelow(const QRect &rect, QScreen *screen) const;
36
37 KToolTipWidget *const q;
38 QTimer hideTimer;
39 QVBoxLayout *layout = nullptr;
40 QWidget *content = nullptr;
41 QWidget *contentParent = nullptr;
42};
43
44void KToolTipWidgetPrivate::init()
45{
46 layout = new QVBoxLayout(q);
47
48 hideTimer.setSingleShot(true);
49 hideTimer.setInterval(500);
50
52
55}
56
57void KToolTipWidgetPrivate::addWidget(QWidget *widget)
58{
59 removeWidget();
60 content = widget;
61 storeParent();
62 layout->addWidget(content);
64}
65
66void KToolTipWidgetPrivate::removeWidget()
67{
68 layout->removeWidget(content);
69 restoreParent();
70}
71
72void KToolTipWidgetPrivate::show(const QPoint &pos, QWindow *transientParent)
73{
74 if (pos.isNull()) {
75 return;
76 }
77
78 q->move(pos);
79 q->createWinId();
80 q->windowHandle()->setProperty("ENABLE_BLUR_BEHIND_HINT", true);
81 q->windowHandle()->setTransientParent(transientParent);
82
84
85 q->show();
86}
87
88void KToolTipWidgetPrivate::storeParent()
89{
90 if (!content) {
91 return;
92 }
93
94 contentParent = qobject_cast<QWidget *>(content->parent());
95}
96
97void KToolTipWidgetPrivate::restoreParent()
98{
99 if (!content || !contentParent) {
100 return;
101 }
102
103 content->setParent(contentParent);
104}
105
106QPoint KToolTipWidgetPrivate::centerBelow(const QRect &rect, QScreen *screen) const
107{
108 // It must be assured that:
109 // - the content is fully visible
110 // - the content is not drawn inside rect
111
112 const QSize size = q->sizeHint();
113 const int margin = q->style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth);
114 const QRect screenGeometry = screen->geometry();
115
116 const bool hasRoomToLeft = (rect.left() - size.width() - margin >= screenGeometry.left());
117 const bool hasRoomToRight = (rect.right() + size.width() + margin <= screenGeometry.right());
118 const bool hasRoomAbove = (rect.top() - size.height() - margin >= screenGeometry.top());
119 const bool hasRoomBelow = (rect.bottom() + size.height() + margin <= screenGeometry.bottom());
120 if (!hasRoomAbove && !hasRoomBelow && !hasRoomToLeft && !hasRoomToRight) {
121 return QPoint();
122 }
123
124 int x = 0;
125 int y = 0;
126 if (hasRoomBelow || hasRoomAbove) {
127 x = qMax(screenGeometry.left(), rect.center().x() - size.width() / 2);
128 if (x + size.width() >= screenGeometry.right()) {
129 x = screenGeometry.right() - size.width() + 1;
130 }
131 Q_ASSERT(x >= 0);
132 if (hasRoomBelow) {
133 y = rect.bottom() + margin;
134 } else {
135 y = rect.top() - size.height() - margin + 1;
136 }
137 } else {
138 Q_ASSERT(hasRoomToLeft || hasRoomToRight);
139 if (hasRoomToRight) {
140 x = rect.right() + margin;
141 } else {
142 x = rect.left() - size.width() - margin + 1;
143 }
144 // Put the tooltip at the bottom of the screen. The x-coordinate has already
145 // been adjusted, so that no overlapping with rect occurs.
146 y = screenGeometry.bottom() - size.height() + 1;
147 }
148
149 return QPoint(x, y);
150}
151
152KToolTipWidget::KToolTipWidget(QWidget *parent)
153 : QWidget(parent)
154 , d(new KToolTipWidgetPrivate(this))
155{
156 d->init();
157}
158
159KToolTipWidget::~KToolTipWidget()
160{
161 d->restoreParent();
162}
163
164void KToolTipWidget::showAt(const QPoint &pos, QWidget *content, QWindow *transientParent)
165{
166 d->addWidget(content);
167 d->show(pos, transientParent);
168}
169
170void KToolTipWidget::showBelow(const QRect &rect, QWidget *content, QWindow *transientParent)
171{
172 d->addWidget(content);
173
174 const auto contentMargins = layout()->contentsMargins();
175 const QSize screenSize = transientParent->screen()->geometry().size();
176
177 content->setMaximumSize(screenSize.shrunkBy(contentMargins));
178
179 d->show(d->centerBelow(rect, transientParent->screen()), transientParent);
180}
181
182int KToolTipWidget::hideDelay() const
183{
184 return d->hideTimer.interval();
185}
186
188{
189 if (!isVisible()) {
190 return;
191 }
192
193 if (hideDelay() > 0) {
194 d->hideTimer.start();
195 } else {
196 hide();
197 }
198}
199
201{
202 d->hideTimer.setInterval(delay);
203}
204
205void KToolTipWidget::enterEvent(QEnterEvent *)
206{
207 // Ignore hide delay and leave tooltip visible.
208 if (hideDelay() > 0) {
209 d->hideTimer.stop();
210 } else {
211 hide();
212 }
213}
214
215void KToolTipWidget::hideEvent(QHideEvent *)
216{
217 d->removeWidget();
218
220
221 // Give time to the content widget to get his own hide event.
223}
224
225void KToolTipWidget::leaveEvent(QEvent *)
226{
227 // Don't bother starting the hide timer, we are done.
228 hide();
229}
230
231void KToolTipWidget::paintEvent(QPaintEvent *event)
232{
233 QStylePainter painter(this);
234 painter.setClipRegion(event->region());
235 QStyleOptionFrame option;
236 option.initFrom(this);
237 painter.drawPrimitive(QStyle::PE_PanelTipLabel, option);
238 painter.end();
239
241}
242
243#include "moc_ktooltipwidget.cpp"
A tooltip that contains a QWidget.
void hideLater()
Hide the tooltip after a delay of hideDelay() ms (to allow interaction with the tooltip's widget).
void hidden()
The tooltip has been hidden and the tooltip's widget is no longer visible.
void showAt(const QPoint &pos, QWidget *content, QWindow *transientParent)
Show a tooltip containing content.
void showBelow(const QRect &rect, QWidget *content, QWindow *transientParent)
Show a tooltip containing content centered below rect.
void setHideDelay(int delay)
Set after how many ms hideLater() will hide the tooltip.
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
QMargins contentsMargins() const const
void removeWidget(QWidget *widget)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
bool disconnect(const QMetaObject::Connection &connection)
QObject * parent() const const
bool setProperty(const char *name, QVariant &&value)
bool isNull() const const
int x() const const
int bottom() const const
QPoint center() const const
int left() const const
int right() const const
int top() const const
int height() const const
QSize shrunkBy(QMargins margins) const const
int width() const const
PM_ToolTipLabelFrameWidth
PE_PanelTipLabel
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
void initFrom(const QWidget *widget)
WA_TranslucentBackground
void setInterval(int msec)
void setSingleShot(bool singleShot)
void timeout()
virtual bool event(QEvent *event) override
void hide()
QLayout * layout() const const
void setMaximumSize(const QSize &)
virtual void paintEvent(QPaintEvent *event)
void move(const QPoint &)
void setAttribute(Qt::WidgetAttribute attribute, bool on)
void setParent(QWidget *parent)
void show()
QStyle * style() const const
bool isVisible() const const
void setWindowFlags(Qt::WindowFlags type)
QWindow * windowHandle() const const
void activeChanged()
QScreen * screen() const const
void setTransientParent(QWindow *parent)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.