Krita Source Code Documentation
Loading...
Searching...
No Matches
KoItemToolTip.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2006 Gábor Lehel <illissius@gmail.com>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6#include "KoItemToolTip.h"
7
8#include <QApplication>
9#include <QTimer>
10#include <QModelIndex>
11#include <QPainter>
12#include <QPaintEvent>
13#include <QPersistentModelIndex>
14#include <QStyleOptionViewItem>
15#include <QTextDocument>
16#include <QToolTip>
17#include <QScreen>
18
19// for HAVE_WAYLAND
20#include <KoConfig.h>
21
22#if defined HAVE_WAYLAND && QT_VERSION >= QT_VERSION_CHECK(6, 11, 0)
23#define HAVE_QT_PRIVATE_TOOLTIP_POSITION_API
24#endif
25
26#ifdef HAVE_QT_PRIVATE_TOOLTIP_POSITION_API
27#include <QtWaylandClient/private/qwaylandwindow_p.h>
28#endif
29
30#include <kis_assert.h>
31
32
33class Q_DECL_HIDDEN KoItemToolTip::Private
34{
35 public:
36 std::unique_ptr<QTextDocument> document;
37 QPersistentModelIndex index;
38 QPoint pos;
39 QTimer timer;
40};
41
43 : QFrame(parent, Qt::FramelessWindowHint | Qt::ToolTip | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint)
44 , d(new Private)
45{
46 Q_ASSERT(parent);
47
48 d->timer.setSingleShot(true);
49 d->timer.setInterval(10000);
50 connect(&d->timer, &QTimer::timeout, this, &KoItemToolTip::hide);
51
52 d->document.reset(new QTextDocument(this));
53
54 parent->installEventFilter(this);
55}
56
60
61void KoItemToolTip::showTip(const QPoint &pos, const QStyleOptionViewItem &option, const QModelIndex &index)
62{
63 std::unique_ptr<QTextDocument> doc(createDocument(index));
64
65 QPoint p = (isVisible() && index == d->index) ? d->pos : pos;
66
67 if (!isVisible() || index != d->index || doc->toHtml() != d->document->toHtml()) {
68 d->pos = p;
69 d->index = index;
70 d->document.swap(doc);
71 updatePosition(p, option);
72 if (!isVisible())
73 show();
74 else
75 update();
76 }
77
78 d->timer.start();
79}
80
81void KoItemToolTip::updatePosition(const QPoint &pos, const QStyleOptionViewItem &option)
82{
83 QWidget *widget = parentWidget();
85
86 const QPoint gpos = widget->mapToGlobal(pos);
87 const QSize size = sizeHint();
88
89 // resize **must** come before `setParentControlGeometry()`, otherwise
90 // compositor will place the window incorrectly!
91 resize(size);
92
93 // make sure that all the platform-specific structures for the window
94 // are created (i.e. QWaylandWindow) before trying to request them
95 // via `windowHandle()->handle()`
96 create();
97
98#ifdef HAVE_QT_PRIVATE_TOOLTIP_POSITION_API
99
100 if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow *>(windowHandle()->handle())) {
101
102 const QPoint parentPos = widget->window()->mapFromGlobal(gpos);
103 const QRect gravityRect(parentPos.x() - 20, parentPos.y() - 20, 40, 40);
104 waylandWindow->setParentControlGeometry(gravityRect);
105 waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ToolTip);
106 } else
107#endif /* HAVE_QT_PRIVATE_TOOLTIP_POSITION_API */
108
109 {
110 QScreen *screen = widget->screen();
111 const QRect availableRect = screen->availableGeometry();
112 const int width = size.width(), height = size.height();
113 const QRect itemRect(widget->mapToGlobal(option.rect.topLeft()), option.rect.size());
114
115 int y = gpos.y() + 20;
116 if (y + height > availableRect.bottom()) {
117 y = itemRect.bottom();
118
119 if (y + height > availableRect.bottom()) {
120 y = gpos.y() - 20 - height;
121
122 if (y < availableRect.top()) {
123 y = itemRect.top() - height;
124
125 if (y < availableRect.top()) {
126 y = availableRect.top();
127 }
128 }
129 }
130 }
131
132 int x = gpos.x() + 20;
133 if (x + width > availableRect.right()) {
134 x = itemRect.right();
135
136 if (x + width > availableRect.right()) {
137 x = gpos.x() - 20 - width;
138
139 if (x < availableRect.left()) {
140 x = itemRect.left() - width;
141
142 if (x < availableRect.left()) {
143 x = availableRect.left();
144 }
145 }
146 }
147 }
148
149 move(QPoint(x, y));
150 }
151}
152
154{
155 return d->document->size().toSize();
156}
157
159{
160 QPainter p(this);
161 d->document->drawContents(&p, rect());
162 p.drawRect(0, 0, width() - 1, height() - 1);
163}
164
165bool KoItemToolTip::eventFilter(QObject *object, QEvent *event)
166{
167 switch(event->type())
168 {
169 case QEvent::Leave:
170 hide();
171 default: break;
172 }
173
174 return QFrame::eventFilter(object, event);
175}
const Params2D p
void updatePosition(const QPoint &pos, const QStyleOptionViewItem &option)
std::unique_ptr< QTextDocument > document
QSize sizeHint() const override
bool eventFilter(QObject *object, QEvent *event) override
KoItemToolTip(QWidget *parent)
void showTip(const QPoint &pos, const QStyleOptionViewItem &option, const QModelIndex &index)
std::unique_ptr< Private > const d
virtual QTextDocument * createDocument(const QModelIndex &index)=0
~KoItemToolTip() override
void paintEvent(QPaintEvent *e) override
QPersistentModelIndex index
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128